From f55ad87273703d02b856b910e5037efe7d77f24c Mon Sep 17 00:00:00 2001 From: Gavin Wood Date: Tue, 16 Mar 2021 13:03:58 +0100 Subject: [PATCH] staking: Flexible generation of reward curve and associated tweaks (#8327) * Initial abstraction * Alter rest of APIs * Fixes * Some extra getters in Gilt pallet. * Refactor Gilt to avoid u128 conversions * Simplify and improve pow in per_things * Add scalar division to per_things * Renaming from_fraction -> from_float, drop _approximation * Fixes * Fixes * Fixes * Fixes * Make stuff build * Fixes * Fixes * Fixes * Fixes * Update .gitignore Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * Update frame/gilt/src/lib.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * Update frame/gilt/src/mock.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * Fixes * Fixes * Fixes Co-authored-by: Shawn Tabrizi Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> --- .gitignore | 1 + bin/node/runtime/src/impls.rs | 2 +- bin/node/runtime/src/lib.rs | 9 +- frame/babe/src/equivocation.rs | 2 +- frame/babe/src/lib.rs | 2 +- frame/babe/src/mock.rs | 2 +- frame/contracts/src/tests.rs | 2 +- frame/gilt/src/lib.rs | 60 +++- frame/gilt/src/mock.rs | 1 + frame/grandpa/src/equivocation.rs | 2 +- frame/grandpa/src/mock.rs | 2 +- frame/im-online/src/lib.rs | 8 +- frame/offences/benchmarking/src/mock.rs | 2 +- frame/session/benchmarking/src/mock.rs | 2 +- frame/session/src/lib.rs | 4 +- frame/staking/fuzzer/src/mock.rs | 2 +- frame/staking/src/inflation.rs | 2 +- frame/staking/src/lib.rs | 68 ++++- frame/staking/src/mock.rs | 21 +- frame/staking/src/testing_utils.rs | 2 +- frame/staking/src/tests.rs | 16 +- frame/support/src/weights.rs | 11 +- .../fuzzer/src/per_thing_rational.rs | 36 +-- primitives/arithmetic/src/fixed_point.rs | 2 +- primitives/arithmetic/src/lib.rs | 2 +- primitives/arithmetic/src/per_things.rs | 276 ++++++++++-------- primitives/npos-elections/src/helpers.rs | 8 +- primitives/npos-elections/src/lib.rs | 4 +- primitives/npos-elections/src/mock.rs | 2 +- primitives/npos-elections/src/phragmms.rs | 2 +- primitives/npos-elections/src/pjr.rs | 3 +- primitives/npos-elections/src/tests.rs | 10 +- 32 files changed, 342 insertions(+), 226 deletions(-) diff --git a/.gitignore b/.gitignore index ce302c74e10a0..0486a1a716e5c 100644 --- a/.gitignore +++ b/.gitignore @@ -24,3 +24,4 @@ rls*.log .cargo/ .cargo-remote.toml *.bin +*.iml diff --git a/bin/node/runtime/src/impls.rs b/bin/node/runtime/src/impls.rs index c6a56e5ac0dab..416266119cb09 100644 --- a/bin/node/runtime/src/impls.rs +++ b/bin/node/runtime/src/impls.rs @@ -84,7 +84,7 @@ mod multiplier_tests { let t1 = v * (s/m - ss/m); let t2 = v.powi(2) * (s/m - ss/m).powi(2) / 2.0; let next_float = previous_float * (1.0 + t1 + t2); - Multiplier::from_fraction(next_float) + Multiplier::from_float(next_float) } fn run_with_system_weight(w: Weight, assertions: F) where F: Fn() -> () { diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index bb372f31c73b9..49c6cb5291305 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -471,7 +471,7 @@ parameter_types! { pub const ElectionLookahead: BlockNumber = EPOCH_DURATION_IN_BLOCKS / 4; pub const MaxIterations: u32 = 10; // 0.05%. The higher the value, the more strict solution acceptance becomes. - pub MinSolutionScoreBump: Perbill = Perbill::from_rational_approximation(5u32, 10_000); + pub MinSolutionScoreBump: Perbill = Perbill::from_rational(5u32, 10_000); pub OffchainSolutionWeightLimit: Weight = RuntimeBlockWeights::get() .get(DispatchClass::Normal) .max_extrinsic.expect("Normal extrinsics have a weight limit configured; qed") @@ -496,7 +496,7 @@ impl pallet_staking::Config for Runtime { pallet_collective::EnsureProportionAtLeast<_3, _4, AccountId, CouncilCollective> >; type SessionInterface = Self; - type RewardCurve = RewardCurve; + type EraPayout = pallet_staking::ConvertCurve; type NextNewSession = Session; type MaxNominatorRewardedPerValidator = MaxNominatorRewardedPerValidator; type ElectionLookahead = ElectionLookahead; @@ -520,7 +520,7 @@ parameter_types! { pub const Fallback: pallet_election_provider_multi_phase::FallbackStrategy = pallet_election_provider_multi_phase::FallbackStrategy::Nothing; - pub SolutionImprovementThreshold: Perbill = Perbill::from_rational_approximation(1u32, 10_000); + pub SolutionImprovementThreshold: Perbill = Perbill::from_rational(1u32, 10_000); // miner configs pub const MultiPhaseUnsignedPriority: TransactionPriority = StakingUnsignedPriority::get() - 1u64; @@ -767,7 +767,7 @@ parameter_types! { pub const DepositPerContract: Balance = TombstoneDeposit::get(); pub const DepositPerStorageByte: Balance = deposit(0, 1); pub const DepositPerStorageItem: Balance = deposit(1, 0); - pub RentFraction: Perbill = Perbill::from_rational_approximation(1u32, 30 * DAYS); + pub RentFraction: Perbill = Perbill::from_rational(1u32, 30 * DAYS); pub const SurchargeReward: Balance = 150 * MILLICENTS; pub const SignedClaimHandicap: u32 = 2; pub const MaxDepth: u32 = 32; @@ -1065,6 +1065,7 @@ parameter_types! { impl pallet_gilt::Config for Runtime { type Event = Event; type Currency = Balances; + type CurrencyBalance = Balance; type AdminOrigin = frame_system::EnsureRoot; type Deficit = (); type Surplus = (); diff --git a/frame/babe/src/equivocation.rs b/frame/babe/src/equivocation.rs index 14ba0f16cb9e2..30fbaf31371bf 100644 --- a/frame/babe/src/equivocation.rs +++ b/frame/babe/src/equivocation.rs @@ -290,7 +290,7 @@ impl Offence fn slash_fraction(offenders_count: u32, validator_set_count: u32) -> Perbill { // the formula is min((3k / n)^2, 1) - let x = Perbill::from_rational_approximation(3 * offenders_count, validator_set_count); + let x = Perbill::from_rational(3 * offenders_count, validator_set_count); // _ ^ 2 x.square() } diff --git a/frame/babe/src/lib.rs b/frame/babe/src/lib.rs index 00bfa4f2656c9..c259b60c6a7ce 100644 --- a/frame/babe/src/lib.rs +++ b/frame/babe/src/lib.rs @@ -784,7 +784,7 @@ impl frame_support::traits::EstimateNextSessionRotation; type SessionInterface = Self; type UnixTime = pallet_timestamp::Module; - type RewardCurve = RewardCurve; + type EraPayout = pallet_staking::ConvertCurve; type MaxNominatorRewardedPerValidator = MaxNominatorRewardedPerValidator; type NextNewSession = Session; type ElectionLookahead = ElectionLookahead; diff --git a/frame/contracts/src/tests.rs b/frame/contracts/src/tests.rs index 2fa09e3405c1c..afa4dd5416bd3 100644 --- a/frame/contracts/src/tests.rs +++ b/frame/contracts/src/tests.rs @@ -246,7 +246,7 @@ parameter_types! { pub const DepositPerContract: u64 = 8 * DepositPerStorageByte::get(); pub const DepositPerStorageByte: u64 = 10_000; pub const DepositPerStorageItem: u64 = 10_000; - pub RentFraction: Perbill = Perbill::from_rational_approximation(4u32, 10_000u32); + pub RentFraction: Perbill = Perbill::from_rational(4u32, 10_000u32); pub const SurchargeReward: u64 = 500_000; pub const MaxDepth: u32 = 100; pub const MaxValueSize: u32 = 16_384; diff --git a/frame/gilt/src/lib.rs b/frame/gilt/src/lib.rs index ab35ce76742bc..fde7e58c4a111 100644 --- a/frame/gilt/src/lib.rs +++ b/frame/gilt/src/lib.rs @@ -78,7 +78,7 @@ pub mod weights; pub mod pallet { use sp_std::prelude::*; use sp_arithmetic::{Perquintill, PerThing}; - use sp_runtime::traits::{Zero, Saturating, SaturatedConversion}; + use sp_runtime::traits::{Zero, Saturating}; use frame_support::traits::{Currency, OnUnbalanced, ReservableCurrency}; use frame_support::pallet_prelude::*; use frame_system::pallet_prelude::*; @@ -96,7 +96,13 @@ pub mod pallet { type Event: From> + IsType<::Event>; /// Currency type that this works on. - type Currency: ReservableCurrency; + type Currency: ReservableCurrency; + + /// Just the `Currency::Balance` type; we have this item to allow us to constrain it to + /// `From`. + type CurrencyBalance: + sp_runtime::traits::AtLeast32BitUnsigned + codec::FullCodec + Copy + + MaybeSerializeDeserialize + sp_std::fmt::Debug + Default + From; /// Origin required for setting the target proportion to be under gilt. type AdminOrigin: EnsureOrigin; @@ -448,11 +454,10 @@ pub mod pallet { // Multiply the proportion it is by the total issued. let total_issuance = T::Currency::total_issuance().saturating_sub(T::IgnoredIssuance::get()); ActiveTotal::::mutate(|totals| { - let nongilt_issuance: u128 = total_issuance.saturating_sub(totals.frozen) - .saturated_into(); + let nongilt_issuance = total_issuance.saturating_sub(totals.frozen); let effective_issuance = totals.proportion.left_from_one() .saturating_reciprocal_mul(nongilt_issuance); - let gilt_value: BalanceOf = (gilt.proportion * effective_issuance).saturated_into(); + let gilt_value = gilt.proportion * effective_issuance; totals.frozen = totals.frozen.saturating_sub(gilt.amount); totals.proportion = totals.proportion.saturating_sub(gilt.proportion); @@ -488,7 +493,40 @@ pub mod pallet { } } + /// Issuance information returned by `issuance()`. + pub struct IssuanceInfo { + /// The balance held in reserve over all active gilts. + pub reserved: Balance, + /// The issuance not held in reserve for active gilts. Together with `reserved` this sums to + /// `Currency::total_issuance`. + pub non_gilt: Balance, + /// The balance that `reserved` is effectively worth, at present. This is not issued funds + /// and could be less than `reserved` (though in most cases should be greater). + pub effective: Balance, + } + impl Pallet { + /// Get the target amount of Gilts that we're aiming for. + pub fn target() -> Perquintill { + ActiveTotal::::get().target + } + + /// Returns information on the issuance of gilts. + pub fn issuance() -> IssuanceInfo> { + let totals = ActiveTotal::::get(); + + let total_issuance = T::Currency::total_issuance(); + let non_gilt = total_issuance.saturating_sub(totals.frozen); + let effective = totals.proportion.left_from_one() + .saturating_reciprocal_mul(non_gilt); + + IssuanceInfo { + reserved: totals.frozen, + non_gilt, + effective, + } + } + /// Attempt to enlarge our gilt-set from bids in order to satisfy our desired target amount /// of funds frozen into gilts. pub fn pursue_target(max_bids: u32) -> Weight { @@ -497,11 +535,10 @@ pub mod pallet { let missing = totals.target.saturating_sub(totals.proportion); let total_issuance = T::Currency::total_issuance().saturating_sub(T::IgnoredIssuance::get()); - let nongilt_issuance: u128 = total_issuance.saturating_sub(totals.frozen) - .saturated_into(); + let nongilt_issuance = total_issuance.saturating_sub(totals.frozen); let effective_issuance = totals.proportion.left_from_one() .saturating_reciprocal_mul(nongilt_issuance); - let intake: BalanceOf = (missing * effective_issuance).saturated_into(); + let intake = missing * effective_issuance; let (bids_taken, queues_hit) = Self::enlarge(intake, max_bids); let first_from_each_queue = T::WeightInfo::pursue_target_per_queue(queues_hit); @@ -550,13 +587,12 @@ pub mod pallet { qs[queue_index].1 = qs[queue_index].1.saturating_sub(bid.amount); // Now to activate the bid... - let nongilt_issuance: u128 = total_issuance.saturating_sub(totals.frozen) - .saturated_into(); + let nongilt_issuance = total_issuance.saturating_sub(totals.frozen); let effective_issuance = totals.proportion.left_from_one() .saturating_reciprocal_mul(nongilt_issuance); - let n: u128 = amount.saturated_into(); + let n = amount; let d = effective_issuance; - let proportion = Perquintill::from_rational_approximation(n, d); + let proportion = Perquintill::from_rational(n, d); let who = bid.who; let index = totals.index; totals.frozen += bid.amount; diff --git a/frame/gilt/src/mock.rs b/frame/gilt/src/mock.rs index ca4ccaff73c58..b943089a741ee 100644 --- a/frame/gilt/src/mock.rs +++ b/frame/gilt/src/mock.rs @@ -103,6 +103,7 @@ ord_parameter_types! { impl pallet_gilt::Config for Test { type Event = Event; type Currency = Balances; + type CurrencyBalance = ::Balance; type AdminOrigin = frame_system::EnsureSignedBy; type Deficit = (); type Surplus = (); diff --git a/frame/grandpa/src/equivocation.rs b/frame/grandpa/src/equivocation.rs index 37496fdeb8592..8ab86b2fed065 100644 --- a/frame/grandpa/src/equivocation.rs +++ b/frame/grandpa/src/equivocation.rs @@ -358,7 +358,7 @@ impl Offence fn slash_fraction(offenders_count: u32, validator_set_count: u32) -> Perbill { // the formula is min((3k / n)^2, 1) - let x = Perbill::from_rational_approximation(3 * offenders_count, validator_set_count); + let x = Perbill::from_rational(3 * offenders_count, validator_set_count); // _ ^ 2 x.square() } diff --git a/frame/grandpa/src/mock.rs b/frame/grandpa/src/mock.rs index 6e83ae481d271..d36d6a9fbc7a5 100644 --- a/frame/grandpa/src/mock.rs +++ b/frame/grandpa/src/mock.rs @@ -211,7 +211,7 @@ impl pallet_staking::Config for Test { type SlashCancelOrigin = frame_system::EnsureRoot; type SessionInterface = Self; type UnixTime = pallet_timestamp::Module; - type RewardCurve = RewardCurve; + type EraPayout = pallet_staking::ConvertCurve; type MaxNominatorRewardedPerValidator = MaxNominatorRewardedPerValidator; type NextNewSession = Session; type ElectionLookahead = ElectionLookahead; diff --git a/frame/im-online/src/lib.rs b/frame/im-online/src/lib.rs index e00b5aa9d1395..df0cfa92dbb25 100644 --- a/frame/im-online/src/lib.rs +++ b/frame/im-online/src/lib.rs @@ -100,11 +100,7 @@ use frame_support::{ }, Parameter, }; -use frame_system::ensure_none; -use frame_system::offchain::{ - SendTransactionTypes, - SubmitTransaction, -}; +use frame_system::{ensure_none, offchain::{SendTransactionTypes, SubmitTransaction}}; pub use weights::WeightInfo; pub mod sr25519 { @@ -813,7 +809,7 @@ impl Offence for UnresponsivenessOffence { // basically, 10% can be offline with no slash, but after that, it linearly climbs up to 7% // when 13/30 are offline (around 5% when 1/3 are offline). if let Some(threshold) = offenders.checked_sub(validator_set_count / 10 + 1) { - let x = Perbill::from_rational_approximation(3 * threshold, validator_set_count); + let x = Perbill::from_rational(3 * threshold, validator_set_count); x.saturating_mul(Perbill::from_percent(7)) } else { Perbill::default() diff --git a/frame/offences/benchmarking/src/mock.rs b/frame/offences/benchmarking/src/mock.rs index d659025247d1e..e374ad73a558a 100644 --- a/frame/offences/benchmarking/src/mock.rs +++ b/frame/offences/benchmarking/src/mock.rs @@ -170,7 +170,7 @@ impl pallet_staking::Config for Test { type SlashCancelOrigin = frame_system::EnsureRoot; type BondingDuration = (); type SessionInterface = Self; - type RewardCurve = RewardCurve; + type EraPayout = pallet_staking::ConvertCurve; type NextNewSession = Session; type ElectionLookahead = (); type Call = Call; diff --git a/frame/session/benchmarking/src/mock.rs b/frame/session/benchmarking/src/mock.rs index 8c392c4e10969..539225c852598 100644 --- a/frame/session/benchmarking/src/mock.rs +++ b/frame/session/benchmarking/src/mock.rs @@ -175,7 +175,7 @@ impl pallet_staking::Config for Test { type SlashCancelOrigin = frame_system::EnsureRoot; type BondingDuration = (); type SessionInterface = Self; - type RewardCurve = RewardCurve; + type EraPayout = pallet_staking::ConvertCurve; type NextNewSession = Session; type ElectionLookahead = (); type Call = Call; diff --git a/frame/session/src/lib.rs b/frame/session/src/lib.rs index 45f3ae9dfce47..77157aa8347cf 100644 --- a/frame/session/src/lib.rs +++ b/frame/session/src/lib.rs @@ -177,12 +177,12 @@ impl< // (0% is never returned). let progress = if now >= offset { let current = (now - offset) % period.clone() + One::one(); - Some(Percent::from_rational_approximation( + Some(Percent::from_rational( current.clone(), period.clone(), )) } else { - Some(Percent::from_rational_approximation( + Some(Percent::from_rational( now + One::one(), offset, )) diff --git a/frame/staking/fuzzer/src/mock.rs b/frame/staking/fuzzer/src/mock.rs index a87e1fc083013..8df365737fc60 100644 --- a/frame/staking/fuzzer/src/mock.rs +++ b/frame/staking/fuzzer/src/mock.rs @@ -185,7 +185,7 @@ impl pallet_staking::Config for Test { type SlashCancelOrigin = frame_system::EnsureRoot; type BondingDuration = (); type SessionInterface = Self; - type RewardCurve = RewardCurve; + type EraPayout = pallet_staking::ConvertCurve; type NextNewSession = Session; type ElectionLookahead = (); type Call = Call; diff --git a/frame/staking/src/inflation.rs b/frame/staking/src/inflation.rs index bd9d1f8bbdb30..e5259543fd4ba 100644 --- a/frame/staking/src/inflation.rs +++ b/frame/staking/src/inflation.rs @@ -38,7 +38,7 @@ pub fn compute_total_payout( // Milliseconds per year for the Julian year (365.25 days). const MILLISECONDS_PER_YEAR: u64 = 1000 * 3600 * 24 * 36525 / 100; - let portion = Perbill::from_rational_approximation(era_duration as u64, MILLISECONDS_PER_YEAR); + let portion = Perbill::from_rational(era_duration as u64, MILLISECONDS_PER_YEAR); let payout = portion * yearly_inflation.calculate_for_fraction_times_denominator( npos_token_staked, total_tokens.clone(), diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index 239effc364434..187f9f30e08a9 100644 --- a/frame/staking/src/lib.rs +++ b/frame/staking/src/lib.rs @@ -782,6 +782,51 @@ impl SessionInterface<::AccountId> for T w } } +/// Handler for determining how much of a balance should be paid out on the current era. +pub trait EraPayout { + /// Determine the payout for this era. + /// + /// Returns the amount to be paid to stakers in this era, as well as whatever else should be + /// paid out ("the rest"). + fn era_payout( + total_staked: Balance, + total_issuance: Balance, + era_duration_millis: u64, + ) -> (Balance, Balance); +} + +impl EraPayout for () { + fn era_payout( + _total_staked: Balance, + _total_issuance: Balance, + _era_duration_millis: u64, + ) -> (Balance, Balance) { + (Default::default(), Default::default()) + } +} + +pub struct ConvertCurve(sp_std::marker::PhantomData); +impl< + Balance: AtLeast32BitUnsigned + Clone, + T: Get<&'static PiecewiseLinear<'static>>, +> EraPayout for ConvertCurve { + fn era_payout( + total_staked: Balance, + total_issuance: Balance, + era_duration_millis: u64, + ) -> (Balance, Balance) { + let (validator_payout, max_payout) = inflation::compute_total_payout( + &T::get(), + total_staked, + total_issuance, + // Duration of era; more than u64::MAX is rewarded as u64::MAX. + era_duration_millis, + ); + let rest = max_payout.saturating_sub(validator_payout.clone()); + (validator_payout, rest) + } +} + pub trait Config: frame_system::Config + SendTransactionTypes> { /// The staking balance. type Currency: LockableCurrency; @@ -838,9 +883,9 @@ pub trait Config: frame_system::Config + SendTransactionTypes> { /// Interface for interacting with a session module. type SessionInterface: self::SessionInterface; - /// The NPoS reward curve used to define yearly inflation. + /// The payout for validators and the system for the current era. /// See [Era payout](./index.html#era-payout). - type RewardCurve: Get<&'static PiecewiseLinear<'static>>; + type EraPayout: EraPayout>; /// Something that can estimate the next session change, accurately or as a best effort guess. type NextNewSession: EstimateNextNewSession; @@ -2413,7 +2458,7 @@ impl Module { // This is the fraction of the total reward that the validator and the // nominators will get. - let validator_total_reward_part = Perbill::from_rational_approximation( + let validator_total_reward_part = Perbill::from_rational( validator_reward_points, total_reward_points, ); @@ -2428,7 +2473,7 @@ impl Module { let validator_leftover_payout = validator_total_payout - validator_commission_payout; // Now let's calculate how this is split to the validator. - let validator_exposure_part = Perbill::from_rational_approximation( + let validator_exposure_part = Perbill::from_rational( exposure.own, exposure.total, ); @@ -2445,7 +2490,7 @@ impl Module { // Lets now calculate how this is split to the nominators. // Reward only the clipped exposures. Note this is not necessarily sorted. for nominator in exposure.others.iter() { - let nominator_exposure_part = Perbill::from_rational_approximation( + let nominator_exposure_part = Perbill::from_rational( nominator.value, exposure.total, ); @@ -2837,15 +2882,10 @@ impl Module { if let Some(active_era_start) = active_era.start { let now_as_millis_u64 = T::UnixTime::now().as_millis().saturated_into::(); - let era_duration = now_as_millis_u64 - active_era_start; - let (validator_payout, max_payout) = inflation::compute_total_payout( - &T::RewardCurve::get(), - Self::eras_total_stake(&active_era.index), - T::Currency::total_issuance(), - // Duration of era; more than u64::MAX is rewarded as u64::MAX. - era_duration.saturated_into::(), - ); - let rest = max_payout.saturating_sub(validator_payout); + let era_duration = (now_as_millis_u64 - active_era_start).saturated_into::(); + let staked = Self::eras_total_stake(&active_era.index); + let issuance = T::Currency::total_issuance(); + let (validator_payout, rest) = T::EraPayout::era_payout(staked, issuance, era_duration); Self::deposit_event(RawEvent::EraPayout(active_era.index, validator_payout, rest)); diff --git a/frame/staking/src/mock.rs b/frame/staking/src/mock.rs index b0e3d9629a358..40f59fa71cd65 100644 --- a/frame/staking/src/mock.rs +++ b/frame/staking/src/mock.rs @@ -260,7 +260,7 @@ impl Config for Test { type SlashCancelOrigin = frame_system::EnsureRoot; type BondingDuration = BondingDuration; type SessionInterface = Self; - type RewardCurve = RewardCurve; + type EraPayout = ConvertCurve; type NextNewSession = Session; type ElectionLookahead = ElectionLookahead; type Call = Call; @@ -670,25 +670,22 @@ pub(crate) fn start_active_era(era_index: EraIndex) { } pub(crate) fn current_total_payout_for_duration(duration: u64) -> Balance { - let reward = inflation::compute_total_payout( - ::RewardCurve::get(), + let (payout, _rest) = ::EraPayout::era_payout( Staking::eras_total_stake(active_era()), Balances::total_issuance(), duration, - ) - .0; - assert!(reward > 0); - reward + ); + assert!(payout > 0); + payout } pub(crate) fn maximum_payout_for_duration(duration: u64) -> Balance { - inflation::compute_total_payout( - ::RewardCurve::get(), - 0, + let (payout, rest) = ::EraPayout::era_payout( + Staking::eras_total_stake(active_era()), Balances::total_issuance(), duration, - ) - .1 + ); + payout + rest } /// Time it takes to finish a session. diff --git a/frame/staking/src/testing_utils.rs b/frame/staking/src/testing_utils.rs index 5affc50d81df7..afe36f55b1dcf 100644 --- a/frame/staking/src/testing_utils.rs +++ b/frame/staking/src/testing_utils.rs @@ -376,7 +376,7 @@ pub fn create_assignments_for_offchain( ), &'static str > { - let ratio = OffchainAccuracy::from_rational_approximation(1, MAX_NOMINATIONS); + let ratio = OffchainAccuracy::from_rational(1, MAX_NOMINATIONS); let assignments: Vec> = >::iter() .take(num_assignments as usize) .map(|(n, t)| Assignment { diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index 0008f8cdba6dc..43ce2259fac7d 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -209,10 +209,10 @@ fn rewards_should_work() { individual: vec![(11, 100), (21, 50)].into_iter().collect(), } ); - let part_for_10 = Perbill::from_rational_approximation::(1000, 1125); - let part_for_20 = Perbill::from_rational_approximation::(1000, 1375); - let part_for_100_from_10 = Perbill::from_rational_approximation::(125, 1125); - let part_for_100_from_20 = Perbill::from_rational_approximation::(375, 1375); + let part_for_10 = Perbill::from_rational::(1000, 1125); + let part_for_20 = Perbill::from_rational::(1000, 1375); + let part_for_100_from_10 = Perbill::from_rational::(125, 1125); + let part_for_100_from_20 = Perbill::from_rational::(375, 1375); start_session(2); start_session(3); @@ -598,8 +598,8 @@ fn nominators_also_get_slashed_pro_rata() { let slash_amount = slash_percent * exposed_stake; let validator_share = - Perbill::from_rational_approximation(exposed_validator, exposed_stake) * slash_amount; - let nominator_share = Perbill::from_rational_approximation( + Perbill::from_rational(exposed_validator, exposed_stake) * slash_amount; + let nominator_share = Perbill::from_rational( exposed_nominator, exposed_stake, ) * slash_amount; @@ -4270,8 +4270,8 @@ fn claim_reward_at_the_last_era_and_no_double_claim_and_invalid_claim() { let init_balance_10 = Balances::total_balance(&10); let init_balance_100 = Balances::total_balance(&100); - let part_for_10 = Perbill::from_rational_approximation::(1000, 1125); - let part_for_100 = Perbill::from_rational_approximation::(125, 1125); + let part_for_10 = Perbill::from_rational::(1000, 1125); + let part_for_100 = Perbill::from_rational::(125, 1125); // Check state Payee::::insert(11, RewardDestination::Controller); diff --git a/frame/support/src/weights.rs b/frame/support/src/weights.rs index abd54994bc9e8..840b1c3c01ac9 100644 --- a/frame/support/src/weights.rs +++ b/frame/support/src/weights.rs @@ -130,11 +130,8 @@ #[cfg(feature = "std")] use serde::{Serialize, Deserialize}; use codec::{Encode, Decode}; -use sp_runtime::{ - RuntimeDebug, - traits::SignedExtension, - generic::{CheckedExtrinsic, UncheckedExtrinsic}, -}; +use sp_runtime::{RuntimeDebug, traits::SignedExtension}; +use sp_runtime::generic::{CheckedExtrinsic, UncheckedExtrinsic}; use crate::dispatch::{DispatchErrorWithPostInfo, DispatchResultWithPostInfo, DispatchError}; use sp_runtime::traits::SaturatedConversion; use sp_arithmetic::{Perbill, traits::{BaseArithmetic, Saturating, Unsigned}}; @@ -964,13 +961,13 @@ mod tests { smallvec![ WeightToFeeCoefficient { coeff_integer: 0, - coeff_frac: Perbill::from_fraction(0.5), + coeff_frac: Perbill::from_float(0.5), negative: false, degree: 3 }, WeightToFeeCoefficient { coeff_integer: 2, - coeff_frac: Perbill::from_rational_approximation(1u32, 3u32), + coeff_frac: Perbill::from_rational(1u32, 3u32), negative: false, degree: 2 }, diff --git a/primitives/arithmetic/fuzzer/src/per_thing_rational.rs b/primitives/arithmetic/fuzzer/src/per_thing_rational.rs index ff172b8bd2704..47ba5a4803056 100644 --- a/primitives/arithmetic/fuzzer/src/per_thing_rational.rs +++ b/primitives/arithmetic/fuzzer/src/per_thing_rational.rs @@ -38,75 +38,75 @@ fn main() { // peru16 let (smaller, bigger) = (u16_pair.0.min(u16_pair.1), u16_pair.0.max(u16_pair.1)); - let ratio = PerU16::from_rational_approximation(smaller, bigger); + let ratio = PerU16::from_rational(smaller, bigger); assert_per_thing_equal_error( ratio, - PerU16::from_fraction(smaller as f64 / bigger.max(1) as f64), + PerU16::from_float(smaller as f64 / bigger.max(1) as f64), 1, ); let (smaller, bigger) = (u32_pair.0.min(u32_pair.1), u32_pair.0.max(u32_pair.1)); - let ratio = PerU16::from_rational_approximation(smaller, bigger); + let ratio = PerU16::from_rational(smaller, bigger); assert_per_thing_equal_error( ratio, - PerU16::from_fraction(smaller as f64 / bigger.max(1) as f64), + PerU16::from_float(smaller as f64 / bigger.max(1) as f64), 1, ); let (smaller, bigger) = (u64_pair.0.min(u64_pair.1), u64_pair.0.max(u64_pair.1)); - let ratio = PerU16::from_rational_approximation(smaller, bigger); + let ratio = PerU16::from_rational(smaller, bigger); assert_per_thing_equal_error( ratio, - PerU16::from_fraction(smaller as f64 / bigger.max(1) as f64), + PerU16::from_float(smaller as f64 / bigger.max(1) as f64), 1, ); // percent let (smaller, bigger) = (u16_pair.0.min(u16_pair.1), u16_pair.0.max(u16_pair.1)); - let ratio = Percent::from_rational_approximation(smaller, bigger); + let ratio = Percent::from_rational(smaller, bigger); assert_per_thing_equal_error( ratio, - Percent::from_fraction(smaller as f64 / bigger.max(1) as f64), + Percent::from_float(smaller as f64 / bigger.max(1) as f64), 1, ); let (smaller, bigger) = (u32_pair.0.min(u32_pair.1), u32_pair.0.max(u32_pair.1)); - let ratio = Percent::from_rational_approximation(smaller, bigger); + let ratio = Percent::from_rational(smaller, bigger); assert_per_thing_equal_error( ratio, - Percent::from_fraction(smaller as f64 / bigger.max(1) as f64), + Percent::from_float(smaller as f64 / bigger.max(1) as f64), 1, ); let (smaller, bigger) = (u64_pair.0.min(u64_pair.1), u64_pair.0.max(u64_pair.1)); - let ratio = Percent::from_rational_approximation(smaller, bigger); + let ratio = Percent::from_rational(smaller, bigger); assert_per_thing_equal_error( ratio, - Percent::from_fraction(smaller as f64 / bigger.max(1) as f64), + Percent::from_float(smaller as f64 / bigger.max(1) as f64), 1, ); // perbill let (smaller, bigger) = (u32_pair.0.min(u32_pair.1), u32_pair.0.max(u32_pair.1)); - let ratio = Perbill::from_rational_approximation(smaller, bigger); + let ratio = Perbill::from_rational(smaller, bigger); assert_per_thing_equal_error( ratio, - Perbill::from_fraction(smaller as f64 / bigger.max(1) as f64), + Perbill::from_float(smaller as f64 / bigger.max(1) as f64), 100, ); let (smaller, bigger) = (u64_pair.0.min(u64_pair.1), u64_pair.0.max(u64_pair.1)); - let ratio = Perbill::from_rational_approximation(smaller, bigger); + let ratio = Perbill::from_rational(smaller, bigger); assert_per_thing_equal_error( ratio, - Perbill::from_fraction(smaller as f64 / bigger.max(1) as f64), + Perbill::from_float(smaller as f64 / bigger.max(1) as f64), 100, ); // perquintillion let (smaller, bigger) = (u64_pair.0.min(u64_pair.1), u64_pair.0.max(u64_pair.1)); - let ratio = Perquintill::from_rational_approximation(smaller, bigger); + let ratio = Perquintill::from_rational(smaller, bigger); assert_per_thing_equal_error( ratio, - Perquintill::from_fraction(smaller as f64 / bigger.max(1) as f64), + Perquintill::from_float(smaller as f64 / bigger.max(1) as f64), 1000, ); diff --git a/primitives/arithmetic/src/fixed_point.rs b/primitives/arithmetic/src/fixed_point.rs index 896d5f38451de..b837c360c7c54 100644 --- a/primitives/arithmetic/src/fixed_point.rs +++ b/primitives/arithmetic/src/fixed_point.rs @@ -376,7 +376,7 @@ macro_rules! implement_fixed { } #[cfg(any(feature = "std", test))] - pub fn from_fraction(x: f64) -> Self { + pub fn from_float(x: f64) -> Self { Self((x * (::DIV as f64)) as $inner_type) } diff --git a/primitives/arithmetic/src/lib.rs b/primitives/arithmetic/src/lib.rs index 561c14a37e203..d6069ad5154d1 100644 --- a/primitives/arithmetic/src/lib.rs +++ b/primitives/arithmetic/src/lib.rs @@ -494,7 +494,7 @@ mod threshold_compare_tests { fn peru16_rational_does_not_overflow() { // A historical example that will panic only for per_thing type that are created with // maximum capacity of their type, e.g. PerU16. - let _ = PerU16::from_rational_approximation(17424870u32, 17424870); + let _ = PerU16::from_rational(17424870u32, 17424870); } #[test] diff --git a/primitives/arithmetic/src/per_things.rs b/primitives/arithmetic/src/per_things.rs index f2b8c4f93b33f..29d5d2be73a1c 100644 --- a/primitives/arithmetic/src/per_things.rs +++ b/primitives/arithmetic/src/per_things.rs @@ -18,8 +18,9 @@ #[cfg(feature = "std")] use serde::{Serialize, Deserialize}; -use sp_std::{ops, fmt, prelude::*, convert::TryInto}; +use sp_std::{ops, fmt, prelude::*, convert::{TryFrom, TryInto}}; use codec::{Encode, CompactAs}; +use num_traits::Pow; use crate::traits::{ SaturatedConversion, UniqueSaturatedInto, Saturating, BaseArithmetic, Bounded, Zero, Unsigned, One, @@ -36,6 +37,7 @@ pub type UpperOf

=

::Upper; /// `X`_. pub trait PerThing: Sized + Saturating + Copy + Default + Eq + PartialEq + Ord + PartialOrd + Bounded + fmt::Debug + + ops::Div + ops::Mul + Pow { /// The data type used to build this per-thingy. type Inner: BaseArithmetic + Unsigned + Copy + Into + fmt::Debug; @@ -70,14 +72,14 @@ pub trait PerThing: fn from_percent(x: Self::Inner) -> Self { let a: Self::Inner = x.min(100.into()); let b: Self::Inner = 100.into(); - Self::from_rational_approximation::(a, b) + Self::from_rational::(a, b) } /// Return the product of multiplication of this value by itself. fn square(self) -> Self { let p = Self::Upper::from(self.deconstruct()); let q = Self::Upper::from(Self::ACCURACY); - Self::from_rational_approximation::(p * p, q * q) + Self::from_rational::(p * p, q * q) } /// Return the part left when `self` is saturating-subtracted from `Self::one()`. @@ -204,7 +206,12 @@ pub trait PerThing: /// Converts a fraction into `Self`. #[cfg(feature = "std")] - fn from_fraction(x: f64) -> Self; + fn from_float(x: f64) -> Self; + + /// Same as `Self::from_float`. + #[deprecated = "Use from_float instead"] + #[cfg(feature = "std")] + fn from_fraction(x: f64) -> Self { Self::from_float(x) } /// Approximate the fraction `p/q` into a per-thing fraction. This will never overflow. /// @@ -219,16 +226,28 @@ pub trait PerThing: /// # fn main () { /// // 989/100 is technically closer to 99%. /// assert_eq!( - /// Percent::from_rational_approximation(989u64, 1000), + /// Percent::from_rational(989u64, 1000), /// Percent::from_parts(98), /// ); /// # } /// ``` - fn from_rational_approximation(p: N, q: N) -> Self + fn from_rational(p: N, q: N) -> Self where N: Clone + Ord + TryInto + TryInto + ops::Div + ops::Rem + ops::Add + Unsigned, Self::Inner: Into; + + /// Same as `Self::from_rational`. + #[deprecated = "Use from_rational instead"] + fn from_rational_approximation(p: N, q: N) -> Self + where + N: Clone + Ord + TryInto + TryInto + + ops::Div + ops::Rem + ops::Add + Unsigned + + Zero + One, + Self::Inner: Into, + { + Self::from_rational(p, q) + } } /// The rounding method to use. @@ -369,11 +388,11 @@ macro_rules! implement_per_thing { /// NOTE: saturate to 0 or 1 if x is beyond `[0, 1]` #[cfg(feature = "std")] - fn from_fraction(x: f64) -> Self { + fn from_float(x: f64) -> Self { Self::from_parts((x.max(0.).min(1.) * $max as f64) as Self::Inner) } - fn from_rational_approximation(p: N, q: N) -> Self + fn from_rational(p: N, q: N) -> Self where N: Clone + Ord + TryInto + TryInto + ops::Div + ops::Rem + ops::Add + Unsigned @@ -471,20 +490,31 @@ macro_rules! implement_per_thing { PerThing::square(self) } - /// See [`PerThing::from_fraction`]. + /// See [`PerThing::from_float`]. #[cfg(feature = "std")] - pub fn from_fraction(x: f64) -> Self { - ::from_fraction(x) + pub fn from_float(x: f64) -> Self { + ::from_float(x) } - /// See [`PerThing::from_rational_approximation`]. + /// See [`PerThing::from_rational`]. + #[deprecated = "Use `PerThing::from_rational` instead"] pub fn from_rational_approximation(p: N, q: N) -> Self where N: Clone + Ord + TryInto<$type> + TryInto<$upper_type> + ops::Div + ops::Rem + ops::Add + Unsigned, $type: Into, { - ::from_rational_approximation(p, q) + ::from_rational(p, q) + } + + /// See [`PerThing::from_rational`]. + pub fn from_rational(p: N, q: N) -> Self + where N: Clone + Ord + TryInto<$type> + + TryInto<$upper_type> + ops::Div + ops::Rem + + ops::Add + Unsigned, + $type: Into, + { + ::from_rational(p, q) } /// See [`PerThing::mul_floor`]. @@ -561,37 +591,13 @@ macro_rules! implement_per_thing { /// Saturating multiply. Compute `self * rhs`, saturating at the numeric bounds instead of /// overflowing. This operation is lossy. fn saturating_mul(self, rhs: Self) -> Self { - let a = self.0 as $upper_type; - let b = rhs.0 as $upper_type; - let m = <$upper_type>::from($max); - let parts = a * b / m; - // This will always fit into $type. - Self::from_parts(parts as $type) + self * rhs } /// Saturating exponentiation. Computes `self.pow(exp)`, saturating at the numeric /// bounds instead of overflowing. This operation is lossy. fn saturating_pow(self, exp: usize) -> Self { - if self.is_zero() || self.is_one() { - self - } else { - let p = <$name as PerThing>::Upper::from(self.deconstruct()); - let q = <$name as PerThing>::Upper::from(Self::ACCURACY); - let mut s = Self::one(); - for _ in 0..exp { - if s.is_zero() { - break; - } else { - // x^2 always fits in Self::Upper if x fits in Self::Inner. - // Verified by a test. - s = Self::from_rational_approximation( - <$name as PerThing>::Upper::from(s.deconstruct()) * p, - q * q, - ); - } - } - s - } + self.pow(exp) } } @@ -607,7 +613,7 @@ macro_rules! implement_per_thing { } } - impl crate::traits::Bounded for $name { + impl Bounded for $name { fn min_value() -> Self { ::zero() } @@ -617,13 +623,48 @@ macro_rules! implement_per_thing { } } + impl ops::Mul for $name { + type Output = Self; + + fn mul(self, rhs: Self) -> Self::Output { + let a = self.0 as $upper_type; + let b = rhs.0 as $upper_type; + let m = <$upper_type>::from($max); + let parts = a * b / m; + // This will always fit into $type. + Self::from_parts(parts as $type) + } + } + + impl Pow for $name { + type Output = Self; + + fn pow(self, exp: usize) -> Self::Output { + if exp == 0 || self.is_one() { + return Self::one() + } + let mut result = self; + let mut exp = exp - 1; + while exp > 0 && !result.is_zero() { + if exp % 2 == 0 { + result = result.square(); + exp /= 2; + } else { + result = result * self; + exp -= 1; + } + } + result + } + } + impl ops::Div for $name { type Output = Self; fn div(self, rhs: Self) -> Self::Output { let p = self.0; let q = rhs.0; - Self::from_rational_approximation(p, q) + Self::from_rational(p, q) } } @@ -648,6 +689,13 @@ macro_rules! implement_per_thing { } } + impl ops::Div for $name where $type: TryFrom { + type Output = Self; + fn div(self, b: N) -> Self::Output { + <$type>::try_from(b).map_or(Self::zero(), |d| Self::from_parts(self.0 / d)) + } + } + #[cfg(test)] mod $test_mod { use codec::{Encode, Decode}; @@ -657,13 +705,13 @@ macro_rules! implement_per_thing { #[test] fn macro_expanded_correctly() { // needed for the `from_percent` to work. UPDATE: this is no longer needed; yet note - // that tests that use percentage or fractions such as $name::from_fraction(0.2) to + // that tests that use percentage or fractions such as $name::from_float(0.2) to // create values will most likely be inaccurate when used with per_things that are // not multiples of 100. // assert!($max >= 100); // assert!($max % 100 == 0); - // needed for `from_rational_approximation` + // needed for `from_rational` assert!(2 * ($max as $upper_type) < <$upper_type>::max_value()); assert!(<$upper_type>::from($max) < <$upper_type>::max_value()); @@ -737,11 +785,11 @@ macro_rules! implement_per_thing { assert_eq!($name::from_percent(100), $name::from_parts($max)); assert_eq!($name::from_percent(200), $name::from_parts($max)); - assert_eq!($name::from_fraction(0.0), $name::from_parts(Zero::zero())); - assert_eq!($name::from_fraction(0.1), $name::from_parts($max / 10)); - assert_eq!($name::from_fraction(1.0), $name::from_parts($max)); - assert_eq!($name::from_fraction(2.0), $name::from_parts($max)); - assert_eq!($name::from_fraction(-1.0), $name::from_parts(Zero::zero())); + assert_eq!($name::from_float(0.0), $name::from_parts(Zero::zero())); + assert_eq!($name::from_float(0.1), $name::from_parts($max / 10)); + assert_eq!($name::from_float(1.0), $name::from_parts($max)); + assert_eq!($name::from_float(2.0), $name::from_parts($max)); + assert_eq!($name::from_float(-1.0), $name::from_parts(Zero::zero())); } #[test] @@ -763,7 +811,7 @@ macro_rules! implement_per_thing { ($num_type:tt) => { // multiplication from all sort of from_percent assert_eq!( - $name::from_fraction(1.0) * $num_type::max_value(), + $name::from_float(1.0) * $num_type::max_value(), $num_type::max_value() ); if $max % 100 == 0 { @@ -773,7 +821,7 @@ macro_rules! implement_per_thing { 1, ); assert_eq!( - $name::from_fraction(0.5) * $num_type::max_value(), + $name::from_float(0.5) * $num_type::max_value(), $num_type::max_value() / 2, ); assert_eq_error_rate!( @@ -783,30 +831,30 @@ macro_rules! implement_per_thing { ); } else { assert_eq!( - $name::from_fraction(0.99) * <$num_type>::max_value(), + $name::from_float(0.99) * <$num_type>::max_value(), ( ( - u256ify!($name::from_fraction(0.99).0) * + u256ify!($name::from_float(0.99).0) * u256ify!(<$num_type>::max_value()) / u256ify!($max) ).as_u128() ) as $num_type, ); assert_eq!( - $name::from_fraction(0.50) * <$num_type>::max_value(), + $name::from_float(0.50) * <$num_type>::max_value(), ( ( - u256ify!($name::from_fraction(0.50).0) * + u256ify!($name::from_float(0.50).0) * u256ify!(<$num_type>::max_value()) / u256ify!($max) ).as_u128() ) as $num_type, ); assert_eq!( - $name::from_fraction(0.01) * <$num_type>::max_value(), + $name::from_float(0.01) * <$num_type>::max_value(), ( ( - u256ify!($name::from_fraction(0.01).0) * + u256ify!($name::from_float(0.01).0) * u256ify!(<$num_type>::max_value()) / u256ify!($max) ).as_u128() @@ -814,7 +862,7 @@ macro_rules! implement_per_thing { ); } - assert_eq!($name::from_fraction(0.0) * $num_type::max_value(), 0); + assert_eq!($name::from_float(0.0) * $num_type::max_value(), 0); // // multiplication with bounds assert_eq!($name::one() * $num_type::max_value(), $num_type::max_value()); @@ -828,7 +876,7 @@ macro_rules! implement_per_thing { // accuracy test assert_eq!( - $name::from_rational_approximation(1 as $type, 3) * 30 as $type, + $name::from_rational(1 as $type, 3) * 30 as $type, 10, ); @@ -837,10 +885,10 @@ macro_rules! implement_per_thing { #[test] fn per_thing_mul_rounds_to_nearest_number() { - assert_eq!($name::from_fraction(0.33) * 10u64, 3); - assert_eq!($name::from_fraction(0.34) * 10u64, 3); - assert_eq!($name::from_fraction(0.35) * 10u64, 3); - assert_eq!($name::from_fraction(0.36) * 10u64, 4); + assert_eq!($name::from_float(0.33) * 10u64, 3); + assert_eq!($name::from_float(0.34) * 10u64, 3); + assert_eq!($name::from_float(0.35) * 10u64, 3); + assert_eq!($name::from_float(0.36) * 10u64, 4); } #[test] @@ -858,33 +906,33 @@ macro_rules! implement_per_thing { ($num_type:tt) => { // within accuracy boundary assert_eq!( - $name::from_rational_approximation(1 as $num_type, 0), + $name::from_rational(1 as $num_type, 0), $name::one(), ); assert_eq!( - $name::from_rational_approximation(1 as $num_type, 1), + $name::from_rational(1 as $num_type, 1), $name::one(), ); assert_eq_error_rate!( - $name::from_rational_approximation(1 as $num_type, 3).0, + $name::from_rational(1 as $num_type, 3).0, $name::from_parts($max / 3).0, 2 ); assert_eq!( - $name::from_rational_approximation(1 as $num_type, 10), - $name::from_fraction(0.10), + $name::from_rational(1 as $num_type, 10), + $name::from_float(0.10), ); assert_eq!( - $name::from_rational_approximation(1 as $num_type, 4), - $name::from_fraction(0.25), + $name::from_rational(1 as $num_type, 4), + $name::from_float(0.25), ); assert_eq!( - $name::from_rational_approximation(1 as $num_type, 4), - $name::from_rational_approximation(2 as $num_type, 8), + $name::from_rational(1 as $num_type, 4), + $name::from_rational(2 as $num_type, 8), ); // no accurate anymore but won't overflow. assert_eq_error_rate!( - $name::from_rational_approximation( + $name::from_rational( $num_type::max_value() - 1, $num_type::max_value() ).0 as $upper_type, @@ -892,7 +940,7 @@ macro_rules! implement_per_thing { 2, ); assert_eq_error_rate!( - $name::from_rational_approximation( + $name::from_rational( $num_type::max_value() / 3, $num_type::max_value() ).0 as $upper_type, @@ -900,7 +948,7 @@ macro_rules! implement_per_thing { 2, ); assert_eq!( - $name::from_rational_approximation(1, $num_type::max_value()), + $name::from_rational(1, $num_type::max_value()), $name::zero(), ); }; @@ -914,28 +962,28 @@ macro_rules! implement_per_thing { // almost at the edge assert_eq!( - $name::from_rational_approximation(max_value - 1, max_value + 1), + $name::from_rational(max_value - 1, max_value + 1), $name::from_parts($max - 2), ); assert_eq!( - $name::from_rational_approximation(1, $max - 1), + $name::from_rational(1, $max - 1), $name::from_parts(1), ); assert_eq!( - $name::from_rational_approximation(1, $max), + $name::from_rational(1, $max), $name::from_parts(1), ); assert_eq!( - $name::from_rational_approximation(2, 2 * max_value - 1), + $name::from_rational(2, 2 * max_value - 1), $name::from_parts(1), ); assert_eq!( - $name::from_rational_approximation(1, max_value + 1), + $name::from_rational(1, max_value + 1), $name::zero(), ); assert_eq!( - $name::from_rational_approximation(3 * max_value / 2, 3 * max_value), - $name::from_fraction(0.5), + $name::from_rational(3 * max_value / 2, 3 * max_value), + $name::from_float(0.5), ); $(per_thing_from_rationale_approx_test!($test_units);)* @@ -943,66 +991,66 @@ macro_rules! implement_per_thing { #[test] fn per_things_mul_operates_in_output_type() { - // assert_eq!($name::from_fraction(0.5) * 100u32, 50u32); - assert_eq!($name::from_fraction(0.5) * 100u64, 50u64); - assert_eq!($name::from_fraction(0.5) * 100u128, 50u128); + // assert_eq!($name::from_float(0.5) * 100u32, 50u32); + assert_eq!($name::from_float(0.5) * 100u64, 50u64); + assert_eq!($name::from_float(0.5) * 100u128, 50u128); } #[test] fn per_thing_saturating_op_works() { assert_eq_error_rate!( - $name::from_fraction(0.5).saturating_add($name::from_fraction(0.4)).0 as $upper_type, - $name::from_fraction(0.9).0 as $upper_type, + $name::from_float(0.5).saturating_add($name::from_float(0.4)).0 as $upper_type, + $name::from_float(0.9).0 as $upper_type, 2, ); assert_eq_error_rate!( - $name::from_fraction(0.5).saturating_add($name::from_fraction(0.5)).0 as $upper_type, + $name::from_float(0.5).saturating_add($name::from_float(0.5)).0 as $upper_type, $name::one().0 as $upper_type, 2, ); assert_eq!( - $name::from_fraction(0.6).saturating_add($name::from_fraction(0.5)), + $name::from_float(0.6).saturating_add($name::from_float(0.5)), $name::one(), ); assert_eq_error_rate!( - $name::from_fraction(0.6).saturating_sub($name::from_fraction(0.5)).0 as $upper_type, - $name::from_fraction(0.1).0 as $upper_type, + $name::from_float(0.6).saturating_sub($name::from_float(0.5)).0 as $upper_type, + $name::from_float(0.1).0 as $upper_type, 2, ); assert_eq!( - $name::from_fraction(0.6).saturating_sub($name::from_fraction(0.6)), - $name::from_fraction(0.0), + $name::from_float(0.6).saturating_sub($name::from_float(0.6)), + $name::from_float(0.0), ); assert_eq!( - $name::from_fraction(0.6).saturating_sub($name::from_fraction(0.7)), - $name::from_fraction(0.0), + $name::from_float(0.6).saturating_sub($name::from_float(0.7)), + $name::from_float(0.0), ); assert_eq_error_rate!( - $name::from_fraction(0.5).saturating_mul($name::from_fraction(0.5)).0 as $upper_type, - $name::from_fraction(0.25).0 as $upper_type, + $name::from_float(0.5).saturating_mul($name::from_float(0.5)).0 as $upper_type, + $name::from_float(0.25).0 as $upper_type, 2, ); assert_eq_error_rate!( - $name::from_fraction(0.2).saturating_mul($name::from_fraction(0.2)).0 as $upper_type, - $name::from_fraction(0.04).0 as $upper_type, + $name::from_float(0.2).saturating_mul($name::from_float(0.2)).0 as $upper_type, + $name::from_float(0.04).0 as $upper_type, 2, ); assert_eq_error_rate!( - $name::from_fraction(0.1).saturating_mul($name::from_fraction(0.1)).0 as $upper_type, - $name::from_fraction(0.01).0 as $upper_type, + $name::from_float(0.1).saturating_mul($name::from_float(0.1)).0 as $upper_type, + $name::from_float(0.01).0 as $upper_type, 1, ); } #[test] fn per_thing_square_works() { - assert_eq!($name::from_fraction(1.0).square(), $name::from_fraction(1.0)); - assert_eq!($name::from_fraction(0.5).square(), $name::from_fraction(0.25)); - assert_eq!($name::from_fraction(0.1).square(), $name::from_fraction(0.01)); + assert_eq!($name::from_float(1.0).square(), $name::from_float(1.0)); + assert_eq!($name::from_float(0.5).square(), $name::from_float(0.25)); + assert_eq!($name::from_float(0.1).square(), $name::from_float(0.01)); assert_eq!( - $name::from_fraction(0.02).square(), + $name::from_float(0.02).square(), $name::from_parts((4 * <$upper_type>::from($max) / 100 / 100) as $type) ); } @@ -1011,30 +1059,30 @@ macro_rules! implement_per_thing { fn per_things_div_works() { // normal assert_eq_error_rate!( - ($name::from_fraction(0.1) / $name::from_fraction(0.20)).0 as $upper_type, - $name::from_fraction(0.50).0 as $upper_type, + ($name::from_float(0.1) / $name::from_float(0.20)).0 as $upper_type, + $name::from_float(0.50).0 as $upper_type, 2, ); assert_eq_error_rate!( - ($name::from_fraction(0.1) / $name::from_fraction(0.10)).0 as $upper_type, - $name::from_fraction(1.0).0 as $upper_type, + ($name::from_float(0.1) / $name::from_float(0.10)).0 as $upper_type, + $name::from_float(1.0).0 as $upper_type, 2, ); assert_eq_error_rate!( - ($name::from_fraction(0.1) / $name::from_fraction(0.0)).0 as $upper_type, - $name::from_fraction(1.0).0 as $upper_type, + ($name::from_float(0.1) / $name::from_float(0.0)).0 as $upper_type, + $name::from_float(1.0).0 as $upper_type, 2, ); // will not overflow assert_eq_error_rate!( - ($name::from_fraction(0.10) / $name::from_fraction(0.05)).0 as $upper_type, - $name::from_fraction(1.0).0 as $upper_type, + ($name::from_float(0.10) / $name::from_float(0.05)).0 as $upper_type, + $name::from_float(1.0).0 as $upper_type, 2, ); assert_eq_error_rate!( - ($name::from_fraction(1.0) / $name::from_fraction(0.5)).0 as $upper_type, - $name::from_fraction(1.0).0 as $upper_type, + ($name::from_float(1.0) / $name::from_float(0.5)).0 as $upper_type, + $name::from_float(1.0).0 as $upper_type, 2, ); } diff --git a/primitives/npos-elections/src/helpers.rs b/primitives/npos-elections/src/helpers.rs index 10a49a084f102..091efdd36ea5f 100644 --- a/primitives/npos-elections/src/helpers.rs +++ b/primitives/npos-elections/src/helpers.rs @@ -95,15 +95,15 @@ mod tests { Assignment { who: 1u32, distribution: vec![ - (10u32, Perbill::from_fraction(0.5)), - (20, Perbill::from_fraction(0.5)), + (10u32, Perbill::from_float(0.5)), + (20, Perbill::from_float(0.5)), ], }, Assignment { who: 2u32, distribution: vec![ - (10, Perbill::from_fraction(0.33)), - (20, Perbill::from_fraction(0.67)), + (10, Perbill::from_float(0.33)), + (20, Perbill::from_float(0.67)), ], }, ]; diff --git a/primitives/npos-elections/src/lib.rs b/primitives/npos-elections/src/lib.rs index 433c470d57d43..10ee12cc55085 100644 --- a/primitives/npos-elections/src/lib.rs +++ b/primitives/npos-elections/src/lib.rs @@ -371,7 +371,7 @@ impl Voter { .edges .into_iter() .filter_map(|e| { - let per_thing = P::from_rational_approximation(e.weight, budget); + let per_thing = P::from_rational(e.weight, budget); // trim zero edges. if per_thing.is_zero() { None } else { Some((e.who, per_thing)) } }).collect::>(); @@ -551,7 +551,7 @@ impl StakedAssignment { let distribution = self.distribution .into_iter() .filter_map(|(target, w)| { - let per_thing = P::from_rational_approximation(w, stake); + let per_thing = P::from_rational(w, stake); if per_thing == Bounded::min_value() { None } else { diff --git a/primitives/npos-elections/src/mock.rs b/primitives/npos-elections/src/mock.rs index ea8f3780e0e6a..14e4139c5d324 100644 --- a/primitives/npos-elections/src/mock.rs +++ b/primitives/npos-elections/src/mock.rs @@ -345,7 +345,7 @@ pub(crate) fn run_and_compare( for (candidate, per_thingy) in distribution { if let Some(float_assignment) = float_assignments.1.iter().find(|x| x.0 == candidate ) { assert_eq_error_rate!( - Output::from_fraction(float_assignment.1).deconstruct(), + Output::from_float(float_assignment.1).deconstruct(), per_thingy.deconstruct(), Output::Inner::one(), ); diff --git a/primitives/npos-elections/src/phragmms.rs b/primitives/npos-elections/src/phragmms.rs index ad93d2f18ef9a..644535d4c41c2 100644 --- a/primitives/npos-elections/src/phragmms.rs +++ b/primitives/npos-elections/src/phragmms.rs @@ -101,7 +101,7 @@ pub(crate) fn calculate_max_score( for edge in voter.edges.iter() { let edge_candidate = edge.candidate.borrow(); if edge_candidate.elected { - let edge_contribution: ExtendedBalance = P::from_rational_approximation( + let edge_contribution: ExtendedBalance = P::from_rational( edge.weight, edge_candidate.backed_stake, ).deconstruct().into(); diff --git a/primitives/npos-elections/src/pjr.rs b/primitives/npos-elections/src/pjr.rs index 6caed9059e875..290110b14e650 100644 --- a/primitives/npos-elections/src/pjr.rs +++ b/primitives/npos-elections/src/pjr.rs @@ -37,7 +37,6 @@ use crate::{ use sp_std::{rc::Rc, vec::Vec}; use sp_std::collections::btree_map::BTreeMap; use sp_arithmetic::{traits::Zero, Perbill}; - /// The type used as the threshold. /// /// Just some reading sugar; Must always be same as [`ExtendedBalance`]; @@ -364,7 +363,7 @@ fn slack(voter: &Voter, t: Threshold) -> Exte let candidate = edge.candidate.borrow(); if candidate.elected { let extra = - Perbill::one().min(Perbill::from_rational_approximation(t, candidate.backed_stake)) + Perbill::one().min(Perbill::from_rational(t, candidate.backed_stake)) * edge.weight; acc.saturating_add(extra) } else { diff --git a/primitives/npos-elections/src/tests.rs b/primitives/npos-elections/src/tests.rs index edfea038ebc50..7bd8565a072fd 100644 --- a/primitives/npos-elections/src/tests.rs +++ b/primitives/npos-elections/src/tests.rs @@ -1095,7 +1095,7 @@ mod score { is_score_better( claim.clone(), initial.clone(), - Perbill::from_rational_approximation(1u32, 10_000), + Perbill::from_rational(1u32, 10_000), ), true, ); @@ -1104,7 +1104,7 @@ mod score { is_score_better( claim.clone(), initial.clone(), - Perbill::from_rational_approximation(2u32, 10_000), + Perbill::from_rational(2u32, 10_000), ), true, ); @@ -1113,7 +1113,7 @@ mod score { is_score_better( claim.clone(), initial.clone(), - Perbill::from_rational_approximation(3u32, 10_000), + Perbill::from_rational(3u32, 10_000), ), true, ); @@ -1122,7 +1122,7 @@ mod score { is_score_better( claim.clone(), initial.clone(), - Perbill::from_rational_approximation(4u32, 10_000), + Perbill::from_rational(4u32, 10_000), ), true, ); @@ -1131,7 +1131,7 @@ mod score { is_score_better( claim.clone(), initial.clone(), - Perbill::from_rational_approximation(5u32, 10_000), + Perbill::from_rational(5u32, 10_000), ), false, );