From 3f8ec0559229f9ebff1fb50cec797809f622886c Mon Sep 17 00:00:00 2001 From: Lachezar Lechev Date: Wed, 17 Mar 2021 17:14:39 +0200 Subject: [PATCH 1/8] primitives - UnifiedNum --- primitives/src/big_num.rs | 17 +-- primitives/src/lib.rs | 11 +- primitives/src/unified_num.rs | 218 ++++++++++++++++++++++++++++++++++ 3 files changed, 234 insertions(+), 12 deletions(-) create mode 100644 primitives/src/unified_num.rs diff --git a/primitives/src/big_num.rs b/primitives/src/big_num.rs index 38d87d613..c67dcdeff 100644 --- a/primitives/src/big_num.rs +++ b/primitives/src/big_num.rs @@ -1,11 +1,12 @@ -use std::convert::TryFrom; -use std::fmt; -use std::iter::Sum; -use std::ops::{Add, AddAssign, Div, Mul, Sub}; -use std::str::FromStr; - -use num::rational::Ratio; -use num::{BigUint, CheckedSub, Integer}; +use std::{ + convert::TryFrom, + fmt, + iter::Sum, + ops::{Add, AddAssign, Div, Mul, Sub}, + str::FromStr, +}; + +use num::{rational::Ratio, BigUint, CheckedSub, Integer}; use num_derive::{Num, NumOps, One, Zero}; use serde::{Deserialize, Deserializer, Serialize, Serializer}; diff --git a/primitives/src/lib.rs b/primitives/src/lib.rs index 4e202f2ca..66b9c9641 100644 --- a/primitives/src/lib.rs +++ b/primitives/src/lib.rs @@ -1,5 +1,7 @@ #![deny(rust_2018_idioms)] #![deny(clippy::all)] +use std::{error, fmt}; + pub use self::{ ad_slot::AdSlot, ad_unit::AdUnit, @@ -10,14 +12,15 @@ pub use self::{ config::Config, event_submission::EventSubmission, ipfs::IPFS, + unified_num::UnifiedNum, validator::{ValidatorDesc, ValidatorId}, }; -use std::{error, fmt}; mod ad_slot; mod ad_unit; pub mod adapter; pub mod address; +pub mod analytics; pub mod balances_map; pub mod big_num; pub mod campaign; @@ -25,6 +28,7 @@ pub mod channel; pub mod channel_v5; pub mod channel_validator; pub mod config; +mod eth_checksum; pub mod event_submission; pub mod ipfs; pub mod market; @@ -32,6 +36,8 @@ pub mod merkle_tree; pub mod sentry; pub mod supermarket; pub mod targeting; +mod unified_num; +pub mod validator; pub mod util { pub use api::ApiUrl; @@ -52,9 +58,6 @@ pub mod util { pub mod logging; } -pub mod analytics; -mod eth_checksum; -pub mod validator; #[derive(Debug, PartialEq, Eq)] pub enum DomainError { diff --git a/primitives/src/unified_num.rs b/primitives/src/unified_num.rs new file mode 100644 index 000000000..56a404f80 --- /dev/null +++ b/primitives/src/unified_num.rs @@ -0,0 +1,218 @@ +use num::{CheckedSub, Integer, One}; +use num_derive::{Num, NumOps, Zero}; +use std::{ + fmt, + iter::Sum, + ops::{Add, AddAssign, Div, Mul, Sub}, +}; + +use crate::BigNum; + +/// Unified precision Number with precision 8 +#[derive(Num, NumOps, Zero, Default, PartialEq, Eq, PartialOrd, Ord)] +pub struct UnifiedNum(BigNum); + +impl UnifiedNum { + pub const PRECISION: usize = 8; + + pub fn div_floor(&self, other: &Self) -> Self { + Self(self.0.div_floor(&other.0)) + } + + pub fn to_f64(&self) -> Option { + self.0.to_f64() + } + + pub fn to_u64(&self) -> Option { + self.0.to_u64() + } +} + +impl From for UnifiedNum { + fn from(number: u64) -> Self { + Self(BigNum::from(number)) + } +} + +impl From for UnifiedNum { + fn from(number: BigNum) -> Self { + Self(number) + } +} + +impl fmt::Display for UnifiedNum { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let mut string_value = self.0.to_str_radix(10); + let value_length = string_value.len(); + + if value_length > Self::PRECISION { + string_value.insert_str(value_length - Self::PRECISION, "."); + + f.write_str(&string_value) + } else { + write!(f, "0.{:0>8}", string_value) + } + } +} + +impl fmt::Debug for UnifiedNum { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "UnifiedNum({})", self.to_string()) + } +} + +impl One for UnifiedNum { + fn one() -> Self { + Self(BigNum::from(10_000_000)) + } +} + +impl Integer for UnifiedNum { + fn div_floor(&self, other: &Self) -> Self { + self.0.div_floor(&other.0).into() + } + + fn mod_floor(&self, other: &Self) -> Self { + self.0.mod_floor(&other.0).into() + } + + fn gcd(&self, other: &Self) -> Self { + self.0.gcd(&other.0).into() + } + + fn lcm(&self, other: &Self) -> Self { + self.0.lcm(&other.0).into() + } + + fn divides(&self, other: &Self) -> bool { + self.0.divides(&other.0) + } + + fn is_multiple_of(&self, other: &Self) -> bool { + self.0.is_multiple_of(&other.0) + } + + fn is_even(&self) -> bool { + self.0.is_even() + } + + fn is_odd(&self) -> bool { + !self.is_even() + } + + fn div_rem(&self, other: &Self) -> (Self, Self) { + let (quotient, remainder) = self.0.div_rem(&other.0); + + (quotient.into(), remainder.into()) + } +} + +impl Add<&UnifiedNum> for &UnifiedNum { + type Output = UnifiedNum; + + fn add(self, rhs: &UnifiedNum) -> Self::Output { + let bignum = &self.0 + &rhs.0; + UnifiedNum(bignum) + } +} + +impl AddAssign<&UnifiedNum> for UnifiedNum { + fn add_assign(&mut self, rhs: &UnifiedNum) { + self.0 += &rhs.0 + } +} + +impl Sub<&UnifiedNum> for &UnifiedNum { + type Output = UnifiedNum; + + fn sub(self, rhs: &UnifiedNum) -> Self::Output { + let bignum = &self.0 - &rhs.0; + UnifiedNum(bignum) + } +} + +impl Sub<&UnifiedNum> for UnifiedNum { + type Output = UnifiedNum; + + fn sub(self, rhs: &UnifiedNum) -> Self::Output { + let bignum = &self.0 - &rhs.0; + UnifiedNum(bignum) + } +} + +impl Sub for &UnifiedNum { + type Output = UnifiedNum; + + fn sub(self, rhs: UnifiedNum) -> Self::Output { + let bignum = &self.0 - &rhs.0; + UnifiedNum(bignum) + } +} + +impl Div<&UnifiedNum> for &UnifiedNum { + type Output = UnifiedNum; + + fn div(self, rhs: &UnifiedNum) -> Self::Output { + let bignum = &self.0 / &rhs.0; + UnifiedNum(bignum) + } +} + +impl Div<&UnifiedNum> for UnifiedNum { + type Output = UnifiedNum; + + fn div(self, rhs: &UnifiedNum) -> Self::Output { + let bignum = &self.0 / &rhs.0; + UnifiedNum(bignum) + } +} + +impl Mul<&UnifiedNum> for &UnifiedNum { + type Output = UnifiedNum; + + fn mul(self, rhs: &UnifiedNum) -> Self::Output { + let bignum = &self.0 * &rhs.0; + UnifiedNum(bignum) + } +} + +impl Mul<&UnifiedNum> for UnifiedNum { + type Output = UnifiedNum; + + fn mul(self, rhs: &UnifiedNum) -> Self::Output { + let bignum = &self.0 * &rhs.0; + UnifiedNum(bignum) + } +} + +impl<'a> Sum<&'a UnifiedNum> for UnifiedNum { + fn sum>(iter: I) -> Self { + let sum_uint = iter.map(|big_num| &big_num.0).sum(); + + Self(sum_uint) + } +} + +impl CheckedSub for UnifiedNum { + fn checked_sub(&self, v: &Self) -> Option { + self.0.checked_sub(&v.0).map(Self) + } +} + +#[cfg(test)] +mod test { + use crate::UnifiedNum; + + #[test] + fn unified_num_displays_correctly() { + let one = UnifiedNum::from(100_000_000); + let zero_point_one = UnifiedNum::from(10_000_000); + let smallest_value = UnifiedNum::from(1); + let random_value = UnifiedNum::from(144_903_000_567_000); + + assert_eq!("1.00000000", &one.to_string()); + assert_eq!("0.10000000", &zero_point_one.to_string()); + assert_eq!("0.00000001", &smallest_value.to_string()); + assert_eq!("1449030.00567000", &random_value.to_string()); + } +} From be4734241bf8ceca3966302889aca5673542856a Mon Sep 17 00:00:00 2001 From: Lachezar Lechev Date: Thu, 18 Mar 2021 13:20:30 +0200 Subject: [PATCH 2/8] pirmitives - BigNum - impl num::pow::Pow --- primitives/src/big_num.rs | 42 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/primitives/src/big_num.rs b/primitives/src/big_num.rs index c67dcdeff..e73c3b1f3 100644 --- a/primitives/src/big_num.rs +++ b/primitives/src/big_num.rs @@ -6,7 +6,7 @@ use std::{ str::FromStr, }; -use num::{rational::Ratio, BigUint, CheckedSub, Integer}; +use num::{pow::Pow, rational::Ratio, BigUint, CheckedSub, Integer}; use num_derive::{Num, NumOps, One, Zero}; use serde::{Deserialize, Deserializer, Serialize, Serializer}; @@ -99,6 +99,46 @@ impl Integer for BigNum { } } +impl Pow for BigNum { + type Output = BigNum; + + fn pow(self, rhs: BigNum) -> Self::Output { + Self(self.0.pow(rhs.0)) + } +} + +impl Pow<&BigNum> for BigNum { + type Output = BigNum; + + fn pow(self, rhs: &BigNum) -> Self::Output { + BigNum(self.0.pow(&rhs.0)) + } +} + +impl Pow for &BigNum { + type Output = BigNum; + + fn pow(self, rhs: BigNum) -> Self::Output { + BigNum(Pow::pow(&self.0, rhs.0)) + } +} + +impl Pow<&BigNum> for &BigNum { + type Output = BigNum; + + fn pow(self, rhs: &BigNum) -> Self::Output { + BigNum(Pow::pow(&self.0, &rhs.0)) + } +} + +impl Pow for BigNum { + type Output = BigNum; + + fn pow(self, rhs: u8) -> Self::Output { + BigNum(self.0.pow(rhs)) + } +} + impl Add<&BigNum> for &BigNum { type Output = BigNum; From 080b5177680a6e9f1c11d3d3130f63cac8b12300 Mon Sep 17 00:00:00 2001 From: Lachezar Lechev Date: Thu, 18 Mar 2021 13:21:30 +0200 Subject: [PATCH 3/8] primitives - UnifiedNum - impl num::pow::Pow & to_preicison() --- primitives/src/unified_num.rs | 86 +++++++++++++++++++++++++++++++++-- 1 file changed, 81 insertions(+), 5 deletions(-) diff --git a/primitives/src/unified_num.rs b/primitives/src/unified_num.rs index 56a404f80..433f12571 100644 --- a/primitives/src/unified_num.rs +++ b/primitives/src/unified_num.rs @@ -1,6 +1,7 @@ -use num::{CheckedSub, Integer, One}; +use num::{pow::Pow, CheckedSub, Integer, One}; use num_derive::{Num, NumOps, Zero}; use std::{ + cmp::Ordering, fmt, iter::Sum, ops::{Add, AddAssign, Div, Mul, Sub}, @@ -13,7 +14,7 @@ use crate::BigNum; pub struct UnifiedNum(BigNum); impl UnifiedNum { - pub const PRECISION: usize = 8; + pub const PRECISION: u8 = 8; pub fn div_floor(&self, other: &Self) -> Self { Self(self.0.div_floor(&other.0)) @@ -26,6 +27,17 @@ impl UnifiedNum { pub fn to_u64(&self) -> Option { self.0.to_u64() } + + /// Transform the UnifiedNum precision 8 to a new precision + pub fn to_precision(&self, precision: u8) -> BigNum { + match precision.cmp(&Self::PRECISION) { + Ordering::Equal => self.0.clone(), + Ordering::Less => self + .0 + .div_floor(&BigNum::from(10).pow(Self::PRECISION - precision)), + Ordering::Greater => (&self.0).mul(&BigNum::from(10).pow(precision - Self::PRECISION)), + } + } } impl From for UnifiedNum { @@ -44,9 +56,10 @@ impl fmt::Display for UnifiedNum { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let mut string_value = self.0.to_str_radix(10); let value_length = string_value.len(); + let precision: usize = Self::PRECISION.into(); - if value_length > Self::PRECISION { - string_value.insert_str(value_length - Self::PRECISION, "."); + if value_length > precision { + string_value.insert_str(value_length - precision, "."); f.write_str(&string_value) } else { @@ -107,6 +120,38 @@ impl Integer for UnifiedNum { } } +impl Pow for UnifiedNum { + type Output = UnifiedNum; + + fn pow(self, rhs: UnifiedNum) -> Self::Output { + Self(self.0.pow(rhs.0)) + } +} + +impl Pow<&UnifiedNum> for UnifiedNum { + type Output = UnifiedNum; + + fn pow(self, rhs: &UnifiedNum) -> Self::Output { + UnifiedNum(self.0.pow(&rhs.0)) + } +} + +impl Pow for &UnifiedNum { + type Output = UnifiedNum; + + fn pow(self, rhs: UnifiedNum) -> Self::Output { + UnifiedNum((&self.0).pow(rhs.0)) + } +} + +impl Pow<&UnifiedNum> for &UnifiedNum { + type Output = UnifiedNum; + + fn pow(self, rhs: &UnifiedNum) -> Self::Output { + UnifiedNum((&self.0).pow(&rhs.0)) + } +} + impl Add<&UnifiedNum> for &UnifiedNum { type Output = UnifiedNum; @@ -201,7 +246,7 @@ impl CheckedSub for UnifiedNum { #[cfg(test)] mod test { - use crate::UnifiedNum; + use super::*; #[test] fn unified_num_displays_correctly() { @@ -215,4 +260,35 @@ mod test { assert_eq!("0.00000001", &smallest_value.to_string()); assert_eq!("1449030.00567000", &random_value.to_string()); } + + #[test] + fn test_convert_unified_num_to_new_precision() { + let dai_precision: u8 = 18; + let usdt_precision: u8 = 6; + let same_precision = UnifiedNum::PRECISION; + + let dai_power = BigNum::from(10).pow(BigNum::from(dai_precision as u64)); + + // 321.00000000 + let dai_unified = UnifiedNum::from(32_100_000_000_u64); + let dai_expected = BigNum::from(321_u64) * dai_power; + assert_eq!(dai_expected, dai_unified.to_precision(dai_precision)); + + // 321.00000777 - should floor to 321.000007 (precision 6) + let usdt_unified = UnifiedNum::from(32_100_000_777_u64); + let usdt_expected = BigNum::from(321_000_007_u64); + assert_eq!( + usdt_expected, + usdt_unified.to_precision(usdt_precision), + "It should floor the result of USDT" + ); + + // 321.00000999 + let same_unified = UnifiedNum::from(32_100_000_777_u64); + assert_eq!( + same_unified.0, + same_unified.to_precision(same_precision), + "It should not make any adjustments to the precision" + ); + } } From 9815a2417010d38213032ebdae0dc304c8891c5e Mon Sep 17 00:00:00 2001 From: Lachezar Lechev Date: Thu, 18 Mar 2021 13:30:37 +0200 Subject: [PATCH 4/8] primitives - UnifiedNum - test for Zero & One --- primitives/src/unified_num.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/primitives/src/unified_num.rs b/primitives/src/unified_num.rs index 433f12571..ef2797c0b 100644 --- a/primitives/src/unified_num.rs +++ b/primitives/src/unified_num.rs @@ -76,7 +76,7 @@ impl fmt::Debug for UnifiedNum { impl One for UnifiedNum { fn one() -> Self { - Self(BigNum::from(10_000_000)) + Self(BigNum::from(100_000_000)) } } @@ -247,6 +247,7 @@ impl CheckedSub for UnifiedNum { #[cfg(test)] mod test { use super::*; + use num::Zero; #[test] fn unified_num_displays_correctly() { @@ -256,6 +257,8 @@ mod test { let random_value = UnifiedNum::from(144_903_000_567_000); assert_eq!("1.00000000", &one.to_string()); + assert_eq!("1.00000000", &UnifiedNum::one().to_string()); + assert_eq!("0.00000000", &UnifiedNum::zero().to_string()); assert_eq!("0.10000000", &zero_point_one.to_string()); assert_eq!("0.00000001", &smallest_value.to_string()); assert_eq!("1449030.00567000", &random_value.to_string()); From 055307ca32e7de1a6cb79d09c560f4291de4cbbe Mon Sep 17 00:00:00 2001 From: Lachezar Lechev Date: Thu, 18 Mar 2021 15:08:54 +0200 Subject: [PATCH 5/8] primitives - BigNum - impl Display instead of ToString --- primitives/src/big_num.rs | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/primitives/src/big_num.rs b/primitives/src/big_num.rs index e73c3b1f3..c9e28bea5 100644 --- a/primitives/src/big_num.rs +++ b/primitives/src/big_num.rs @@ -59,6 +59,12 @@ impl fmt::Debug for BigNum { } } +impl fmt::Display for BigNum { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.0.fmt(f) + } +} + impl Integer for BigNum { fn div_floor(&self, other: &Self) -> Self { self.0.div_floor(&other.0).into() @@ -250,12 +256,6 @@ impl FromStr for BigNum { } } -impl ToString for BigNum { - fn to_string(&self) -> String { - self.0.to_str_radix(10) - } -} - impl From for BigNum { fn from(value: u64) -> Self { Self(BigUint::from(value)) @@ -338,4 +338,11 @@ mod test { let expected: BigNum = 11.into(); assert_eq!(expected, &big_num * &ratio); } + #[test] + fn bignum_formatting() { + let bignum: BigNum = 5000.into(); + + assert_eq!("5000", &bignum.to_string()); + assert_eq!("BigNum(radix: 10; 5000)", &format!("{:?}", &bignum)); + } } From 310ea23a99d1ed289ecd8720ed1668e98c060cff Mon Sep 17 00:00:00 2001 From: Lachezar Lechev Date: Mon, 22 Mar 2021 13:53:37 +0200 Subject: [PATCH 6/8] primitives - UnifiedNum - use u64 as internal value --- primitives/src/big_num.rs | 8 ++ primitives/src/unified_num.rs | 170 +++++++++++++++++++--------------- sentry/src/middleware/auth.rs | 2 +- 3 files changed, 104 insertions(+), 76 deletions(-) diff --git a/primitives/src/big_num.rs b/primitives/src/big_num.rs index c9e28bea5..82cdb8d78 100644 --- a/primitives/src/big_num.rs +++ b/primitives/src/big_num.rs @@ -10,6 +10,8 @@ use num::{pow::Pow, rational::Ratio, BigUint, CheckedSub, Integer}; use num_derive::{Num, NumOps, One, Zero}; use serde::{Deserialize, Deserializer, Serialize, Serializer}; +use crate::UnifiedNum; + #[derive( Serialize, Deserialize, Clone, PartialEq, Eq, PartialOrd, Ord, NumOps, One, Zero, Num, Default, )] @@ -268,6 +270,12 @@ impl From for BigNum { } } +impl<'a> Sum<&'a UnifiedNum> for BigNum { + fn sum>(iter: I) -> BigNum { + BigNum(iter.map(|unified| BigUint::from(unified.to_u64())).sum()) + } +} + fn biguint_from_str<'de, D>(deserializer: D) -> Result where D: Deserializer<'de>, diff --git a/primitives/src/unified_num.rs b/primitives/src/unified_num.rs index ef2797c0b..cc1a532cb 100644 --- a/primitives/src/unified_num.rs +++ b/primitives/src/unified_num.rs @@ -1,5 +1,6 @@ -use num::{pow::Pow, CheckedSub, Integer, One}; -use num_derive::{Num, NumOps, Zero}; +use num::{pow::Pow, CheckedAdd, CheckedDiv, CheckedMul, CheckedSub, Integer, One}; +use num_derive::{FromPrimitive, Num, NumCast, NumOps, ToPrimitive, Zero}; +use num_traits::CheckedRem; use std::{ cmp::Ordering, fmt, @@ -10,8 +11,22 @@ use std::{ use crate::BigNum; /// Unified precision Number with precision 8 -#[derive(Num, NumOps, Zero, Default, PartialEq, Eq, PartialOrd, Ord)] -pub struct UnifiedNum(BigNum); +#[derive( + Clone, + Copy, + Num, + NumOps, + NumCast, + ToPrimitive, + FromPrimitive, + Zero, + Default, + PartialEq, + Eq, + PartialOrd, + Ord, +)] +pub struct UnifiedNum(u64); impl UnifiedNum { pub const PRECISION: u8 = 8; @@ -20,41 +35,50 @@ impl UnifiedNum { Self(self.0.div_floor(&other.0)) } - pub fn to_f64(&self) -> Option { - self.0.to_f64() + pub fn to_u64(&self) -> u64 { + self.0 } - pub fn to_u64(&self) -> Option { - self.0.to_u64() + pub fn checked_add(&self, rhs: &UnifiedNum) -> Option { + CheckedAdd::checked_add(self, rhs) + } + + pub fn checked_sub(&self, rhs: &UnifiedNum) -> Option { + CheckedSub::checked_sub(self, rhs) + } + + pub fn checked_mul(&self, rhs: &UnifiedNum) -> Option { + CheckedMul::checked_mul(self, rhs) + } + + pub fn checked_div(&self, rhs: &UnifiedNum) -> Option { + CheckedDiv::checked_div(self, rhs) + } + + pub fn checked_rem(&self, rhs: &UnifiedNum) -> Option { + CheckedRem::checked_rem(self, rhs) } /// Transform the UnifiedNum precision 8 to a new precision pub fn to_precision(&self, precision: u8) -> BigNum { + let inner = BigNum::from(self.0); match precision.cmp(&Self::PRECISION) { - Ordering::Equal => self.0.clone(), - Ordering::Less => self - .0 - .div_floor(&BigNum::from(10).pow(Self::PRECISION - precision)), - Ordering::Greater => (&self.0).mul(&BigNum::from(10).pow(precision - Self::PRECISION)), + Ordering::Equal => inner, + Ordering::Less => inner.div_floor(&BigNum::from(10).pow(Self::PRECISION - precision)), + Ordering::Greater => inner.mul(&BigNum::from(10).pow(precision - Self::PRECISION)), } } } impl From for UnifiedNum { fn from(number: u64) -> Self { - Self(BigNum::from(number)) - } -} - -impl From for UnifiedNum { - fn from(number: BigNum) -> Self { Self(number) } } impl fmt::Display for UnifiedNum { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let mut string_value = self.0.to_str_radix(10); + let mut string_value = self.0.to_string(); let value_length = string_value.len(); let precision: usize = Self::PRECISION.into(); @@ -76,7 +100,7 @@ impl fmt::Debug for UnifiedNum { impl One for UnifiedNum { fn one() -> Self { - Self(BigNum::from(100_000_000)) + Self(100_000_000) } } @@ -120,44 +144,11 @@ impl Integer for UnifiedNum { } } -impl Pow for UnifiedNum { - type Output = UnifiedNum; - - fn pow(self, rhs: UnifiedNum) -> Self::Output { - Self(self.0.pow(rhs.0)) - } -} - -impl Pow<&UnifiedNum> for UnifiedNum { - type Output = UnifiedNum; - - fn pow(self, rhs: &UnifiedNum) -> Self::Output { - UnifiedNum(self.0.pow(&rhs.0)) - } -} - -impl Pow for &UnifiedNum { - type Output = UnifiedNum; - - fn pow(self, rhs: UnifiedNum) -> Self::Output { - UnifiedNum((&self.0).pow(rhs.0)) - } -} - -impl Pow<&UnifiedNum> for &UnifiedNum { - type Output = UnifiedNum; - - fn pow(self, rhs: &UnifiedNum) -> Self::Output { - UnifiedNum((&self.0).pow(&rhs.0)) - } -} - impl Add<&UnifiedNum> for &UnifiedNum { type Output = UnifiedNum; fn add(self, rhs: &UnifiedNum) -> Self::Output { - let bignum = &self.0 + &rhs.0; - UnifiedNum(bignum) + UnifiedNum(self.0 + rhs.0) } } @@ -171,8 +162,7 @@ impl Sub<&UnifiedNum> for &UnifiedNum { type Output = UnifiedNum; fn sub(self, rhs: &UnifiedNum) -> Self::Output { - let bignum = &self.0 - &rhs.0; - UnifiedNum(bignum) + UnifiedNum(self.0 - rhs.0) } } @@ -180,8 +170,7 @@ impl Sub<&UnifiedNum> for UnifiedNum { type Output = UnifiedNum; fn sub(self, rhs: &UnifiedNum) -> Self::Output { - let bignum = &self.0 - &rhs.0; - UnifiedNum(bignum) + UnifiedNum(self.0 - rhs.0) } } @@ -189,8 +178,7 @@ impl Sub for &UnifiedNum { type Output = UnifiedNum; fn sub(self, rhs: UnifiedNum) -> Self::Output { - let bignum = &self.0 - &rhs.0; - UnifiedNum(bignum) + UnifiedNum(self.0 - rhs.0) } } @@ -198,8 +186,7 @@ impl Div<&UnifiedNum> for &UnifiedNum { type Output = UnifiedNum; fn div(self, rhs: &UnifiedNum) -> Self::Output { - let bignum = &self.0 / &rhs.0; - UnifiedNum(bignum) + UnifiedNum(self.0 / rhs.0) } } @@ -207,8 +194,7 @@ impl Div<&UnifiedNum> for UnifiedNum { type Output = UnifiedNum; fn div(self, rhs: &UnifiedNum) -> Self::Output { - let bignum = &self.0 / &rhs.0; - UnifiedNum(bignum) + UnifiedNum(self.0 / rhs.0) } } @@ -216,8 +202,7 @@ impl Mul<&UnifiedNum> for &UnifiedNum { type Output = UnifiedNum; fn mul(self, rhs: &UnifiedNum) -> Self::Output { - let bignum = &self.0 * &rhs.0; - UnifiedNum(bignum) + UnifiedNum(self.0 * rhs.0) } } @@ -225,22 +210,44 @@ impl Mul<&UnifiedNum> for UnifiedNum { type Output = UnifiedNum; fn mul(self, rhs: &UnifiedNum) -> Self::Output { - let bignum = &self.0 * &rhs.0; - UnifiedNum(bignum) + UnifiedNum(self.0 * rhs.0) } } -impl<'a> Sum<&'a UnifiedNum> for UnifiedNum { - fn sum>(iter: I) -> Self { - let sum_uint = iter.map(|big_num| &big_num.0).sum(); +impl<'a> Sum<&'a UnifiedNum> for Option { + fn sum>(mut iter: I) -> Self { + iter.try_fold(0_u64, |acc, unified| acc.checked_add(unified.0)) + .map(UnifiedNum) + } +} - Self(sum_uint) +impl CheckedAdd for UnifiedNum { + fn checked_add(&self, v: &Self) -> Option { + self.0.checked_add(v.0).map(Self) } } impl CheckedSub for UnifiedNum { fn checked_sub(&self, v: &Self) -> Option { - self.0.checked_sub(&v.0).map(Self) + self.0.checked_sub(v.0).map(Self) + } +} + +impl CheckedMul for UnifiedNum { + fn checked_mul(&self, v: &Self) -> Option { + self.0.checked_mul(v.0).map(Self) + } +} + +impl CheckedDiv for UnifiedNum { + fn checked_div(&self, v: &Self) -> Option { + self.0.checked_div(v.0).map(Self) + } +} + +impl CheckedRem for UnifiedNum { + fn checked_rem(&self, v: &Self) -> Option { + self.0.checked_rem(v.0).map(Self) } } @@ -249,6 +256,19 @@ mod test { use super::*; use num::Zero; + #[test] + fn unified_num_sum() { + let num_max = UnifiedNum(u64::MAX); + let num_1 = UnifiedNum(1); + let num_5 = UnifiedNum(5); + + let succeeding_sum: Option = [num_1, num_5].iter().sum(); + let overflow_sum: Option = [num_1, num_max].iter().sum(); + + assert_eq!(Some(UnifiedNum(6)), succeeding_sum); + assert_eq!(None, overflow_sum); + } + #[test] fn unified_num_displays_correctly() { let one = UnifiedNum::from(100_000_000); @@ -289,7 +309,7 @@ mod test { // 321.00000999 let same_unified = UnifiedNum::from(32_100_000_777_u64); assert_eq!( - same_unified.0, + BigNum::from(same_unified.0), same_unified.to_precision(same_precision), "It should not make any adjustments to the precision" ); diff --git a/sentry/src/middleware/auth.rs b/sentry/src/middleware/auth.rs index 82c9b6548..ce404e98a 100644 --- a/sentry/src/middleware/auth.rs +++ b/sentry/src/middleware/auth.rs @@ -133,7 +133,7 @@ mod test { use primitives::util::tests::prep_db::{AUTH, IDS}; - use primitives::{config::configuration}; + use primitives::config::configuration; use deadpool::managed::Object; From a38e0f22503b5cab05c44dc42d7b71d8ef3a5ab1 Mon Sep 17 00:00:00 2001 From: Lachezar Lechev Date: Tue, 23 Mar 2021 13:17:57 +0200 Subject: [PATCH 7/8] primitives - UnifiedNum - Update doc --- primitives/src/unified_num.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/primitives/src/unified_num.rs b/primitives/src/unified_num.rs index cc1a532cb..4c0d22343 100644 --- a/primitives/src/unified_num.rs +++ b/primitives/src/unified_num.rs @@ -10,7 +10,10 @@ use std::{ use crate::BigNum; -/// Unified precision Number with precision 8 +/// Unified Number with a precision of 8 digits after the decimal point +/// The number can be a maximum of `u64::MAX` (the underlying type), +/// or in a `UnifiedNum` value `184_467_440_737.09551615` +/// The actual number is handled as a unsigned number and only the display shows the decimal point #[derive( Clone, Copy, From 590352789b3284ee029b86821df116fb8decd3ee Mon Sep 17 00:00:00 2001 From: Lachezar Lechev Date: Tue, 23 Mar 2021 13:44:55 +0200 Subject: [PATCH 8/8] primitives - UnifiedNum - fix test comment --- primitives/src/unified_num.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/primitives/src/unified_num.rs b/primitives/src/unified_num.rs index 4c0d22343..11c13dd70 100644 --- a/primitives/src/unified_num.rs +++ b/primitives/src/unified_num.rs @@ -309,7 +309,7 @@ mod test { "It should floor the result of USDT" ); - // 321.00000999 + // 321.00000777 let same_unified = UnifiedNum::from(32_100_000_777_u64); assert_eq!( BigNum::from(same_unified.0),