diff --git a/pallets/networks/Cargo.toml b/pallets/networks/Cargo.toml index ca9a189..525277d 100644 --- a/pallets/networks/Cargo.toml +++ b/pallets/networks/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ghost-networks" -version = "0.1.20" +version = "0.1.21" license.workspace = true authors.workspace = true edition.workspace = true diff --git a/pallets/networks/src/lib.rs b/pallets/networks/src/lib.rs index 5cf532b..995e863 100644 --- a/pallets/networks/src/lib.rs +++ b/pallets/networks/src/lib.rs @@ -12,7 +12,7 @@ use scale_info::TypeInfo; use sp_runtime::{ curve::PiecewiseLinear, - traits::{AtLeast32BitUnsigned, CheckedAdd, CheckedSub, Member}, + traits::{AtLeast32BitUnsigned, CheckedAdd, CheckedSub, Member, UniqueSaturatedInto}, DispatchResult, }; use sp_std::{convert::TryInto, prelude::*}; @@ -21,12 +21,10 @@ pub use ghost_traits::networks::{ NetworkDataBasicHandler, NetworkDataInspectHandler, NetworkDataMutateHandler, }; -mod math; pub mod migrations; mod weights; pub use crate::weights::WeightInfo; -use math::MulDiv; pub use module::*; #[cfg(any(feature = "runtime-benchmarks", test))] @@ -111,11 +109,16 @@ where let estimated_reward = reward_curve.calculate_for_fraction_times_denominator(total_staked, adjusted_issuance); - let payout = MulDiv::::calculate( - estimated_reward, - accumulated_commission, - adjusted_issuance, - ); + + let payout: Balance = sp_runtime::helpers_128bit::multiply_by_rational_with_rounding( + estimated_reward.unique_saturated_into(), + accumulated_commission.unique_saturated_into(), + adjusted_issuance.unique_saturated_into(), + sp_runtime::Rounding::NearestPrefUp, + ) + .map(|result| result.unique_saturated_into()) + .unwrap_or_default(); + let rest_payout = accumulated_commission.saturating_sub(payout); (payout, rest_payout) diff --git a/pallets/networks/src/math.rs b/pallets/networks/src/math.rs deleted file mode 100644 index 794351e..0000000 --- a/pallets/networks/src/math.rs +++ /dev/null @@ -1,134 +0,0 @@ -use crate::AtLeast32BitUnsigned; - -pub struct MulDiv(core::marker::PhantomData); -impl MulDiv -where - Balance: Copy - + AtLeast32BitUnsigned - + num_traits::ops::wrapping::WrappingAdd - + num_traits::ops::overflowing::OverflowingAdd - + sp_std::ops::AddAssign - + sp_std::ops::Not - + sp_std::ops::Shl - + sp_std::ops::Shr - + sp_std::ops::BitAnd, -{ - fn zero(&self) -> Balance { - 0u32.into() - } - - fn one(&self) -> Balance { - 1u32.into() - } - - fn bit_shift(&self) -> Balance { - let u32_shift: u32 = core::mem::size_of::() - .saturating_mul(4) - .try_into() - .unwrap_or_default(); - u32_shift.into() - } - - fn least_significant_bits(&self, a: Balance) -> Balance { - a & ((self.one() << self.bit_shift()) - self.one()) - } - - fn most_significant_bits(&self, a: Balance) -> Balance { - a >> self.bit_shift() - } - - fn two_complement(&self, a: Balance) -> Balance { - (!a).wrapping_add(&self.one()) - } - - fn adjusted_ratio(&self, a: Balance) -> Balance { - (self.two_complement(a) / a).wrapping_add(&self.one()) - } - - fn modulo(&self, a: Balance) -> Balance { - self.two_complement(a) % a - } - - fn overflow_resistant_addition( - &self, - a0: Balance, - a1: Balance, - b0: Balance, - b1: Balance, - ) -> (Balance, Balance) { - let (r0, overflow) = a0.overflowing_add(&b0); - let overflow: Balance = overflow.then(|| 1u32).unwrap_or_default().into(); - let r1 = a1.wrapping_add(&b1).wrapping_add(&overflow); - (r0, r1) - } - - fn overflow_resistant_multiplication(&self, a: Balance, b: Balance) -> (Balance, Balance) { - let (a0, a1) = ( - self.least_significant_bits(a), - self.most_significant_bits(a), - ); - let (b0, b1) = ( - self.least_significant_bits(b), - self.most_significant_bits(b), - ); - let (x, y) = (a1 * b0, b1 * a0); - - let (r0, r1) = (a0 * b0, a1 * b1); - let (r0, r1) = self.overflow_resistant_addition( - r0, - r1, - self.least_significant_bits(x) << self.bit_shift(), - self.most_significant_bits(x), - ); - let (r0, r1) = self.overflow_resistant_addition( - r0, - r1, - self.least_significant_bits(y) << self.bit_shift(), - self.most_significant_bits(y), - ); - - (r0, r1) - } - - fn overflow_resistant_division( - &self, - mut a0: Balance, - mut a1: Balance, - b: Balance, - ) -> (Balance, Balance) { - if b == self.one() { - return (a0, a1); - } - - let zero: Balance = 0u32.into(); - let (q, r) = (self.adjusted_ratio(b), self.modulo(b)); - let (mut x0, mut x1) = (zero, zero); - - while a1 != zero { - let (t0, t1) = self.overflow_resistant_multiplication(a1, q); - let (new_x0, new_x1) = self.overflow_resistant_addition(x0, x1, t0, t1); - x0 = new_x0; - x1 = new_x1; - - let (t0, t1) = self.overflow_resistant_multiplication(a1, r); - let (new_a0, new_a1) = self.overflow_resistant_addition(t0, t1, a0, zero); - a0 = new_a0; - a1 = new_a1; - } - - self.overflow_resistant_addition(x0, x1, a0 / b, zero) - } - - fn mul_div(&self, a: Balance, b: Balance, c: Balance) -> Balance { - let (t0, t1) = self.overflow_resistant_multiplication(a, b); - self.overflow_resistant_division(t0, t1, c).0 - } - - pub fn calculate(a: Balance, b: Balance, c: Balance) -> Balance { - let inner = MulDiv(core::marker::PhantomData); - if c == inner.zero() { - return c; - } - inner.mul_div(a, b, c) - } -} diff --git a/pallets/networks/src/tests.rs b/pallets/networks/src/tests.rs index c4c86ab..94b06a5 100644 --- a/pallets/networks/src/tests.rs +++ b/pallets/networks/src/tests.rs @@ -1673,123 +1673,6 @@ fn check_substrate_guarantees_not_to_overflow_u32() { }); } -#[test] -fn check_muldiv_guarantees_not_to_overflow_for_u128() { - ExtBuilder::build().execute_with(|| { - let mut a: u128 = 2; - let mut b: u128 = 3; - let mut c: u128 = 6; - let mut result: u128 = 1; - - loop { - a = match a.checked_mul(1_000) { - Some(value) => value, - None => break, - }; - b = match b.checked_mul(1_000) { - Some(value) => value, - None => break, - }; - c = match c.checked_mul(1_000) { - Some(value) => value, - None => break, - }; - result = match result.checked_mul(1_000) { - Some(value) => value, - None => break, - }; - - assert_eq!(MulDiv::::calculate(a, b, c), result); - } - - assert_eq!( - MulDiv::::calculate(u128::MAX, u128::MAX, u128::MAX), - u128::MAX - ); - assert_eq!(MulDiv::::calculate(u128::MAX, 0, 0), 0); - assert_eq!(MulDiv::::calculate(0, u128::MAX, 0), 0); - assert_eq!(MulDiv::::calculate(0, 0, u128::MAX), 0); - }); -} - -#[test] -fn check_muldiv_guarantees_not_to_overflow_for_u64() { - ExtBuilder::build().execute_with(|| { - let mut a: u64 = 2; - let mut b: u64 = 3; - let mut c: u64 = 6; - let mut result: u64 = 1; - - loop { - a = match a.checked_mul(1_000) { - Some(value) => value, - None => break, - }; - b = match b.checked_mul(1_000) { - Some(value) => value, - None => break, - }; - c = match c.checked_mul(1_000) { - Some(value) => value, - None => break, - }; - result = match result.checked_mul(1_000) { - Some(value) => value, - None => break, - }; - - assert_eq!(MulDiv::::calculate(a, b, c), result); - } - - assert_eq!( - MulDiv::::calculate(u64::MAX, u64::MAX, u64::MAX), - u64::MAX - ); - assert_eq!(MulDiv::::calculate(u64::MAX, 0, 0), 0); - assert_eq!(MulDiv::::calculate(0, u64::MAX, 0), 0); - assert_eq!(MulDiv::::calculate(0, 0, u64::MAX), 0); - }); -} - -#[test] -fn check_muldiv_guarantees_not_to_overflow_for_u32() { - ExtBuilder::build().execute_with(|| { - let mut a: u32 = 2; - let mut b: u32 = 3; - let mut c: u32 = 6; - let mut result: u32 = 1; - - loop { - a = match a.checked_mul(1_000) { - Some(value) => value, - None => break, - }; - b = match b.checked_mul(1_000) { - Some(value) => value, - None => break, - }; - c = match c.checked_mul(1_000) { - Some(value) => value, - None => break, - }; - result = match result.checked_mul(1_000) { - Some(value) => value, - None => break, - }; - - assert_eq!(MulDiv::::calculate(a, b, c), result); - } - - assert_eq!( - MulDiv::::calculate(u32::MAX, u32::MAX, u32::MAX), - u32::MAX - ); - assert_eq!(MulDiv::::calculate(u32::MAX, 0, 0), 0); - assert_eq!(MulDiv::::calculate(0, u32::MAX, 0), 0); - assert_eq!(MulDiv::::calculate(0, 0, u32::MAX), 0); - }); -} - #[test] fn check_bridged_inflation_curve_for_overflow() { ExtBuilder::build().execute_with(|| {