From ca69a9b0220e633e0f18f4af869535b7d19e6ef4 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 19 Jan 2021 06:01:03 +0100 Subject: [PATCH 01/13] Allow 24 nominations per validator and publish count --- frame/staking/src/benchmarking.rs | 4 ++-- frame/staking/src/lib.rs | 7 +++++-- frame/staking/src/testing_utils.rs | 14 +++++++------- 3 files changed, 14 insertions(+), 11 deletions(-) diff --git a/frame/staking/src/benchmarking.rs b/frame/staking/src/benchmarking.rs index 6009761f365da..ffd93d340a898 100644 --- a/frame/staking/src/benchmarking.rs +++ b/frame/staking/src/benchmarking.rs @@ -506,10 +506,10 @@ benchmarks! { Some(w), )?; - // needed for the solution to be generates. + // needed for the solution to be generated. assert!(>::create_stakers_snapshot().0); - // set number of winners + // set number of winners. ValidatorCount::put(w); // create a assignments in total for the w winners. diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index c3aeaada421b9..d9764216e0c00 100644 --- a/frame/staking/src/lib.rs +++ b/frame/staking/src/lib.rs @@ -372,10 +372,10 @@ pub type EraIndex = u32; /// Counter for the number of "reward" points earned by a given validator. pub type RewardPoint = u32; -// Note: Maximum nomination limit is set here -- 16. +// Note: Maximum nomination limit is set here -- 24. generate_solution_type!( #[compact] - pub struct CompactAssignments::(16) + pub struct CompactAssignments::(24) ); /// Accuracy used for on-chain election. @@ -1266,6 +1266,9 @@ decl_module! { /// their reward. This used to limit the i/o cost for the nominator payout. const MaxNominatorRewardedPerValidator: u32 = T::MaxNominatorRewardedPerValidator::get(); + /// The maximum of validator candidates each nominator may nominate. + const MaxNominations: u32 = MAX_NOMINATIONS as u32; + type Error = Error; fn deposit_event() = default; diff --git a/frame/staking/src/testing_utils.rs b/frame/staking/src/testing_utils.rs index c8d8cb28e2b22..4832f51e0387e 100644 --- a/frame/staking/src/testing_utils.rs +++ b/frame/staking/src/testing_utils.rs @@ -107,18 +107,18 @@ pub fn create_validators( /// we are working with a clean state. /// /// Parameters: -/// - `validators`: number of bonded validators +/// - `validators`: number of bonded validators. /// - `nominators`: number of bonded nominators. -/// - `edge_per_nominator`: number of edge (vote) per nominator. +/// - `edges_per_nominator`: number of edges (votes) per nominator. /// - `randomize_stake`: whether to randomize the stakes. /// - `to_nominate`: if `Some(n)`, only the first `n` bonded validator are voted upon. -/// Else, all of them are considered and `edge_per_nominator` random validators are voted for. +/// Else, all of them are considered and `edges_per_nominator` random validators are voted for. /// -/// Return the validators choosen to be nominated. +/// Return the validators chosen to be nominated. pub fn create_validators_with_nominators_for_era( validators: u32, nominators: u32, - edge_per_nominator: usize, + edges_per_nominator: usize, randomize_stake: bool, to_nominate: Option, ) -> Result::Source>, &'static str> { @@ -155,9 +155,9 @@ pub fn create_validators_with_nominators_for_era( // Have them randomly validate let mut available_validators = validator_choosen.clone(); let mut selected_validators: Vec<::Source> = - Vec::with_capacity(edge_per_nominator); + Vec::with_capacity(edges_per_nominator); - for _ in 0 .. validators.min(edge_per_nominator as u32) { + for _ in 0 .. validators.min(edges_per_nominator as u32) { let selected = rng.next_u32() as usize % available_validators.len(); let validator = available_validators.remove(selected); selected_validators.push(validator); From 1d2a95f6376ffecd31669eee9c390c813ae42cb2 Mon Sep 17 00:00:00 2001 From: kianenigma Date: Tue, 19 Jan 2021 15:36:00 +0000 Subject: [PATCH 02/13] Fix test. --- frame/staking/src/benchmarking.rs | 12 ++++++++---- frame/staking/src/testing_utils.rs | 5 +++-- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/frame/staking/src/benchmarking.rs b/frame/staking/src/benchmarking.rs index ffd93d340a898..e91286c09496d 100644 --- a/frame/staking/src/benchmarking.rs +++ b/frame/staking/src/benchmarking.rs @@ -409,7 +409,7 @@ benchmarks! { let v in 1 .. 10; let n in 1 .. 100; - create_validators_with_nominators_for_era::(v, n, MAX_NOMINATIONS, false, None)?; + create_validators_with_nominators_for_era::(v, n, MAX_NOMINATIONS, false, 1000, None)?; let session_index = SessionIndex::one(); }: { let validators = Staking::::new_era(session_index).ok_or("`new_era` failed")?; @@ -420,7 +420,7 @@ benchmarks! { payout_all { let v in 1 .. 10; let n in 1 .. 100; - create_validators_with_nominators_for_era::(v, n, MAX_NOMINATIONS, false, None)?; + create_validators_with_nominators_for_era::(v, n, MAX_NOMINATIONS, false, 1000, None)?; // Start a new Era let new_validators = Staking::::new_era(SessionIndex::one()).unwrap(); assert!(new_validators.len() == v as usize); @@ -503,6 +503,7 @@ benchmarks! { n, MAX_NOMINATIONS, false, + 1000, Some(w), )?; @@ -574,6 +575,7 @@ benchmarks! { n, MAX_NOMINATIONS, false, + 1000, Some(w), )?; @@ -657,7 +659,7 @@ benchmarks! { // number of nominator intention. let n in 500 .. 1000; - create_validators_with_nominators_for_era::(v, n, MAX_NOMINATIONS, false, None)?; + create_validators_with_nominators_for_era::(v, n, MAX_NOMINATIONS, false, 1000, None)?; // needed for the solution to be generates. assert!(>::create_stakers_snapshot().0); @@ -720,7 +722,7 @@ mod tests { let v = 10; let n = 100; - create_validators_with_nominators_for_era::(v, n, MAX_NOMINATIONS, false, None) + create_validators_with_nominators_for_era::(v, n, MAX_NOMINATIONS, false, 1000, None) .unwrap(); let count_validators = Validators::::iter().count(); @@ -835,6 +837,8 @@ mod tests { assert_ok!(test_benchmark_payout_all::()); // only run one of them to same time on the CI. ignore the other two. assert_ok!(test_benchmark_submit_solution_initial::()); + assert_ok!(test_benchmark_submit_solution_better::()); + assert_ok!(test_benchmark_submit_solution_weaker::()); }); } diff --git a/frame/staking/src/testing_utils.rs b/frame/staking/src/testing_utils.rs index 4832f51e0387e..099b5576b63b3 100644 --- a/frame/staking/src/testing_utils.rs +++ b/frame/staking/src/testing_utils.rs @@ -120,6 +120,7 @@ pub fn create_validators_with_nominators_for_era( nominators: u32, edges_per_nominator: usize, randomize_stake: bool, + balance_factor: u32, to_nominate: Option, ) -> Result::Source>, &'static str> { clear_validators_and_nominators::(); @@ -130,7 +131,7 @@ pub fn create_validators_with_nominators_for_era( // Create validators for i in 0 .. validators { - let balance_factor = if randomize_stake { rng.next_u32() % 255 + 10 } else { 100u32 }; + let balance_factor = if randomize_stake { rng.next_u32() % 255 + balance_factor } else { balance_factor }; let (v_stash, v_controller) = create_stash_controller::(i, balance_factor, RewardDestination::Staked)?; let validator_prefs = ValidatorPrefs { commission: Perbill::from_percent(50), @@ -145,7 +146,7 @@ pub fn create_validators_with_nominators_for_era( // Create nominators for j in 0 .. nominators { - let balance_factor = if randomize_stake { rng.next_u32() % 255 + 10 } else { 100u32 }; + let balance_factor = if randomize_stake { rng.next_u32() % 255 + balance_factor } else { balance_factor }; let (_n_stash, n_controller) = create_stash_controller::( u32::max_value() - j, balance_factor, From 75d65d36e13b817d9aca02ff63fb48991dc8e7e7 Mon Sep 17 00:00:00 2001 From: kianenigma Date: Tue, 19 Jan 2021 19:24:12 +0000 Subject: [PATCH 03/13] Fix fuzzers. --- frame/staking/fuzzer/src/submit_solution.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/frame/staking/fuzzer/src/submit_solution.rs b/frame/staking/fuzzer/src/submit_solution.rs index d94ee49b96db4..11e13a64379d8 100644 --- a/frame/staking/fuzzer/src/submit_solution.rs +++ b/frame/staking/fuzzer/src/submit_solution.rs @@ -100,6 +100,7 @@ fn main() { num_nominators, edge_per_voter as usize, true, + 1000, None, )); From 09750779d09b6c883d41578a4a71b91a8824c5d5 Mon Sep 17 00:00:00 2001 From: kianenigma Date: Wed, 20 Jan 2021 06:52:40 +0000 Subject: [PATCH 04/13] Another fix. --- frame/staking/src/benchmarking.rs | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/frame/staking/src/benchmarking.rs b/frame/staking/src/benchmarking.rs index e91286c09496d..e1365b55dd91e 100644 --- a/frame/staking/src/benchmarking.rs +++ b/frame/staking/src/benchmarking.rs @@ -494,9 +494,9 @@ benchmarks! { // `compact.len()`. let a in 200 .. 400; // number of winners, also ValidatorCount. This will be equal to `winner.len()`. - let w in 16 .. 100; + let w in 24 .. 100; - ensure!(w as usize >= MAX_NOMINATIONS, "doesn't support lower value"); + assert!(w as usize >= MAX_NOMINATIONS, "doesn't support lower value"); let winners = create_validators_with_nominators_for_era::( v, @@ -557,7 +557,7 @@ benchmarks! { assert_eq!(>::queued_score().unwrap(), score); } - // same as submit_solution_initial but we place a very weak solution on chian first. + // same as submit_solution_initial but we place a very weak solution on chain first. submit_solution_better { // number of validator intention. let v in 200 .. 400; @@ -566,9 +566,9 @@ benchmarks! { // number of assignments. Basically, number of active nominators. let a in 200 .. 400; // number of winners, also ValidatorCount. - let w in 16 .. 100; + let w in 24 .. 100; - ensure!(w as usize >= MAX_NOMINATIONS, "doesn't support lower value"); + assert!(w as usize >= MAX_NOMINATIONS, "doesn't support lower value"); let winners = create_validators_with_nominators_for_era::( v, @@ -836,9 +836,7 @@ mod tests { assert_ok!(test_benchmark_do_slash::()); assert_ok!(test_benchmark_payout_all::()); // only run one of them to same time on the CI. ignore the other two. - assert_ok!(test_benchmark_submit_solution_initial::()); assert_ok!(test_benchmark_submit_solution_better::()); - assert_ok!(test_benchmark_submit_solution_weaker::()); }); } @@ -846,7 +844,7 @@ mod tests { #[ignore] fn test_benchmarks_offchain() { ExtBuilder::default().has_stakers(false).build().execute_with(|| { - assert_ok!(test_benchmark_submit_solution_better::()); + assert_ok!(test_benchmark_submit_solution_initial::()); assert_ok!(test_benchmark_submit_solution_weaker::()); }); } From 8409407703562a12bedab1a42471c61a5432ffda Mon Sep 17 00:00:00 2001 From: kianenigma Date: Thu, 21 Jan 2021 11:52:26 +0000 Subject: [PATCH 05/13] checkpoint --- frame/staking/src/lib.rs | 142 +++++++++++----------- frame/staking/src/offchain_election.rs | 94 ++++++-------- frame/staking/src/slashing.rs | 35 +++--- primitives/arithmetic/src/lib.rs | 8 +- primitives/arithmetic/src/per_things.rs | 39 +++--- primitives/npos-elections/src/lib.rs | 32 ++++- primitives/npos-elections/src/mock.rs | 5 +- primitives/npos-elections/src/phragmen.rs | 4 +- primitives/npos-elections/src/phragmms.rs | 6 +- 9 files changed, 190 insertions(+), 175 deletions(-) diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index d9764216e0c00..4730883649d0a 100644 --- a/frame/staking/src/lib.rs +++ b/frame/staking/src/lib.rs @@ -305,11 +305,11 @@ use frame_support::{ }; use pallet_session::historical; use sp_runtime::{ - Percent, Perbill, PerU16, InnerOf, RuntimeDebug, DispatchError, + Percent, Perbill, InnerOf, RuntimeDebug, DispatchError, PerThing, curve::PiecewiseLinear, traits::{ Convert, Zero, StaticLookup, CheckedSub, Saturating, SaturatedConversion, - AtLeast32BitUnsigned, Dispatchable, + AtLeast32BitUnsigned, Dispatchable, Bounded, }, transaction_validity::{ TransactionValidityError, TransactionValidity, ValidTransaction, InvalidTransaction, @@ -328,14 +328,13 @@ use frame_system::{ }; use sp_npos_elections::{ ExtendedBalance, Assignment, ElectionScore, ElectionResult as PrimitiveElectionResult, - to_support_map, EvaluateSupport, seq_phragmen, generate_solution_type, is_score_better, - SupportMap, VoteWeight, CompactSolution, PerThing128, + to_support_map, EvaluateSupport, seq_phragmen, is_score_better, CompactSolution, SupportMap, + VoteWeight, PerThing128, }; pub use weights::WeightInfo; const STAKING_ID: LockIdentifier = *b"staking "; pub const MAX_UNLOCKING_CHUNKS: usize = 32; -pub const MAX_NOMINATIONS: usize = ::LIMIT; pub(crate) const LOG_TARGET: &'static str = "staking"; @@ -350,21 +349,12 @@ macro_rules! log { }; } -/// Data type used to index nominators in the compact type -pub type NominatorIndex = u32; +pub type NominatorIndexOf = <::CompactSolution as CompactSolution>::Voter; +pub type ValidatorIndexOf = <::CompactSolution as CompactSolution>::Target; +pub type OffchainAccuracyOf = <::CompactSolution as CompactSolution>::Accuracy; -/// Data type used to index validators in the compact type. -pub type ValidatorIndex = u16; - -// Ensure the size of both ValidatorIndex and NominatorIndex. They both need to be well below usize. -static_assertions::const_assert!(size_of::() <= size_of::()); -static_assertions::const_assert!(size_of::() <= size_of::()); -static_assertions::const_assert!(size_of::() <= size_of::()); -static_assertions::const_assert!(size_of::() <= size_of::()); - -/// Maximum number of stakers that can be stored in a snapshot. -pub(crate) const MAX_VALIDATORS: usize = ValidatorIndex::max_value() as usize; -pub(crate) const MAX_NOMINATORS: usize = NominatorIndex::max_value() as usize; +/// Accuracy used for on-chain election. +pub type ChainAccuracy = Perbill; /// Counter for the number of eras that have passed. pub type EraIndex = u32; @@ -372,18 +362,6 @@ pub type EraIndex = u32; /// Counter for the number of "reward" points earned by a given validator. pub type RewardPoint = u32; -// Note: Maximum nomination limit is set here -- 24. -generate_solution_type!( - #[compact] - pub struct CompactAssignments::(24) -); - -/// Accuracy used for on-chain election. -pub type ChainAccuracy = Perbill; - -/// Accuracy used for off-chain election. This better be small. -pub type OffchainAccuracy = PerU16; - /// The balance type of this module. pub type BalanceOf = <::Currency as Currency<::AccountId>>::Balance; @@ -679,7 +657,7 @@ pub struct ElectionResult { /// Flat list of new exposures, to be updated in the [`Exposure`] storage. exposures: Vec<(AccountId, Exposure)>, /// Type of the result. This is kept on chain only to track and report the best score's - /// submission type. An optimisation could remove this. + /// submission type. An optimization could remove this. compute: ElectionCompute, } @@ -701,13 +679,12 @@ pub enum ElectionStatus { pub struct ElectionSize { /// Number of validators in the snapshot of the current election round. #[codec(compact)] - pub validators: ValidatorIndex, + pub validators: u32, /// Number of nominators in the snapshot of the current election round. #[codec(compact)] - pub nominators: NominatorIndex, + pub nominators: u32, } - impl ElectionStatus { pub fn is_open_at(&self, n: BlockNumber) -> bool { *self == Self::Open(n) @@ -757,6 +734,7 @@ impl SessionInterface<::AccountId> for T w T::SessionManager: pallet_session::SessionManager<::AccountId>, T::ValidatorIdOf: Convert<::AccountId, Option<::AccountId>>, + ExtendedBalance: From>> { fn disable_validator(validator: &::AccountId) -> Result { >::disable(validator) @@ -771,7 +749,10 @@ impl SessionInterface<::AccountId> for T w } } -pub trait Config: frame_system::Config + SendTransactionTypes> { +pub trait Config: frame_system::Config + SendTransactionTypes> +where + ExtendedBalance: From>> +{ /// The staking balance. type Currency: LockableCurrency; @@ -865,6 +846,11 @@ pub trait Config: frame_system::Config + SendTransactionTypes> { /// enough to fit in the block. type OffchainSolutionWeightLimit: Get; + /// The compact solution type used to accept offchain solution. + /// + /// This is implicitly encoding the maximum number of nominations as well. + type CompactSolution: CompactSolution + frame_support::Parameter; + /// Weight information for extrinsics in this pallet. type WeightInfo: WeightInfo; } @@ -905,7 +891,7 @@ impl Default for Releases { } decl_storage! { - trait Store for Module as Staking { + trait Store for Module as Staking where ExtendedBalance: From>> { /// Number of eras to keep in history. /// /// Information is kept for eras in `[current_era - history_depth; current_era]`. @@ -1157,7 +1143,7 @@ decl_event!( decl_error! { /// Error for the staking module. - pub enum Error for Module { + pub enum Error for Module where ExtendedBalance: From>> { /// Not a controller account. NotController, /// Not a stash account. @@ -1229,7 +1215,7 @@ decl_error! { } decl_module! { - pub struct Module for enum Call where origin: T::Origin { + pub struct Module for enum Call where origin: T::Origin, ExtendedBalance: From>> { /// Number of sessions per era. const SessionsPerEra: SessionIndex = T::SessionsPerEra::get(); @@ -1267,7 +1253,7 @@ decl_module! { const MaxNominatorRewardedPerValidator: u32 = T::MaxNominatorRewardedPerValidator::get(); /// The maximum of validator candidates each nominator may nominate. - const MaxNominations: u32 = MAX_NOMINATIONS as u32; + const MaxNominations: u32 = T::CompactSolution::LIMIT as u32; type Error = Error; @@ -1355,6 +1341,14 @@ decl_module! { } fn integrity_test() { + // Ensure the size of both ValidatorIndex and NominatorIndex. They both need to be well + // below usize. + assert!(size_of::>() <= size_of::()); + assert!(size_of::>() <= size_of::()); + assert!(size_of::>() <= size_of::()); + assert!(size_of::>() <= size_of::()); + + sp_io::TestExternalities::new_empty().execute_with(|| assert!( T::SlashDeferDuration::get() < T::BondingDuration::get() || T::BondingDuration::get() == 0, @@ -1369,17 +1363,17 @@ decl_module! { // will always return `Ok`. // 1. Maximum sum of Vec must fit into `UpperOf`. assert!( - >>::try_into(MAX_NOMINATIONS) + >>::try_into(T::CompactSolution::LIMIT) .unwrap() .checked_mul(::one().deconstruct().try_into().unwrap()) .is_some() ); - // 2. Maximum sum of Vec must fit into `UpperOf`. + // 2. Maximum sum of Vec> must fit into `UpperOf>`. assert!( - >>::try_into(MAX_NOMINATIONS) + >>>::try_into(T::CompactSolution::LIMIT) .unwrap() - .checked_mul(::one().deconstruct().try_into().unwrap()) + .checked_mul(>::one().deconstruct().try_into().unwrap()) .is_some() ); } @@ -1662,7 +1656,7 @@ decl_module! { /// /// # /// - The transaction's complexity is proportional to the size of `targets` (N) - /// which is capped at CompactAssignments::LIMIT (MAX_NOMINATIONS). + /// which is capped at (T::CompactSolution::LIMIT). /// - Both the reads and writes follow a similar pattern. /// --------- /// Weight: O(N) @@ -1679,7 +1673,7 @@ decl_module! { let stash = &ledger.stash; ensure!(!targets.is_empty(), Error::::EmptyTargets); let targets = targets.into_iter() - .take(MAX_NOMINATIONS) + .take(T::CompactSolution::LIMIT) .map(|t| T::Lookup::lookup(t)) .collect::, _>>()?; @@ -2077,8 +2071,8 @@ decl_module! { /// - The `score` that they claim their solution has. /// /// Both validators and nominators will be represented by indices in the solution. The - /// indices should respect the corresponding types ([`ValidatorIndex`] and - /// [`NominatorIndex`]). Moreover, they should be valid when used to index into + /// indices should respect the corresponding types ([`ValidatorIndexOf`] and + /// [`NominatorIndexOf`]). Moreover, they should be valid when used to index into /// [`SnapshotValidators`] and [`SnapshotNominators`]. Any invalid index will cause the /// solution to be rejected. These two storage items are set during the election window and /// may be used to determine the indices. @@ -2114,8 +2108,8 @@ decl_module! { )] pub fn submit_election_solution( origin, - winners: Vec, - compact: CompactAssignments, + winners: Vec>, + compact: T::CompactSolution, score: ElectionScore, era: EraIndex, size: ElectionSize, @@ -2148,8 +2142,8 @@ decl_module! { )] pub fn submit_election_solution_unsigned( origin, - winners: Vec, - compact: CompactAssignments, + winners: Vec>, + compact: T::CompactSolution, score: ElectionScore, era: EraIndex, size: ElectionSize, @@ -2174,7 +2168,7 @@ decl_module! { } } -impl Module { +impl Module where ExtendedBalance: From>> { /// The total balance that can be slashed from a stash account as of right now. pub fn slashable_balance_of(stash: &T::AccountId) -> BalanceOf { // Weight note: consider making the stake accessible through stash. @@ -2211,21 +2205,23 @@ impl Module { let validators = >::iter().map(|(v, _)| v).collect::>(); let mut nominators = >::iter().map(|(n, _)| n).collect::>(); + let max_validators: usize = >::max_value().saturated_into(); + let max_nominators: usize = >::max_value().saturated_into(); + let num_validators = validators.len(); let num_nominators = nominators.len(); add_db_reads_writes((num_validators + num_nominators) as Weight, 0); - if - num_validators > MAX_VALIDATORS || - num_nominators.saturating_add(num_validators) > MAX_NOMINATORS + if num_validators > max_validators + || num_nominators.saturating_add(num_validators) > max_nominators { log!( warn, "💸 Snapshot size too big [{} <> {}][{} <> {}].", num_validators, - MAX_VALIDATORS, + max_validators, num_nominators, - MAX_NOMINATORS, + max_nominators, ); (false, consumed_weight) } else { @@ -2463,8 +2459,8 @@ impl Module { /// Checks a given solution and if correct and improved, writes it on chain as the queued result /// of the next round. This may be called by both a signed and an unsigned transaction. pub fn check_and_replace_solution( - winners: Vec, - compact_assignments: CompactAssignments, + winners: Vec>, + compact_assignments: T::CompactSolution, compute: ElectionCompute, claimed_score: ElectionScore, era: EraIndex, @@ -2520,7 +2516,7 @@ impl Module { // NOTE: at the moment, since staking is explicitly blocking any offence until election // is closed, we don't check here if the account id at `snapshot_validators[widx]` is // actually a validator. If this ever changes, this loop needs to also check this. - snapshot_validators.get(widx as usize).cloned().ok_or(Error::::OffchainElectionBogusWinner) + snapshot_validators.get(widx.saturated_into()).cloned().ok_or(Error::::OffchainElectionBogusWinner) }).collect::, Error>>()?; // decode the rest of the snapshot. @@ -2528,11 +2524,11 @@ impl Module { .ok_or(Error::::SnapshotUnavailable)?; // helpers - let nominator_at = |i: NominatorIndex| -> Option { - snapshot_nominators.get(i as usize).cloned() + let nominator_at = |i: NominatorIndexOf| -> Option { + snapshot_nominators.get(i.saturated_into()).cloned() }; - let validator_at = |i: ValidatorIndex| -> Option { - snapshot_validators.get(i as usize).cloned() + let validator_at = |i: ValidatorIndexOf| -> Option { + snapshot_validators.get(i.saturated_into()).cloned() }; // un-compact. @@ -2592,7 +2588,7 @@ impl Module { // defensive only. A compact assignment of length one does NOT encode the weight and // it is always created to be 100%. ensure!( - distribution[0].1 == OffchainAccuracy::one(), + distribution[0].1 == >::one(), Error::::OffchainElectionBogusSelfVote, ); } @@ -3105,7 +3101,7 @@ impl Module { /// /// Once the first new_session is planned, all session must start and then end in order, though /// some session can lag in between the newest session planned and the latest session started. -impl pallet_session::SessionManager for Module { +impl pallet_session::SessionManager for Module where ExtendedBalance: From>> { fn new_session(new_index: SessionIndex) -> Option> { frame_support::debug::native::trace!( target: LOG_TARGET, @@ -3135,7 +3131,7 @@ impl pallet_session::SessionManager for Module { } } -impl historical::SessionManager>> for Module { +impl historical::SessionManager>> for Module where ExtendedBalance: From>> { fn new_session(new_index: SessionIndex) -> Option>)>> { @@ -3164,7 +3160,8 @@ impl historical::SessionManager pallet_authorship::EventHandler for Module where - T: Config + pallet_authorship::Config + pallet_session::Config + T: Config + pallet_authorship::Config + pallet_session::Config, + ExtendedBalance: From>> { fn note_author(author: T::AccountId) { Self::reward_by_ids(vec![(author, 20)]) @@ -3181,7 +3178,7 @@ impl pallet_authorship::EventHandler for Module /// if any. pub struct StashOf(sp_std::marker::PhantomData); -impl Convert> for StashOf { +impl Convert> for StashOf where ExtendedBalance: From>> { fn convert(controller: T::AccountId) -> Option { >::ledger(&controller).map(|l| l.stash) } @@ -3196,6 +3193,7 @@ pub struct ExposureOf(sp_std::marker::PhantomData); impl Convert>>> for ExposureOf + where ExtendedBalance: From>> { fn convert(validator: T::AccountId) -> Option>> { if let Some(active_era) = >::active_era() { @@ -3221,6 +3219,7 @@ for Module where ::AccountId, Option<::AccountId>, >, + ExtendedBalance: From>> { fn on_offence( offenders: &[OffenceDetails>], @@ -3353,6 +3352,7 @@ impl ReportOffence T: Config, R: ReportOffence, O: Offence, + ExtendedBalance: From>> { fn report_offence(reporters: Vec, offence: O) -> Result<(), OffenceError> { // disallow any slashing from before the current bonding period. @@ -3375,7 +3375,7 @@ impl ReportOffence } #[allow(deprecated)] -impl frame_support::unsigned::ValidateUnsigned for Module { +impl frame_support::unsigned::ValidateUnsigned for Module where ExtendedBalance: From>> { type Call = Call; fn validate_unsigned(source: TransactionSource, call: &Self::Call) -> TransactionValidity { if let Call::submit_election_solution_unsigned( diff --git a/frame/staking/src/offchain_election.rs b/frame/staking/src/offchain_election.rs index 5b1fe44d7e2ce..47688c7cd13f1 100644 --- a/frame/staking/src/offchain_election.rs +++ b/frame/staking/src/offchain_election.rs @@ -17,10 +17,7 @@ //! Helpers for offchain worker election. -use crate::{ - Call, CompactAssignments, ElectionSize, Module, NominatorIndex, Nominators, OffchainAccuracy, - Config, ValidatorIndex, WeightInfo, -}; +use crate::*; use codec::Decode; use frame_support::{traits::Get, weights::Weight, IterableStorageMap}; use frame_system::offchain::SubmitTransaction; @@ -73,7 +70,7 @@ pub(crate) const DEFAULT_LONGEVITY: u64 = 25; /// Returns `Ok(())` if offchain worker should happen, `Err(reason)` otherwise. pub(crate) fn set_check_offchain_execution_status( now: T::BlockNumber, -) -> Result<(), &'static str> { +) -> Result<(), &'static str> where ExtendedBalance: From>> { let storage = StorageValueRef::persistent(&OFFCHAIN_HEAD_DB); let threshold = T::BlockNumber::from(OFFCHAIN_REPEAT); @@ -108,14 +105,15 @@ pub(crate) fn set_check_offchain_execution_status( /// The internal logic of the offchain worker of this module. This runs the phragmen election, /// compacts and reduces the solution, computes the score and submits it back to the chain as an /// unsigned transaction, without any signature. -pub(crate) fn compute_offchain_election() -> Result<(), OffchainElectionError> { +pub(crate) fn compute_offchain_election() -> Result<(), OffchainElectionError> +where + ExtendedBalance: From>> +{ let iters = get_balancing_iters::(); - // compute raw solution. Note that we use `OffchainAccuracy`. - let ElectionResult { - winners, - assignments, - } = >::do_phragmen::(iters) - .ok_or(OffchainElectionError::ElectionFailed)?; + // compute raw solution. Note that we use `OffchainAccuracyOf`. + let ElectionResult { winners, assignments } = + >::do_phragmen::>(iters) + .ok_or(OffchainElectionError::ElectionFailed)?; // process and prepare it for submission. let (winners, compact, score, size) = prepare_submission::( @@ -151,7 +149,7 @@ pub(crate) fn compute_offchain_election() -> Result<(), OffchainElect /// Get a random number of iterations to run the balancing. /// /// Uses the offchain seed to generate a random number. -pub fn get_balancing_iters() -> usize { +pub fn get_balancing_iters() -> usize where ExtendedBalance: From>> { match T::MaxIterations::get() { 0 => 0, max @ _ => { @@ -182,12 +180,7 @@ pub fn maximum_compact_len( // helper closures. let weight_with = |voters: u32| -> Weight { - W::submit_solution_better( - size.validators.into(), - size.nominators.into(), - voters, - winners_len, - ) + W::submit_solution_better(size.validators, size.nominators, voters, winners_len) }; let next_voters = |current_weight: Weight, voters: u32, step: u32| -> Result { @@ -246,8 +239,8 @@ pub fn maximum_compact_len( /// /// The weight of the solution is foremost a function of the number of voters (i.e. /// `compact.len()`). Aside from this, the other components of the weight are invariant. The number -/// of winners shall not be changed (otherwise the solution is invalid) and the `ElectionSize` is -/// merely a representation of the total number of stakers. +/// of winners shall not be changed (otherwise the solution is invalid) and the `ElectionSize` +/// is merely a representation of the total number of stakers. /// /// Thus, we reside to stripping away some voters. This means only changing the `compact` struct. /// @@ -259,11 +252,12 @@ pub fn maximum_compact_len( /// then the solution will be discarded. pub fn trim_to_weight( maximum_allowed_voters: u32, - mut compact: CompactAssignments, + mut compact: T::CompactSolution, nominator_index: FN, -) -> Result +) -> Result where - for<'r> FN: Fn(&'r T::AccountId) -> Option, + for<'r> FN: Fn(&'r T::AccountId) -> Option>, + ExtendedBalance: From>> { match compact.voter_count().checked_sub(maximum_allowed_voters as usize) { Some(to_remove) if to_remove > 0 => { @@ -284,7 +278,7 @@ where if compact.remove_voter(index) { crate::log!( trace, - "💸 removed a voter at index {} with stake {:?} from compact to reduce the size", + "💸 removed a voter at index {:?} with stake {:?} from compact to reduce the size", index, _stake, ); @@ -319,16 +313,16 @@ where /// /// This does a lot of stuff; read the inline comments. pub fn prepare_submission( - assignments: Vec>, + assignments: Vec>>, winners: Vec<(T::AccountId, ExtendedBalance)>, do_reduce: bool, maximum_weight: Weight, ) -> Result< - (Vec, CompactAssignments, ElectionScore, ElectionSize), + (Vec>, T::CompactSolution, ElectionScore, ElectionSize), OffchainElectionError, > where - ExtendedBalance: From<::Inner>, + ExtendedBalance: From< as PerThing>::Inner>, { // make sure that the snapshot is available. let snapshot_validators = @@ -337,30 +331,30 @@ where >::snapshot_nominators().ok_or(OffchainElectionError::SnapshotUnavailable)?; // all helper closures that we'd ever need. - let nominator_index = |a: &T::AccountId| -> Option { + let nominator_index = |a: &T::AccountId| -> Option> { snapshot_nominators .iter() .position(|x| x == a) - .and_then(|i| >::try_into(i).ok()) + .and_then(|i| >>::try_into(i).ok()) }; - let validator_index = |a: &T::AccountId| -> Option { + let validator_index = |a: &T::AccountId| -> Option> { snapshot_validators .iter() .position(|x| x == a) - .and_then(|i| >::try_into(i).ok()) + .and_then(|i| >>::try_into(i).ok()) }; - let nominator_at = |i: NominatorIndex| -> Option { - snapshot_nominators.get(i as usize).cloned() + let nominator_at = |i: NominatorIndexOf| -> Option { + snapshot_nominators.get(i.saturated_into()).cloned() }; - let validator_at = |i: ValidatorIndex| -> Option { - snapshot_validators.get(i as usize).cloned() + let validator_at = |i: ValidatorIndexOf| -> Option { + snapshot_validators.get(i.saturated_into()).cloned() }; // both conversions are safe; snapshots are not created if they exceed. let size = ElectionSize { - validators: snapshot_validators.len() as ValidatorIndex, - nominators: snapshot_nominators.len() as NominatorIndex, + validators: snapshot_validators.len() as u32, + nominators: snapshot_nominators.len() as u32, }; // Clean winners. @@ -382,7 +376,7 @@ where .map_err(|e| OffchainElectionError::from(e))?; // compact encode the assignment. - let compact = CompactAssignments::from_assignment( + let compact = T::CompactSolution::from_assignment( low_accuracy_assignment, nominator_index, validator_index, @@ -424,12 +418,11 @@ where }; // winners to index. Use a simple for loop for a more expressive early exit in case of error. - let mut winners_indexed: Vec = Vec::with_capacity(winners.len()); + let mut winners_indexed: Vec> = Vec::with_capacity(winners.len()); for w in winners { if let Some(idx) = snapshot_validators.iter().position(|v| *v == w) { - let compact_index: ValidatorIndex = idx - .try_into() - .map_err(|_| OffchainElectionError::InvalidWinner)?; + let compact_index: ValidatorIndexOf = + idx.try_into().map_err(|_| OffchainElectionError::InvalidWinner)?; winners_indexed.push(compact_index); } else { return Err(OffchainElectionError::InvalidWinner); @@ -524,10 +517,7 @@ mod test { #[test] fn find_max_voter_binary_search_works() { - let size = ElectionSize { - validators: 0, - nominators: 10, - }; + let size = ElectionSize { validators: 0u16, nominators: 10u32 }; assert_eq!(maximum_compact_len::(0, size, 0), 0); assert_eq!(maximum_compact_len::(0, size, 1), 0); @@ -551,10 +541,7 @@ mod test { assert_eq!(maximum_compact_len::(0, size, 11_000), 10); assert_eq!(maximum_compact_len::(0, size, 22_000), 10); - let size = ElectionSize { - validators: 0, - nominators: 1, - }; + let size = ElectionSize { validators: 0u16, nominators: 1u32 }; assert_eq!(maximum_compact_len::(0, size, 0), 0); assert_eq!(maximum_compact_len::(0, size, 1), 0); @@ -568,10 +555,7 @@ mod test { assert_eq!(maximum_compact_len::(0, size, 2010), 1); assert_eq!(maximum_compact_len::(0, size, 3333), 1); - let size = ElectionSize { - validators: 0, - nominators: 2, - }; + let size = ElectionSize { validators: 0u16, nominators: 2u32 }; assert_eq!(maximum_compact_len::(0, size, 0), 0); assert_eq!(maximum_compact_len::(0, size, 1), 0); diff --git a/frame/staking/src/slashing.rs b/frame/staking/src/slashing.rs index 2b2ac61356c47..5a74a13549d5d 100644 --- a/frame/staking/src/slashing.rs +++ b/frame/staking/src/slashing.rs @@ -51,7 +51,7 @@ use super::{ EraIndex, Config, Module, Store, BalanceOf, Exposure, Perbill, SessionInterface, - NegativeImbalanceOf, UnappliedSlash, Error, + NegativeImbalanceOf, UnappliedSlash, Error, ExtendedBalance, OffchainAccuracyOf, }; use sp_runtime::{traits::{Zero, Saturating}, RuntimeDebug, DispatchResult}; use frame_support::{ @@ -190,7 +190,7 @@ impl SpanRecord { /// Parameters for performing a slash. #[derive(Clone)] -pub(crate) struct SlashParams<'a, T: 'a + Config> { +pub(crate) struct SlashParams<'a, T: 'a + Config> where ExtendedBalance: From>> { /// The stash account being slashed. pub(crate) stash: &'a T::AccountId, /// The proportion of the slash. @@ -215,7 +215,8 @@ pub(crate) struct SlashParams<'a, T: 'a + Config> { /// The pending slash record returned does not have initialized reporters. Those have /// to be set at a higher level, if any. pub(crate) fn compute_slash(params: SlashParams) - -> Option>> +-> Option>> +where ExtendedBalance: From>> { let SlashParams { stash, @@ -309,9 +310,9 @@ pub(crate) fn compute_slash(params: SlashParams) // doesn't apply any slash, but kicks out the validator if the misbehavior is from // the most recent slashing span. -fn kick_out_if_recent( - params: SlashParams, -) { +fn kick_out_if_recent(params: SlashParams) +where ExtendedBalance: From>> +{ // these are not updated by era-span or end-span. let mut reward_payout = Zero::zero(); let mut val_slashed = Zero::zero(); @@ -342,7 +343,9 @@ fn slash_nominators( params: SlashParams, prior_slash_p: Perbill, nominators_slashed: &mut Vec<(T::AccountId, BalanceOf)>, -) -> BalanceOf { +) -> BalanceOf + where ExtendedBalance: From>> +{ let SlashParams { stash: _, slash, @@ -418,7 +421,7 @@ fn slash_nominators( // dropping this struct applies any necessary slashes, which can lead to free balance // being 0, and the account being garbage-collected -- a dead account should get no new // metadata. -struct InspectingSpans<'a, T: Config + 'a> { +struct InspectingSpans<'a, T: Config + 'a> where ExtendedBalance: From>> { dirty: bool, window_start: EraIndex, stash: &'a T::AccountId, @@ -436,7 +439,7 @@ fn fetch_spans<'a, T: Config + 'a>( paid_out: &'a mut BalanceOf, slash_of: &'a mut BalanceOf, reward_proportion: Perbill, -) -> InspectingSpans<'a, T> { +) -> InspectingSpans<'a, T> where ExtendedBalance: From>> { let spans = as Store>::SlashingSpans::get(stash).unwrap_or_else(|| { let spans = SlashingSpans::new(window_start); as Store>::SlashingSpans::insert(stash, &spans); @@ -455,7 +458,7 @@ fn fetch_spans<'a, T: Config + 'a>( } } -impl<'a, T: 'a + Config> InspectingSpans<'a, T> { +impl<'a, T: 'a + Config> InspectingSpans<'a, T> where ExtendedBalance: From>> { fn span_index(&self) -> SpanIndex { self.spans.span_index } @@ -526,7 +529,7 @@ impl<'a, T: 'a + Config> InspectingSpans<'a, T> { } } -impl<'a, T: 'a + Config> Drop for InspectingSpans<'a, T> { +impl<'a, T: 'a + Config> Drop for InspectingSpans<'a, T> where ExtendedBalance: From>> { fn drop(&mut self) { // only update on disk if we slashed this account. if !self.dirty { return } @@ -542,7 +545,7 @@ impl<'a, T: 'a + Config> Drop for InspectingSpans<'a, T> { } /// Clear slashing metadata for an obsolete era. -pub(crate) fn clear_era_metadata(obsolete_era: EraIndex) { +pub(crate) fn clear_era_metadata(obsolete_era: EraIndex) where ExtendedBalance: From>> { as Store>::ValidatorSlashInEra::remove_prefix(&obsolete_era); as Store>::NominatorSlashInEra::remove_prefix(&obsolete_era); } @@ -551,7 +554,7 @@ pub(crate) fn clear_era_metadata(obsolete_era: EraIndex) { pub(crate) fn clear_stash_metadata( stash: &T::AccountId, num_slashing_spans: u32, -) -> DispatchResult { +) -> DispatchResult where ExtendedBalance: From>> { let spans = match as Store>::SlashingSpans::get(stash) { None => return Ok(()), Some(s) => s, @@ -581,7 +584,7 @@ pub fn do_slash( value: BalanceOf, reward_payout: &mut BalanceOf, slashed_imbalance: &mut NegativeImbalanceOf, -) { +) where ExtendedBalance: From>> { let controller = match >::bonded(stash) { None => return, // defensive: should always exist. Some(c) => c, @@ -613,7 +616,7 @@ pub fn do_slash( } /// Apply a previously-unapplied slash. -pub(crate) fn apply_slash(unapplied_slash: UnappliedSlash>) { +pub(crate) fn apply_slash(unapplied_slash: UnappliedSlash>) where ExtendedBalance: From>> { let mut slashed_imbalance = NegativeImbalanceOf::::zero(); let mut reward_payout = unapplied_slash.payout; @@ -642,7 +645,7 @@ fn pay_reporters( reward_payout: BalanceOf, slashed_imbalance: NegativeImbalanceOf, reporters: &[T::AccountId], -) { +) where ExtendedBalance: From>> { if reward_payout.is_zero() || reporters.is_empty() { // nobody to pay out to or nothing to pay; // just treat the whole value as slashed. diff --git a/primitives/arithmetic/src/lib.rs b/primitives/arithmetic/src/lib.rs index ca02df0d1d4bb..b59c8e7e96daa 100644 --- a/primitives/arithmetic/src/lib.rs +++ b/primitives/arithmetic/src/lib.rs @@ -114,17 +114,17 @@ impl_normalize_for_numeric!(u8, u16, u32, u64, u128); impl Normalizable

for Vec

{ fn normalize(&self, targeted_sum: P) -> Result, &'static str> { - let inners = self + let uppers = self .iter() - .map(|p| p.clone().deconstruct().into()) + .map(|p| >::from(p.clone().deconstruct())) .collect::>(); - let normalized = normalize(inners.as_ref(), targeted_sum.deconstruct().into())?; + let normalized = normalize(uppers.as_ref(), >::from(targeted_sum.deconstruct()))?; Ok( normalized .into_iter() - .map(|i: UpperOf

| P::from_parts(i.saturated_into())) + .map(|i: UpperOf

| P::from_parts(i.saturated_into::())) .collect() ) } diff --git a/primitives/arithmetic/src/per_things.rs b/primitives/arithmetic/src/per_things.rs index c6a31a0ffe869..30097b960cb5c 100644 --- a/primitives/arithmetic/src/per_things.rs +++ b/primitives/arithmetic/src/per_things.rs @@ -21,7 +21,7 @@ use serde::{Serialize, Deserialize}; use sp_std::{ops, fmt, prelude::*, convert::TryInto}; use codec::{Encode, CompactAs}; use crate::traits::{ - SaturatedConversion, UniqueSaturatedInto, Saturating, BaseArithmetic, Bounded, Zero, Unsigned, + SaturatedConversion, UniqueSaturatedInto, Saturating, BaseArithmetic, Bounded, Zero, Unsigned, One, }; use sp_debug_derive::RuntimeDebug; @@ -37,7 +37,7 @@ pub trait PerThing: Sized + Saturating + Copy + Default + Eq + PartialEq + Ord + PartialOrd + Bounded + fmt::Debug { /// The data type used to build this per-thingy. - type Inner: BaseArithmetic + Unsigned + Copy + fmt::Debug; + type Inner: BaseArithmetic + Unsigned + Copy + Into + fmt::Debug; /// A data type larger than `Self::Inner`, used to avoid overflow in some computations. /// It must be able to compute `ACCURACY^2`. @@ -65,14 +65,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_approximation::(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_approximation::(p * p, q * q) } /// Multiplication that always rounds down to a whole number. The standard `Mul` rounds to the @@ -205,8 +205,10 @@ pub trait PerThing: /// # } /// ``` fn from_rational_approximation(p: N, q: N) -> Self - where N: Clone + Ord + From + TryInto + TryInto + - ops::Div + ops::Rem + ops::Add + Unsigned; + where + N: Clone + Ord + TryInto + TryInto + + ops::Div + ops::Rem + ops::Add + Unsigned, + Self::Inner: Into; } /// The rounding method to use. @@ -231,14 +233,15 @@ where Output=N> + ops::Add + ops::Rem + Saturating + Unsigned, P: PerThing, { - let maximum: N = P::ACCURACY.into(); + let maximum = N::from(P::ACCURACY); let c = rational_mul_correction::( x.clone(), P::ACCURACY, part, rounding, ); - (x / part.into()).saturating_mul(maximum).saturating_add(c) + let part_n = N::from(part); + (x / part_n).saturating_mul(maximum).saturating_add(c) } /// Overflow-prune multiplication. Accurately multiply a value by `self` without overflowing. @@ -252,8 +255,8 @@ where Output=N> + ops::Add + ops::Rem + Unsigned, P: PerThing, { - let maximum: N = P::ACCURACY.into(); - let part_n: N = part.into(); + let maximum = N::from(P::ACCURACY); + let part_n = N::from(part); let c = rational_mul_correction::( x.clone(), part, @@ -304,7 +307,7 @@ where rem_mul_div_inner = rem_mul_div_inner + 1.into(); }, } - rem_mul_div_inner.into() + N::from(rem_mul_div_inner) } macro_rules! implement_per_thing { @@ -362,14 +365,15 @@ macro_rules! implement_per_thing { } fn from_rational_approximation(p: N, q: N) -> Self - where N: Clone + Ord + From + TryInto + TryInto - + ops::Div + ops::Rem + ops::Add + Unsigned + where N: Clone + Ord + TryInto + TryInto + + ops::Div + ops::Rem + ops::Add + Unsigned + Zero + One, + Self::Inner: Into, { let div_ceil = |x: N, f: N| -> N { let mut o = x.clone() / f.clone(); let r = x.rem(f.clone()); - if r > N::from(0) { - o = o + N::from(1); + if r > N::zero() { + o = o + N::one(); } o }; @@ -464,9 +468,10 @@ macro_rules! implement_per_thing { /// See [`PerThing::from_rational_approximation`]. pub fn from_rational_approximation(p: N, q: N) -> Self - where N: Clone + Ord + From<$type> + TryInto<$type> + + where N: Clone + Ord + TryInto<$type> + TryInto<$upper_type> + ops::Div + ops::Rem + - ops::Add + Unsigned + ops::Add + Unsigned, + $type: Into, { ::from_rational_approximation(p, q) } diff --git a/primitives/npos-elections/src/lib.rs b/primitives/npos-elections/src/lib.rs index 2f6e133f1dc79..61377a89ebae9 100644 --- a/primitives/npos-elections/src/lib.rs +++ b/primitives/npos-elections/src/lib.rs @@ -89,7 +89,7 @@ use sp_std::{ }; use sp_core::RuntimeDebug; -use codec::{Decode, Encode}; +use codec::{Decode, Encode, HasCompact}; #[cfg(feature = "std")] use serde::{Deserialize, Serialize}; @@ -139,10 +139,32 @@ pub trait CompactSolution: Sized { const LIMIT: usize; /// The voter type. Needs to be an index (convert to usize). - type Voter: UniqueSaturatedInto + TryInto + TryFrom + Debug + Copy + Clone; + type Voter: UniqueSaturatedInto + + TryInto + + TryFrom + + Debug + + Bounded + + Copy + + Clone + + PartialEq + + Eq + + HasCompact + + Encode + + Decode; /// The target type. Needs to be an index (convert to usize). - type Target: UniqueSaturatedInto + TryInto + TryFrom + Debug + Copy + Clone; + type Target: UniqueSaturatedInto + + TryInto + + TryFrom + + Debug + + Bounded + + Copy + + Clone + + PartialEq + + Eq + + HasCompact + + Encode + + Decode; /// The weight/accuracy type of each vote. type Accuracy: PerThing128; @@ -333,8 +355,8 @@ impl Voter { /// site might compensate by calling `normalize()` on the returned `Assignment` as a /// post-precessing. pub fn into_assignment(self) -> Option> - where - ExtendedBalance: From>, + // where + // ExtendedBalance: From>, { let who = self.who; let budget = self.budget; diff --git a/primitives/npos-elections/src/mock.rs b/primitives/npos-elections/src/mock.rs index 57b2204a72b48..0932dbd64d353 100644 --- a/primitives/npos-elections/src/mock.rs +++ b/primitives/npos-elections/src/mock.rs @@ -321,8 +321,9 @@ pub(crate) fn run_and_compare( voters: Vec<(AccountId, Vec)>, stake_of: &Box VoteWeight>, to_elect: usize, -) where - ExtendedBalance: From>, +) + // where + // ExtendedBalance: From>, { // run fixed point code. let ElectionResult { winners, assignments } = seq_phragmen::<_, Output>( diff --git a/primitives/npos-elections/src/phragmen.rs b/primitives/npos-elections/src/phragmen.rs index 24a6b81af31a7..3c27c7ed85489 100644 --- a/primitives/npos-elections/src/phragmen.rs +++ b/primitives/npos-elections/src/phragmen.rs @@ -69,8 +69,8 @@ pub fn seq_phragmen( initial_voters: Vec<(AccountId, VoteWeight, Vec)>, balance: Option<(usize, ExtendedBalance)>, ) -> Result, crate::Error> -where - ExtendedBalance: From>, +// where +// ExtendedBalance: From>, { let (candidates, voters) = setup_inputs(initial_candidates, initial_voters); diff --git a/primitives/npos-elections/src/phragmms.rs b/primitives/npos-elections/src/phragmms.rs index b37d3432f9d7e..f8cbd376f6fa0 100644 --- a/primitives/npos-elections/src/phragmms.rs +++ b/primitives/npos-elections/src/phragmms.rs @@ -47,8 +47,8 @@ pub fn phragmms( initial_voters: Vec<(AccountId, VoteWeight, Vec)>, balancing_config: Option<(usize, ExtendedBalance)>, ) -> Result, &'static str> -where - ExtendedBalance: From>, +// where +// ExtendedBalance: From>, { let (candidates, mut voters) = setup_inputs(initial_candidates, initial_voters); @@ -89,7 +89,7 @@ where pub(crate) fn calculate_max_score( candidates: &[CandidatePtr], voters: &[Voter], -) -> Option> where ExtendedBalance: From> { +) -> Option> /*where ExtendedBalance: From>*/ { for c_ptr in candidates.iter() { let mut candidate = c_ptr.borrow_mut(); if !candidate.elected { From c5b2836914584ca98825c6513407e61ed83f20ef Mon Sep 17 00:00:00 2001 From: kianenigma Date: Thu, 21 Jan 2021 11:50:57 +0000 Subject: [PATCH 06/13] checkpoint --- frame/elections-phragmen/src/lib.rs | 2 +- frame/staking/src/benchmarking.rs | 77 ++++++++++++++++--- frame/staking/src/lib.rs | 53 +++++++------ frame/staking/src/mock.rs | 33 ++++---- frame/staking/src/offchain_election.rs | 21 +++-- frame/staking/src/slashing.rs | 33 ++++---- frame/staking/src/testing_utils.rs | 57 +++++++------- frame/staking/src/tests.rs | 37 ++------- primitives/election-providers/src/onchain.rs | 5 +- primitives/npos-elections/benches/phragmen.rs | 5 +- primitives/npos-elections/compact/src/lib.rs | 7 ++ primitives/npos-elections/src/helpers.rs | 14 +--- primitives/npos-elections/src/lib.rs | 23 +++--- primitives/npos-elections/src/mock.rs | 5 +- primitives/npos-elections/src/phragmen.rs | 7 +- primitives/npos-elections/src/phragmms.rs | 9 +-- 16 files changed, 195 insertions(+), 193 deletions(-) diff --git a/frame/elections-phragmen/src/lib.rs b/frame/elections-phragmen/src/lib.rs index 5027840aef3c7..ac0051eda4dc6 100644 --- a/frame/elections-phragmen/src/lib.rs +++ b/frame/elections-phragmen/src/lib.rs @@ -1099,7 +1099,7 @@ mod tests { type OnNewAccount = (); type OnKilledAccount = (); type SystemWeightInfo = (); - type SS58Prefix = (); + type SS58Prefix = (); } parameter_types! { diff --git a/frame/staking/src/benchmarking.rs b/frame/staking/src/benchmarking.rs index e1365b55dd91e..f1602605a6bdc 100644 --- a/frame/staking/src/benchmarking.rs +++ b/frame/staking/src/benchmarking.rs @@ -198,9 +198,64 @@ benchmarks! { assert!(Validators::::contains_key(stash)); } - // Worst case scenario, MAX_NOMINATIONS + kick { + // scenario: we want to kick `k` nominators from nominating us (we are a validator). + // we'll assume that `k` is under 128 for the purposes of determining the slope. + // each nominator should have `T::CompactSolution::LIMIT` validators nominated, and our validator + // should be somewhere in there. + let k in 1 .. 128; + + // these are the other validators; there are `T::CompactSolution::LIMIT - 1` of them, so there are a + // total of `T::CompactSolution::LIMIT` validators in the system. + let rest_of_validators = create_validators::(T::CompactSolution::LIMIT as u32 - 1, 100)?; + + // this is the validator that will be kicking. + let (stash, controller) = create_stash_controller::(T::CompactSolution::LIMIT as u32 - 1, 100, Default::default())?; + let stash_lookup: ::Source = T::Lookup::unlookup(stash.clone()); + + // they start validating. + Staking::::validate(RawOrigin::Signed(controller.clone()).into(), Default::default())?; + + // we now create the nominators. there will be `k` of them; each will nominate all + // validators. we will then kick each of the `k` nominators from the main validator. + let mut nominator_stashes = Vec::with_capacity(k as usize); + for i in 0 .. k { + // create a nominator stash. + let (n_stash, n_controller) = create_stash_controller::(T::CompactSolution::LIMIT as u32 + i, 100, Default::default())?; + + // bake the nominations; we first clone them from the rest of the validators. + let mut nominations = rest_of_validators.clone(); + // then insert "our" validator somewhere in there (we vary it) to avoid accidental + // optimisations/pessimisations. + nominations.insert(i as usize % (nominations.len() + 1), stash_lookup.clone()); + // then we nominate. + Staking::::nominate(RawOrigin::Signed(n_controller.clone()).into(), nominations)?; + + nominator_stashes.push(n_stash); + } + + // all nominators now should be nominating our validator... + for n in nominator_stashes.iter() { + assert!(Nominators::::get(n).unwrap().targets.contains(&stash)); + } + + // we need the unlookuped version of the nominator stash for the kick. + let kicks = nominator_stashes.iter() + .map(|n| T::Lookup::unlookup(n.clone())) + .collect::>(); + + whitelist_account!(controller); + }: _(RawOrigin::Signed(controller), kicks) + verify { + // all nominators now should *not* be nominating our validator... + for n in nominator_stashes.iter() { + assert!(!Nominators::::get(n).unwrap().targets.contains(&stash)); + } + } + + // Worst case scenario, T::CompactSolution::LIMIT nominate { - let n in 1 .. MAX_NOMINATIONS as u32; + let n in 1 .. T::CompactSolution::LIMIT as u32; let (stash, controller) = create_stash_controller::(n + 1, 100, Default::default())?; let validators = create_validators::(n, 100)?; whitelist_account!(controller); @@ -409,7 +464,7 @@ benchmarks! { let v in 1 .. 10; let n in 1 .. 100; - create_validators_with_nominators_for_era::(v, n, MAX_NOMINATIONS, false, 1000, None)?; + create_validators_with_nominators_for_era::(v, n, T::CompactSolution::LIMIT, false, 1000, None)?; let session_index = SessionIndex::one(); }: { let validators = Staking::::new_era(session_index).ok_or("`new_era` failed")?; @@ -420,7 +475,7 @@ benchmarks! { payout_all { let v in 1 .. 10; let n in 1 .. 100; - create_validators_with_nominators_for_era::(v, n, MAX_NOMINATIONS, false, 1000, None)?; + create_validators_with_nominators_for_era::(v, n, T::CompactSolution::LIMIT, false, 1000, None)?; // Start a new Era let new_validators = Staking::::new_era(SessionIndex::one()).unwrap(); assert!(new_validators.len() == v as usize); @@ -496,12 +551,12 @@ benchmarks! { // number of winners, also ValidatorCount. This will be equal to `winner.len()`. let w in 24 .. 100; - assert!(w as usize >= MAX_NOMINATIONS, "doesn't support lower value"); + assert!(w as usize >= T::CompactSolution::LIMIT, "doesn't support lower value"); let winners = create_validators_with_nominators_for_era::( v, n, - MAX_NOMINATIONS, + T::CompactSolution::LIMIT, false, 1000, Some(w), @@ -568,12 +623,12 @@ benchmarks! { // number of winners, also ValidatorCount. let w in 24 .. 100; - assert!(w as usize >= MAX_NOMINATIONS, "doesn't support lower value"); + assert!(w as usize >= T::CompactSolution::LIMIT, "doesn't support lower value"); let winners = create_validators_with_nominators_for_era::( v, n, - MAX_NOMINATIONS, + T::CompactSolution::LIMIT, false, 1000, Some(w), @@ -659,7 +714,7 @@ benchmarks! { // number of nominator intention. let n in 500 .. 1000; - create_validators_with_nominators_for_era::(v, n, MAX_NOMINATIONS, false, 1000, None)?; + create_validators_with_nominators_for_era::(v, n, T::CompactSolution::LIMIT, false, 1000, None)?; // needed for the solution to be generates. assert!(>::create_stakers_snapshot().0); @@ -713,7 +768,7 @@ benchmarks! { #[cfg(test)] mod tests { use super::*; - use crate::mock::{ExtBuilder, Test, Balances, Staking, Origin}; + use crate::mock::{ExtBuilder, Test, Balances, Staking, Origin, TestSolution,}; use frame_support::assert_ok; #[test] @@ -722,7 +777,7 @@ mod tests { let v = 10; let n = 100; - create_validators_with_nominators_for_era::(v, n, MAX_NOMINATIONS, false, 1000, None) + create_validators_with_nominators_for_era::(v, n, T::CompactSolution::LIMIT, false, 1000, None) .unwrap(); let count_validators = Validators::::iter().count(); diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index 4730883649d0a..5dd75d1608917 100644 --- a/frame/staking/src/lib.rs +++ b/frame/staking/src/lib.rs @@ -349,8 +349,11 @@ macro_rules! log { }; } +/// The nominator index in the compact solution. pub type NominatorIndexOf = <::CompactSolution as CompactSolution>::Voter; +/// The validators index in the compact solution. pub type ValidatorIndexOf = <::CompactSolution as CompactSolution>::Target; +/// The offchain accuracy in the compact solution. pub type OffchainAccuracyOf = <::CompactSolution as CompactSolution>::Accuracy; /// Accuracy used for on-chain election. @@ -734,7 +737,6 @@ impl SessionInterface<::AccountId> for T w T::SessionManager: pallet_session::SessionManager<::AccountId>, T::ValidatorIdOf: Convert<::AccountId, Option<::AccountId>>, - ExtendedBalance: From>> { fn disable_validator(validator: &::AccountId) -> Result { >::disable(validator) @@ -749,10 +751,7 @@ impl SessionInterface<::AccountId> for T w } } -pub trait Config: frame_system::Config + SendTransactionTypes> -where - ExtendedBalance: From>> -{ +pub trait Config: frame_system::Config + SendTransactionTypes> { /// The staking balance. type Currency: LockableCurrency; @@ -849,7 +848,7 @@ where /// The compact solution type used to accept offchain solution. /// /// This is implicitly encoding the maximum number of nominations as well. - type CompactSolution: CompactSolution + frame_support::Parameter; + type CompactSolution: CompactSolution + frame_support::Parameter + Default; /// Weight information for extrinsics in this pallet. type WeightInfo: WeightInfo; @@ -891,7 +890,7 @@ impl Default for Releases { } decl_storage! { - trait Store for Module as Staking where ExtendedBalance: From>> { + trait Store for Module as Staking { /// Number of eras to keep in history. /// /// Information is kept for eras in `[current_era - history_depth; current_era]`. @@ -1143,7 +1142,7 @@ decl_event!( decl_error! { /// Error for the staking module. - pub enum Error for Module where ExtendedBalance: From>> { + pub enum Error for Module { /// Not a controller account. NotController, /// Not a stash account. @@ -1215,7 +1214,7 @@ decl_error! { } decl_module! { - pub struct Module for enum Call where origin: T::Origin, ExtendedBalance: From>> { + pub struct Module for enum Call where origin: T::Origin { /// Number of sessions per era. const SessionsPerEra: SessionIndex = T::SessionsPerEra::get(); @@ -1358,22 +1357,24 @@ decl_module! { ) ); - use sp_runtime::UpperOf; + use sp_runtime::{UpperOf, traits::CheckedMul}; // see the documentation of `Assignment::try_normalize`. Now we can ensure that this // will always return `Ok`. // 1. Maximum sum of Vec must fit into `UpperOf`. assert!( >>::try_into(T::CompactSolution::LIMIT) - .unwrap() + .unwrap_or_else(|_| panic!()) .checked_mul(::one().deconstruct().try_into().unwrap()) .is_some() ); // 2. Maximum sum of Vec> must fit into `UpperOf>`. + let max_inner = >::one().deconstruct(); + let max_inner = >>::from(max_inner); assert!( >>>::try_into(T::CompactSolution::LIMIT) - .unwrap() - .checked_mul(>::one().deconstruct().try_into().unwrap()) + .unwrap_or_else(|_| panic!()) + .checked_mul(&max_inner) .is_some() ); } @@ -1672,6 +1673,10 @@ decl_module! { let ledger = Self::ledger(&controller).ok_or(Error::::NotController)?; let stash = &ledger.stash; ensure!(!targets.is_empty(), Error::::EmptyTargets); + ensure!(targets.len() <= T::CompactSolution::LIMIT, Error::::TooManyTargets); + + let old = Nominators::::get(stash).map_or_else(Vec::new, |x| x.targets); + let targets = targets.into_iter() .take(T::CompactSolution::LIMIT) .map(|t| T::Lookup::lookup(t)) @@ -2168,7 +2173,7 @@ decl_module! { } } -impl Module where ExtendedBalance: From>> { +impl Module { /// The total balance that can be slashed from a stash account as of right now. pub fn slashable_balance_of(stash: &T::AccountId) -> BalanceOf { // Weight note: consider making the stake accessible through stash. @@ -2902,10 +2907,7 @@ impl Module where ExtendedBalance: From( iterations: usize, - ) -> Option> - where - ExtendedBalance: From>, - { + ) -> Option> { let weight_of = Self::slashable_balance_of_fn(); let mut all_nominators: Vec<(T::AccountId, VoteWeight, Vec)> = Vec::new(); let mut all_validators = Vec::new(); @@ -3101,7 +3103,7 @@ impl Module where ExtendedBalance: From pallet_session::SessionManager for Module where ExtendedBalance: From>> { +impl pallet_session::SessionManager for Module { fn new_session(new_index: SessionIndex) -> Option> { frame_support::debug::native::trace!( target: LOG_TARGET, @@ -3131,7 +3133,7 @@ impl pallet_session::SessionManager for Module where } } -impl historical::SessionManager>> for Module where ExtendedBalance: From>> { +impl historical::SessionManager>> for Module { fn new_session(new_index: SessionIndex) -> Option>)>> { @@ -3161,7 +3163,6 @@ impl historical::SessionManager pallet_authorship::EventHandler for Module where T: Config + pallet_authorship::Config + pallet_session::Config, - ExtendedBalance: From>> { fn note_author(author: T::AccountId) { Self::reward_by_ids(vec![(author, 20)]) @@ -3178,7 +3179,7 @@ impl pallet_authorship::EventHandler for Module /// if any. pub struct StashOf(sp_std::marker::PhantomData); -impl Convert> for StashOf where ExtendedBalance: From>> { +impl Convert> for StashOf { fn convert(controller: T::AccountId) -> Option { >::ledger(&controller).map(|l| l.stash) } @@ -3193,7 +3194,7 @@ pub struct ExposureOf(sp_std::marker::PhantomData); impl Convert>>> for ExposureOf - where ExtendedBalance: From>> + { fn convert(validator: T::AccountId) -> Option>> { if let Some(active_era) = >::active_era() { @@ -3218,8 +3219,7 @@ for Module where T::ValidatorIdOf: Convert< ::AccountId, Option<::AccountId>, - >, - ExtendedBalance: From>> + > { fn on_offence( offenders: &[OffenceDetails>], @@ -3352,7 +3352,6 @@ impl ReportOffence T: Config, R: ReportOffence, O: Offence, - ExtendedBalance: From>> { fn report_offence(reporters: Vec, offence: O) -> Result<(), OffenceError> { // disallow any slashing from before the current bonding period. @@ -3375,7 +3374,7 @@ impl ReportOffence } #[allow(deprecated)] -impl frame_support::unsigned::ValidateUnsigned for Module where ExtendedBalance: From>> { +impl frame_support::unsigned::ValidateUnsigned for Module { type Call = Call; fn validate_unsigned(source: TransactionSource, call: &Self::Call) -> TransactionValidity { if let Call::submit_election_solution_unsigned( diff --git a/frame/staking/src/mock.rs b/frame/staking/src/mock.rs index cf1486a9b691c..9e9146442215d 100644 --- a/frame/staking/src/mock.rs +++ b/frame/staking/src/mock.rs @@ -30,12 +30,16 @@ use sp_npos_elections::{ to_support_map, EvaluateSupport, reduce, ExtendedBalance, StakedAssignment, ElectionScore, }; use sp_runtime::{ + PerU16, curve::PiecewiseLinear, testing::{Header, TestXt, UintAuthorityId}, traits::{IdentityLookup, Zero}, }; use sp_staking::offence::{OffenceDetails, OnOffenceHandler}; use std::{cell::RefCell, collections::HashSet}; +use sp_npos_elections::generate_solution_type; + +generate_solution_type!(pub struct TestSolution::(24)); pub const INIT_TIMESTAMP: u64 = 30_000; pub const BLOCK_TIME: u64 = 1000; @@ -274,6 +278,7 @@ impl Config for Test { type MaxNominatorRewardedPerValidator = MaxNominatorRewardedPerValidator; type UnsignedPriority = UnsignedPriority; type OffchainSolutionWeightLimit = OffchainSolutionWeightLimit; + type CompactSolution = TestSolution; type WeightInfo = (); } @@ -791,7 +796,7 @@ pub(crate) fn add_slash(who: &AccountId) { // distributed evenly. pub(crate) fn horrible_npos_solution( do_reduce: bool, -) -> (CompactAssignments, Vec, ElectionScore) { +) -> (TestSolution, Vec>, ElectionScore) { let mut backing_stake_of: BTreeMap = BTreeMap::new(); // self stake @@ -878,19 +883,19 @@ pub(crate) fn horrible_npos_solution( let snapshot_validators = Staking::snapshot_validators().unwrap(); let snapshot_nominators = Staking::snapshot_nominators().unwrap(); - let nominator_index = |a: &AccountId| -> Option { - snapshot_nominators.iter().position(|x| x == a).map(|i| i as NominatorIndex) + let nominator_index = |a: &AccountId| -> Option> { + snapshot_nominators.iter().position(|x| x == a).map(|i| i as NominatorIndexOf) }; - let validator_index = |a: &AccountId| -> Option { - snapshot_validators.iter().position(|x| x == a).map(|i| i as ValidatorIndex) + let validator_index = |a: &AccountId| -> Option> { + snapshot_validators.iter().position(|x| x == a).map(|i| i as ValidatorIndexOf) }; // convert back to ratio assignment. This takes less space. let assignments_reduced = - sp_npos_elections::assignment_staked_to_ratio::(staked_assignment); + sp_npos_elections::assignment_staked_to_ratio::>(staked_assignment); let compact = - CompactAssignments::from_assignment(assignments_reduced, nominator_index, validator_index) + TestSolution::from_assignment(assignments_reduced, nominator_index, validator_index) .unwrap(); // winner ids to index @@ -909,12 +914,12 @@ pub(crate) fn prepare_submission_with( do_reduce: bool, iterations: usize, tweak: impl FnOnce(&mut Vec>), -) -> (CompactAssignments, Vec, ElectionScore) { +) -> (TestSolution, Vec>, ElectionScore) { // run election on the default stuff. let sp_npos_elections::ElectionResult { winners, assignments, - } = Staking::do_phragmen::(iterations).unwrap(); + } = Staking::do_phragmen::>(iterations).unwrap(); let winners = sp_npos_elections::to_without_backing(winners); let mut staked = sp_npos_elections::assignment_ratio_to_staked( @@ -932,22 +937,22 @@ pub(crate) fn prepare_submission_with( // convert back to ratio assignment. This takes less space. let snapshot_validators = Staking::snapshot_validators().expect("snapshot not created."); let snapshot_nominators = Staking::snapshot_nominators().expect("snapshot not created."); - let nominator_index = |a: &AccountId| -> Option { + let nominator_index = |a: &AccountId| -> Option> { snapshot_nominators .iter() .position(|x| x == a) .map_or_else( || { println!("unable to find nominator index for {:?}", a); None }, - |i| Some(i as NominatorIndex), + |i| Some(i as NominatorIndexOf), ) }; - let validator_index = |a: &AccountId| -> Option { + let validator_index = |a: &AccountId| -> Option> { snapshot_validators .iter() .position(|x| x == a) .map_or_else( || { println!("unable to find validator index for {:?}", a); None }, - |i| Some(i as ValidatorIndex), + |i| Some(i as ValidatorIndexOf), ) }; @@ -970,7 +975,7 @@ pub(crate) fn prepare_submission_with( }; let compact = - CompactAssignments::from_assignment(assignments_reduced, nominator_index, validator_index) + TestSolution::from_assignment(assignments_reduced, nominator_index, validator_index) .expect("Failed to create compact"); // winner ids to index diff --git a/frame/staking/src/offchain_election.rs b/frame/staking/src/offchain_election.rs index 47688c7cd13f1..119ffb7c7faa6 100644 --- a/frame/staking/src/offchain_election.rs +++ b/frame/staking/src/offchain_election.rs @@ -70,7 +70,7 @@ pub(crate) const DEFAULT_LONGEVITY: u64 = 25; /// Returns `Ok(())` if offchain worker should happen, `Err(reason)` otherwise. pub(crate) fn set_check_offchain_execution_status( now: T::BlockNumber, -) -> Result<(), &'static str> where ExtendedBalance: From>> { +) -> Result<(), &'static str> { let storage = StorageValueRef::persistent(&OFFCHAIN_HEAD_DB); let threshold = T::BlockNumber::from(OFFCHAIN_REPEAT); @@ -149,7 +149,7 @@ where /// Get a random number of iterations to run the balancing. /// /// Uses the offchain seed to generate a random number. -pub fn get_balancing_iters() -> usize where ExtendedBalance: From>> { +pub fn get_balancing_iters() -> usize { match T::MaxIterations::get() { 0 => 0, max @ _ => { @@ -256,8 +256,7 @@ pub fn trim_to_weight( nominator_index: FN, ) -> Result where - for<'r> FN: Fn(&'r T::AccountId) -> Option>, - ExtendedBalance: From>> + for<'r> FN: Fn(&'r T::AccountId) -> Option> { match compact.voter_count().checked_sub(maximum_allowed_voters as usize) { Some(to_remove) if to_remove > 0 => { @@ -318,11 +317,9 @@ pub fn prepare_submission( do_reduce: bool, maximum_weight: Weight, ) -> Result< - (Vec>, T::CompactSolution, ElectionScore, ElectionSize), - OffchainElectionError, -> -where - ExtendedBalance: From< as PerThing>::Inner>, + (Vec>, T::CompactSolution, ElectionScore, ElectionSize), + OffchainElectionError + > { // make sure that the snapshot is available. let snapshot_validators = @@ -517,7 +514,7 @@ mod test { #[test] fn find_max_voter_binary_search_works() { - let size = ElectionSize { validators: 0u16, nominators: 10u32 }; + let size = ElectionSize { validators: 0u32, nominators: 10u32 }; assert_eq!(maximum_compact_len::(0, size, 0), 0); assert_eq!(maximum_compact_len::(0, size, 1), 0); @@ -541,7 +538,7 @@ mod test { assert_eq!(maximum_compact_len::(0, size, 11_000), 10); assert_eq!(maximum_compact_len::(0, size, 22_000), 10); - let size = ElectionSize { validators: 0u16, nominators: 1u32 }; + let size = ElectionSize { validators: 0u32, nominators: 1u32 }; assert_eq!(maximum_compact_len::(0, size, 0), 0); assert_eq!(maximum_compact_len::(0, size, 1), 0); @@ -555,7 +552,7 @@ mod test { assert_eq!(maximum_compact_len::(0, size, 2010), 1); assert_eq!(maximum_compact_len::(0, size, 3333), 1); - let size = ElectionSize { validators: 0u16, nominators: 2u32 }; + let size = ElectionSize { validators: 0u32, nominators: 2u32 }; assert_eq!(maximum_compact_len::(0, size, 0), 0); assert_eq!(maximum_compact_len::(0, size, 1), 0); diff --git a/frame/staking/src/slashing.rs b/frame/staking/src/slashing.rs index 5a74a13549d5d..c6f9d2ca6f844 100644 --- a/frame/staking/src/slashing.rs +++ b/frame/staking/src/slashing.rs @@ -190,7 +190,7 @@ impl SpanRecord { /// Parameters for performing a slash. #[derive(Clone)] -pub(crate) struct SlashParams<'a, T: 'a + Config> where ExtendedBalance: From>> { +pub(crate) struct SlashParams<'a, T: 'a + Config> { /// The stash account being slashed. pub(crate) stash: &'a T::AccountId, /// The proportion of the slash. @@ -214,10 +214,7 @@ pub(crate) struct SlashParams<'a, T: 'a + Config> where ExtendedBalance: From(params: SlashParams) --> Option>> -where ExtendedBalance: From>> -{ +pub(crate) fn compute_slash(params: SlashParams) -> Option>> { let SlashParams { stash, slash, @@ -310,9 +307,7 @@ where ExtendedBalance: From>> // doesn't apply any slash, but kicks out the validator if the misbehavior is from // the most recent slashing span. -fn kick_out_if_recent(params: SlashParams) -where ExtendedBalance: From>> -{ +fn kick_out_if_recent(params: SlashParams) { // these are not updated by era-span or end-span. let mut reward_payout = Zero::zero(); let mut val_slashed = Zero::zero(); @@ -343,9 +338,7 @@ fn slash_nominators( params: SlashParams, prior_slash_p: Perbill, nominators_slashed: &mut Vec<(T::AccountId, BalanceOf)>, -) -> BalanceOf - where ExtendedBalance: From>> -{ +) -> BalanceOf { let SlashParams { stash: _, slash, @@ -421,7 +414,7 @@ fn slash_nominators( // dropping this struct applies any necessary slashes, which can lead to free balance // being 0, and the account being garbage-collected -- a dead account should get no new // metadata. -struct InspectingSpans<'a, T: Config + 'a> where ExtendedBalance: From>> { +struct InspectingSpans<'a, T: Config + 'a> { dirty: bool, window_start: EraIndex, stash: &'a T::AccountId, @@ -439,7 +432,7 @@ fn fetch_spans<'a, T: Config + 'a>( paid_out: &'a mut BalanceOf, slash_of: &'a mut BalanceOf, reward_proportion: Perbill, -) -> InspectingSpans<'a, T> where ExtendedBalance: From>> { +) -> InspectingSpans<'a, T> { let spans = as Store>::SlashingSpans::get(stash).unwrap_or_else(|| { let spans = SlashingSpans::new(window_start); as Store>::SlashingSpans::insert(stash, &spans); @@ -458,7 +451,7 @@ fn fetch_spans<'a, T: Config + 'a>( } } -impl<'a, T: 'a + Config> InspectingSpans<'a, T> where ExtendedBalance: From>> { +impl<'a, T: 'a + Config> InspectingSpans<'a, T> { fn span_index(&self) -> SpanIndex { self.spans.span_index } @@ -529,7 +522,7 @@ impl<'a, T: 'a + Config> InspectingSpans<'a, T> where ExtendedBalance: From Drop for InspectingSpans<'a, T> where ExtendedBalance: From>> { +impl<'a, T: 'a + Config> Drop for InspectingSpans<'a, T> { fn drop(&mut self) { // only update on disk if we slashed this account. if !self.dirty { return } @@ -545,7 +538,7 @@ impl<'a, T: 'a + Config> Drop for InspectingSpans<'a, T> where ExtendedBalance: } /// Clear slashing metadata for an obsolete era. -pub(crate) fn clear_era_metadata(obsolete_era: EraIndex) where ExtendedBalance: From>> { +pub(crate) fn clear_era_metadata(obsolete_era: EraIndex) { as Store>::ValidatorSlashInEra::remove_prefix(&obsolete_era); as Store>::NominatorSlashInEra::remove_prefix(&obsolete_era); } @@ -554,7 +547,7 @@ pub(crate) fn clear_era_metadata(obsolete_era: EraIndex) where Extend pub(crate) fn clear_stash_metadata( stash: &T::AccountId, num_slashing_spans: u32, -) -> DispatchResult where ExtendedBalance: From>> { +) -> DispatchResult { let spans = match as Store>::SlashingSpans::get(stash) { None => return Ok(()), Some(s) => s, @@ -584,7 +577,7 @@ pub fn do_slash( value: BalanceOf, reward_payout: &mut BalanceOf, slashed_imbalance: &mut NegativeImbalanceOf, -) where ExtendedBalance: From>> { +) { let controller = match >::bonded(stash) { None => return, // defensive: should always exist. Some(c) => c, @@ -616,7 +609,7 @@ pub fn do_slash( } /// Apply a previously-unapplied slash. -pub(crate) fn apply_slash(unapplied_slash: UnappliedSlash>) where ExtendedBalance: From>> { +pub(crate) fn apply_slash(unapplied_slash: UnappliedSlash>) { let mut slashed_imbalance = NegativeImbalanceOf::::zero(); let mut reward_payout = unapplied_slash.payout; @@ -645,7 +638,7 @@ fn pay_reporters( reward_payout: BalanceOf, slashed_imbalance: NegativeImbalanceOf, reporters: &[T::AccountId], -) where ExtendedBalance: From>> { +) { if reward_payout.is_zero() || reporters.is_empty() { // nobody to pay out to or nothing to pay; // just treat the whole value as slashed. diff --git a/frame/staking/src/testing_utils.rs b/frame/staking/src/testing_utils.rs index 099b5576b63b3..10bb3a6860a58 100644 --- a/frame/staking/src/testing_utils.rs +++ b/frame/staking/src/testing_utils.rs @@ -176,7 +176,7 @@ pub fn create_validators_with_nominators_for_era( /// which has a less score than the seq-phragmen. pub fn get_weak_solution( do_reduce: bool, -) -> (Vec, CompactAssignments, ElectionScore, ElectionSize) { +) -> (Vec>, T::CompactSolution, ElectionScore, ElectionSize) { let mut backing_stake_of: BTreeMap> = BTreeMap::new(); // self stake @@ -221,17 +221,17 @@ pub fn get_weak_solution( let snapshot_validators = >::snapshot_validators().unwrap(); let snapshot_nominators = >::snapshot_nominators().unwrap(); - let nominator_index = |a: &T::AccountId| -> Option { + let nominator_index = |a: &T::AccountId| -> Option> { snapshot_nominators .iter() .position(|x| x == a) - .and_then(|i| >::try_into(i).ok()) + .and_then(|i| >>::try_into(i).ok()) }; - let validator_index = |a: &T::AccountId| -> Option { + let validator_index = |a: &T::AccountId| -> Option> { snapshot_validators .iter() .position(|x| x == a) - .and_then(|i| >::try_into(i).ok()) + .and_then(|i| >>::try_into(i).ok()) }; // convert back to ratio assignment. This takes less space. @@ -240,7 +240,7 @@ pub fn get_weak_solution( // re-calculate score based on what the chain will decode. let score = { - let staked = assignment_ratio_to_staked::<_, OffchainAccuracy, _>( + let staked = assignment_ratio_to_staked::<_, OffchainAccuracyOf, _>( low_accuracy_assignment.clone(), >::slashable_balance_of_fn(), ); @@ -251,7 +251,7 @@ pub fn get_weak_solution( }; // compact encode the assignment. - let compact = CompactAssignments::from_assignment( + let compact = T::CompactSolution::from_assignment( low_accuracy_assignment, nominator_index, validator_index, @@ -267,13 +267,13 @@ pub fn get_weak_solution( .position(|v| *v == w) .unwrap() .try_into() - .unwrap() + .unwrap_or_else(|_| panic!()) }) - .collect::>(); + .collect::>>(); let size = ElectionSize { - validators: snapshot_validators.len() as ValidatorIndex, - nominators: snapshot_nominators.len() as NominatorIndex, + validators: snapshot_validators.len() as u32, + nominators: snapshot_nominators.len() as u32, }; (winners, compact, score, size) @@ -284,8 +284,8 @@ pub fn get_weak_solution( pub fn get_seq_phragmen_solution( do_reduce: bool, ) -> ( - Vec, - CompactAssignments, + Vec>, + T::CompactSolution, ElectionScore, ElectionSize, ) { @@ -294,7 +294,7 @@ pub fn get_seq_phragmen_solution( let sp_npos_elections::ElectionResult { winners, assignments, - } = >::do_phragmen::(iters).unwrap(); + } = >::do_phragmen::>(iters).unwrap(); offchain_election::prepare_submission::( assignments, @@ -310,8 +310,8 @@ pub fn get_single_winner_solution( winner: T::AccountId, ) -> Result< ( - Vec, - CompactAssignments, + Vec>, + T::CompactSolution, ElectionScore, ElectionSize, ), @@ -333,18 +333,17 @@ pub fn get_single_winner_solution( let stake = ::to_vote(stake, T::Currency::total_issuance()) as ExtendedBalance; - let val_index = val_index as ValidatorIndex; - let nom_index = nom_index as NominatorIndex; + let val_index: ValidatorIndexOf = val_index.try_into().unwrap_or_else(|_| { panic!("Failed to convert") }); + let nom_index: NominatorIndexOf = nom_index.try_into().unwrap_or_else(|_| { panic!("Failed to convert") }); + + let winners: Vec> = vec![val_index]; + let mut compact: T::CompactSolution = Default::default(); + compact.add_edge(nom_index, val_index); - let winners = vec![val_index]; - let compact = CompactAssignments { - votes1: vec![(nom_index, val_index)], - ..Default::default() - }; let score = [stake, stake, stake * stake]; let size = ElectionSize { - validators: snapshot_validators.len() as ValidatorIndex, - nominators: snapshot_nominators.len() as NominatorIndex, + validators: snapshot_validators.len() as u32, + nominators: snapshot_nominators.len() as u32, }; Ok((winners, compact, score, size)) @@ -364,19 +363,19 @@ pub fn init_active_era() { } /// Create random assignments for the given list of winners. Each assignment will have -/// MAX_NOMINATIONS edges. +/// T::CompactSolution::LIMIT edges. pub fn create_assignments_for_offchain( num_assignments: u32, winners: Vec<::Source>, ) -> Result< ( Vec<(T::AccountId, ExtendedBalance)>, - Vec>, + Vec>>, ), &'static str > { - let ratio = OffchainAccuracy::from_rational_approximation(1, MAX_NOMINATIONS); - let assignments: Vec> = >::iter() + let ratio = >::from_rational_approximation(1, T::CompactSolution::LIMIT.try_into().unwrap()); + let assignments: Vec>> = >::iter() .take(num_assignments as usize) .map(|(n, t)| Assignment { who: n, diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index 914aff9c45242..2450fa3411261 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -2900,8 +2900,8 @@ mod offchain_election { use std::sync::Arc; use substrate_test_utils::assert_eq_uvec; - fn percent(x: u16) -> OffchainAccuracy { - OffchainAccuracy::from_percent(x) + fn percent(x: u16) -> OffchainAccuracyOf { + >::from_percent(x) } /// setup a new set of validators and nominator storage items independent of the parent mock @@ -2943,15 +2943,15 @@ mod offchain_election { fn election_size() -> ElectionSize { ElectionSize { - validators: Staking::snapshot_validators().unwrap().len() as ValidatorIndex, - nominators: Staking::snapshot_nominators().unwrap().len() as NominatorIndex, + validators: Staking::snapshot_validators().unwrap().len() as u32, + nominators: Staking::snapshot_nominators().unwrap().len() as u32, } } fn submit_solution( origin: Origin, - winners: Vec, - compact: CompactAssignments, + winners: Vec>, + compact: TestSolution, score: ElectionScore, ) -> DispatchResultWithPostInfo { Staking::submit_election_solution( @@ -3169,31 +3169,6 @@ mod offchain_election { }) } - #[test] - #[ignore] - fn offchain_wont_work_if_snapshot_fails() { - ExtBuilder::default() - .offchain_election_ext() - .build() - .execute_with(|| { - run_to_block(12); - assert!(Staking::snapshot_validators().is_some()); - assert_eq!(Staking::era_election_status(), ElectionStatus::Open(12)); - - // validate more than the limit - let limit: NominatorIndex = ValidatorIndex::max_value() as NominatorIndex + 1; - let ctrl = 1_000_000; - for i in 0..limit { - bond_validator((1000 + i).into(), (1000 + i + ctrl).into(), 100); - } - - // window stays closed since no snapshot was taken. - run_to_block(27); - assert!(Staking::snapshot_validators().is_none()); - assert_eq!(Staking::era_election_status(), ElectionStatus::Closed); - }) - } - #[test] fn staking_is_locked_when_election_window_open() { ExtBuilder::default() diff --git a/primitives/election-providers/src/onchain.rs b/primitives/election-providers/src/onchain.rs index 496ba7fda47e9..4ea7617c3b25e 100644 --- a/primitives/election-providers/src/onchain.rs +++ b/primitives/election-providers/src/onchain.rs @@ -58,10 +58,7 @@ pub trait Config { type DataProvider: ElectionDataProvider; } -impl ElectionProvider for OnChainSequentialPhragmen -where - ExtendedBalance: From>, -{ +impl ElectionProvider for OnChainSequentialPhragmen { type Error = Error; type DataProvider = T::DataProvider; diff --git a/primitives/npos-elections/benches/phragmen.rs b/primitives/npos-elections/benches/phragmen.rs index 07d07658a46a1..721eddd01db8a 100644 --- a/primitives/npos-elections/benches/phragmen.rs +++ b/primitives/npos-elections/benches/phragmen.rs @@ -63,10 +63,7 @@ mod bench_closure_and_slice { ratio: Vec>, stakes: &[VoteWeight], ) -> Vec> - where - T: sp_std::ops::Mul, - ExtendedBalance: From<::Inner>, - { + where T: sp_std::ops::Mul { ratio .into_iter() .zip(stakes.into_iter().map(|x| *x as ExtendedBalance)) diff --git a/primitives/npos-elections/compact/src/lib.rs b/primitives/npos-elections/compact/src/lib.rs index 191998a341924..99a9db8ec1325 100644 --- a/primitives/npos-elections/compact/src/lib.rs +++ b/primitives/npos-elections/compact/src/lib.rs @@ -170,6 +170,8 @@ fn struct_def( let from_impl = assignment::from_impl(count); let into_impl = assignment::into_impl(count, weight_type.clone()); + let single_field_name = field_name_for(1); + Ok(quote! ( /// A struct to encode a election assignment in a compact way. #derives_and_maybe_compact_encoding @@ -248,6 +250,11 @@ fn struct_def( #into_impl Ok(assignments) } + + #[cfg(any(feature = "std", test))] + fn add_edge(&mut self, voter: Self::Voter, target: Self::Target) { + self.#single_field_name.push((voter, target)); + } } )) } diff --git a/primitives/npos-elections/src/helpers.rs b/primitives/npos-elections/src/helpers.rs index 4a2099947ea10..969401e531405 100644 --- a/primitives/npos-elections/src/helpers.rs +++ b/primitives/npos-elections/src/helpers.rs @@ -32,8 +32,7 @@ pub fn assignment_ratio_to_staked( stake_of: FS, ) -> Vec> where - for<'r> FS: Fn(&'r A) -> VoteWeight, - ExtendedBalance: From>, + for<'r> FS: Fn(&'r A) -> VoteWeight { ratios .into_iter() @@ -51,7 +50,6 @@ pub fn assignment_ratio_to_staked_normalized ) -> Result>, Error> where for<'r> FS: Fn(&'r A) -> VoteWeight, - ExtendedBalance: From>, { let mut staked = assignment_ratio_to_staked(ratio, &stake_of); staked @@ -68,20 +66,14 @@ where /// Note that this will NOT attempt at normalizing the result. pub fn assignment_staked_to_ratio( staked: Vec>, -) -> Vec> -where - ExtendedBalance: From>, -{ +) -> Vec> { staked.into_iter().map(|a| a.into_assignment()).collect() } /// Same as [`assignment_staked_to_ratio`] and try and do normalization. pub fn assignment_staked_to_ratio_normalized( staked: Vec>, -) -> Result>, Error> -where - ExtendedBalance: From>, -{ +) -> Result>, Error> { let mut ratio = staked.into_iter().map(|a| a.into_assignment()).collect::>(); ratio.iter_mut().map(|a| a.try_normalize().map_err(|err| Error::ArithmeticError(err)) diff --git a/primitives/npos-elections/src/lib.rs b/primitives/npos-elections/src/lib.rs index 61377a89ebae9..e2fc83850de1f 100644 --- a/primitives/npos-elections/src/lib.rs +++ b/primitives/npos-elections/src/lib.rs @@ -231,13 +231,18 @@ pub trait CompactSolution: Sized { where for<'r> FS: Fn(&'r A) -> VoteWeight, A: IdentifierT, - ExtendedBalance: From>, { let ratio = self.into_assignment(voter_at, target_at)?; let staked = helpers::assignment_ratio_to_staked_normalized(ratio, stake_of)?; let supports = to_supports(winners, &staked)?; Ok(supports.evaluate()) } + + /// Add a single edge 1-to-1 edge. + #[cfg(any(feature = "std", test))] + fn add_edge(&mut self, _voter: Self::Voter, _target: Self::Target) { + panic!("add_edge not implemented and cannot be used.") + } } // re-export the compact solution type. @@ -354,10 +359,7 @@ impl Voter { /// Note that this might create _un-normalized_ assignments, due to accuracy loss of `P`. Call /// site might compensate by calling `normalize()` on the returned `Assignment` as a /// post-precessing. - pub fn into_assignment(self) -> Option> - // where - // ExtendedBalance: From>, - { + pub fn into_assignment(self) -> Option> { let who = self.who; let budget = self.budget; let distribution = self.edges.into_iter().filter_map(|e| { @@ -527,11 +529,7 @@ impl StakedAssignment { /// /// If an edge stake is so small that it cannot be represented in `T`, it is ignored. This edge /// can never be re-created and does not mean anything useful anymore. - pub fn into_assignment(self) -> Assignment - where - ExtendedBalance: From>, - AccountId: IdentifierT, - { + pub fn into_assignment(self) -> Assignment where AccountId: IdentifierT { let stake = self.total(); let distribution = self.distribution .into_iter() @@ -728,10 +726,7 @@ where /// greater or less than `that`. /// /// Note that the third component should be minimized. -pub fn is_score_better(this: ElectionScore, that: ElectionScore, epsilon: P) -> bool -where - ExtendedBalance: From>, -{ +pub fn is_score_better(this: ElectionScore, that: ElectionScore, epsilon: P) -> bool { match this .iter() .zip(that.iter()) diff --git a/primitives/npos-elections/src/mock.rs b/primitives/npos-elections/src/mock.rs index 0932dbd64d353..46ec8902b2bd2 100644 --- a/primitives/npos-elections/src/mock.rs +++ b/primitives/npos-elections/src/mock.rs @@ -321,10 +321,7 @@ pub(crate) fn run_and_compare( voters: Vec<(AccountId, Vec)>, stake_of: &Box VoteWeight>, to_elect: usize, -) - // where - // ExtendedBalance: From>, -{ +) { // run fixed point code. let ElectionResult { winners, assignments } = seq_phragmen::<_, Output>( to_elect, diff --git a/primitives/npos-elections/src/phragmen.rs b/primitives/npos-elections/src/phragmen.rs index 3c27c7ed85489..dad65666738c7 100644 --- a/primitives/npos-elections/src/phragmen.rs +++ b/primitives/npos-elections/src/phragmen.rs @@ -27,7 +27,7 @@ use crate::{ use sp_arithmetic::{ helpers_128bit::multiply_by_rational, traits::{Bounded, Zero}, - InnerOf, Rational128, + Rational128, }; use sp_std::prelude::*; @@ -68,10 +68,7 @@ pub fn seq_phragmen( initial_candidates: Vec, initial_voters: Vec<(AccountId, VoteWeight, Vec)>, balance: Option<(usize, ExtendedBalance)>, -) -> Result, crate::Error> -// where -// ExtendedBalance: From>, -{ +) -> Result, crate::Error> { let (candidates, voters) = setup_inputs(initial_candidates, initial_voters); let (candidates, mut voters) = seq_phragmen_core::( diff --git a/primitives/npos-elections/src/phragmms.rs b/primitives/npos-elections/src/phragmms.rs index f8cbd376f6fa0..ad93d2f18ef9a 100644 --- a/primitives/npos-elections/src/phragmms.rs +++ b/primitives/npos-elections/src/phragmms.rs @@ -25,7 +25,7 @@ use crate::{ IdentifierT, ElectionResult, ExtendedBalance, setup_inputs, VoteWeight, Voter, CandidatePtr, balance, PerThing128, }; -use sp_arithmetic::{PerThing, InnerOf, Rational128, traits::Bounded}; +use sp_arithmetic::{PerThing, Rational128, traits::Bounded}; use sp_std::{prelude::*, rc::Rc}; /// Execute the phragmms method. @@ -46,10 +46,7 @@ pub fn phragmms( initial_candidates: Vec, initial_voters: Vec<(AccountId, VoteWeight, Vec)>, balancing_config: Option<(usize, ExtendedBalance)>, -) -> Result, &'static str> -// where -// ExtendedBalance: From>, -{ +) -> Result, &'static str> { let (candidates, mut voters) = setup_inputs(initial_candidates, initial_voters); let mut winners = vec![]; @@ -89,7 +86,7 @@ pub fn phragmms( pub(crate) fn calculate_max_score( candidates: &[CandidatePtr], voters: &[Voter], -) -> Option> /*where ExtendedBalance: From>*/ { +) -> Option> { for c_ptr in candidates.iter() { let mut candidate = c_ptr.borrow_mut(); if !candidate.elected { From 7d53b0714afe087aeaeedc3a96c9f1aae839ee6e Mon Sep 17 00:00:00 2001 From: kianenigma Date: Thu, 21 Jan 2021 15:15:17 +0000 Subject: [PATCH 07/13] Tidy it up. --- frame/staking/src/benchmarking.rs | 18 +++++++++++------- frame/staking/src/lib.rs | 18 +++++++++--------- frame/staking/src/mock.rs | 4 +--- frame/staking/src/offchain_election.rs | 12 +++++++----- frame/staking/src/slashing.rs | 8 ++++++-- frame/staking/src/testing_utils.rs | 11 ++++++++--- primitives/arithmetic/src/per_things.rs | 3 +-- 7 files changed, 43 insertions(+), 31 deletions(-) diff --git a/frame/staking/src/benchmarking.rs b/frame/staking/src/benchmarking.rs index 448b8bc111992..df4f0b87e3e18 100644 --- a/frame/staking/src/benchmarking.rs +++ b/frame/staking/src/benchmarking.rs @@ -200,18 +200,22 @@ benchmarks! { } kick { - // scenario: we want to kick `k` nominators from nominating us (we are a validator). - // we'll assume that `k` is under 128 for the purposes of determining the slope. - // each nominator should have `T::CompactSolution::LIMIT` validators nominated, and our validator - // should be somewhere in there. + // scenario: we want to kick `k` nominators from nominating us (we are a validator). we'll + // assume that `k` is under 128 for the purposes of determining the slope. each nominator + // should have `T::CompactSolution::LIMIT` validators nominated, and our validator should be + // somewhere in there. let k in 1 .. 128; - // these are the other validators; there are `T::CompactSolution::LIMIT - 1` of them, so there are a - // total of `T::CompactSolution::LIMIT` validators in the system. + // these are the other validators; there are `T::CompactSolution::LIMIT - 1` of them, so + // there are a total of `T::CompactSolution::LIMIT` validators in the system. let rest_of_validators = create_validators::(T::CompactSolution::LIMIT as u32 - 1, 100)?; // this is the validator that will be kicking. - let (stash, controller) = create_stash_controller::(T::CompactSolution::LIMIT as u32 - 1, 100, Default::default())?; + let (stash, controller) = create_stash_controller::( + T::CompactSolution::LIMIT as u32 - 1, + 100, + Default::default(), + )?; let stash_lookup: ::Source = T::Lookup::unlookup(stash.clone()); // they start validating. diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index 4b069c2c22a88..fa9c230c1903f 100644 --- a/frame/staking/src/lib.rs +++ b/frame/staking/src/lib.rs @@ -683,7 +683,7 @@ pub struct ElectionResult { /// Flat list of new exposures, to be updated in the [`Exposure`] storage. exposures: Vec<(AccountId, Exposure)>, /// Type of the result. This is kept on chain only to track and report the best score's - /// submission type. An optimization could remove this. + /// submission type. An optimisation could remove this. compute: ElectionCompute, } @@ -1430,7 +1430,8 @@ decl_module! { .is_some() ); - // 2. Maximum sum of Vec> must fit into `UpperOf>`. + // 2. Maximum sum of Vec> must fit into + // `UpperOf>`. let max_inner = >::one().deconstruct(); let max_inner = >>::from(max_inner); assert!( @@ -3205,7 +3206,7 @@ impl Module { /// /// Once the first new_session is planned, all session must start and then end in order, though /// some session can lag in between the newest session planned and the latest session started. -impl pallet_session::SessionManager for Module { +impl pallet_session::SessionManager for Module { fn new_session(new_index: SessionIndex) -> Option> { frame_support::debug::native::trace!( target: LOG_TARGET, @@ -3235,7 +3236,7 @@ impl pallet_session::SessionManager for Module { } } -impl historical::SessionManager>> for Module { +impl historical::SessionManager>> for Module { fn new_session(new_index: SessionIndex) -> Option>)>> { @@ -3264,7 +3265,7 @@ impl historical::SessionManager pallet_authorship::EventHandler for Module where - T: Config + pallet_authorship::Config + pallet_session::Config, + T: Config + pallet_authorship::Config + pallet_session::Config { fn note_author(author: T::AccountId) { Self::reward_by_ids(vec![(author, 20)]) @@ -3281,7 +3282,7 @@ impl pallet_authorship::EventHandler for Module /// if any. pub struct StashOf(sp_std::marker::PhantomData); -impl Convert> for StashOf { +impl Convert> for StashOf { fn convert(controller: T::AccountId) -> Option { >::ledger(&controller).map(|l| l.stash) } @@ -3296,7 +3297,6 @@ pub struct ExposureOf(sp_std::marker::PhantomData); impl Convert>>> for ExposureOf - { fn convert(validator: T::AccountId) -> Option>> { if let Some(active_era) = >::active_era() { @@ -3321,7 +3321,7 @@ for Module where T::ValidatorIdOf: Convert< ::AccountId, Option<::AccountId>, - > + >, { fn on_offence( offenders: &[OffenceDetails>], @@ -3476,7 +3476,7 @@ impl ReportOffence } #[allow(deprecated)] -impl frame_support::unsigned::ValidateUnsigned for Module { +impl frame_support::unsigned::ValidateUnsigned for Module { type Call = Call; fn validate_unsigned(source: TransactionSource, call: &Self::Call) -> TransactionValidity { if let Call::submit_election_solution_unsigned( diff --git a/frame/staking/src/mock.rs b/frame/staking/src/mock.rs index 9e9146442215d..7ace697e64b06 100644 --- a/frame/staking/src/mock.rs +++ b/frame/staking/src/mock.rs @@ -30,16 +30,14 @@ use sp_npos_elections::{ to_support_map, EvaluateSupport, reduce, ExtendedBalance, StakedAssignment, ElectionScore, }; use sp_runtime::{ - PerU16, curve::PiecewiseLinear, testing::{Header, TestXt, UintAuthorityId}, traits::{IdentityLookup, Zero}, }; use sp_staking::offence::{OffenceDetails, OnOffenceHandler}; use std::{cell::RefCell, collections::HashSet}; -use sp_npos_elections::generate_solution_type; -generate_solution_type!(pub struct TestSolution::(24)); +pub type TestSolution = crate::default_solution::CompactSolution24; pub const INIT_TIMESTAMP: u64 = 30_000; pub const BLOCK_TIME: u64 = 1000; diff --git a/frame/staking/src/offchain_election.rs b/frame/staking/src/offchain_election.rs index 2212dfe14d121..326238e801b5d 100644 --- a/frame/staking/src/offchain_election.rs +++ b/frame/staking/src/offchain_election.rs @@ -70,7 +70,7 @@ pub(crate) const DEFAULT_LONGEVITY: u64 = 25; /// Returns `Ok(())` if offchain worker should happen, `Err(reason)` otherwise. pub(crate) fn set_check_offchain_execution_status( now: T::BlockNumber, -) -> Result<(), &'static str> { +) -> Result<(), &'static str> { let storage = StorageValueRef::persistent(&OFFCHAIN_HEAD_DB); let threshold = T::BlockNumber::from(OFFCHAIN_REPEAT); @@ -108,9 +108,11 @@ pub(crate) fn set_check_offchain_execution_status( pub(crate) fn compute_offchain_election() -> Result<(), OffchainElectionError> { let iters = get_balancing_iters::(); // compute raw solution. Note that we use `OffchainAccuracyOf`. - let ElectionResult { winners, assignments } = - >::do_phragmen::>(iters) - .ok_or(OffchainElectionError::ElectionFailed)?; + let ElectionResult { + winners, + assignments, + } = >::do_phragmen::>(iters) + .ok_or(OffchainElectionError::ElectionFailed)?; // process and prepare it for submission. let (winners, compact, score, size) = prepare_submission::( @@ -253,7 +255,7 @@ pub fn trim_to_weight( nominator_index: FN, ) -> Result where - for<'r> FN: Fn(&'r T::AccountId) -> Option> + for<'r> FN: Fn(&'r T::AccountId) -> Option>, { match compact.voter_count().checked_sub(maximum_allowed_voters as usize) { Some(to_remove) if to_remove > 0 => { diff --git a/frame/staking/src/slashing.rs b/frame/staking/src/slashing.rs index 2737ea1a37df9..2b2ac61356c47 100644 --- a/frame/staking/src/slashing.rs +++ b/frame/staking/src/slashing.rs @@ -214,7 +214,9 @@ pub(crate) struct SlashParams<'a, T: 'a + Config> { /// /// The pending slash record returned does not have initialized reporters. Those have /// to be set at a higher level, if any. -pub(crate) fn compute_slash(params: SlashParams) -> Option>> { +pub(crate) fn compute_slash(params: SlashParams) + -> Option>> +{ let SlashParams { stash, slash, @@ -307,7 +309,9 @@ pub(crate) fn compute_slash(params: SlashParams) -> Option(params: SlashParams) { +fn kick_out_if_recent( + params: SlashParams, +) { // these are not updated by era-span or end-span. let mut reward_payout = Zero::zero(); let mut val_slashed = Zero::zero(); diff --git a/frame/staking/src/testing_utils.rs b/frame/staking/src/testing_utils.rs index 7433c2ee8ec41..8d229eae87644 100644 --- a/frame/staking/src/testing_utils.rs +++ b/frame/staking/src/testing_utils.rs @@ -335,8 +335,10 @@ pub fn get_single_winner_solution( let stake = ::to_vote(stake, T::Currency::total_issuance()) as ExtendedBalance; - let val_index: ValidatorIndexOf = val_index.try_into().unwrap_or_else(|_| { panic!("Failed to convert") }); - let nom_index: NominatorIndexOf = nom_index.try_into().unwrap_or_else(|_| { panic!("Failed to convert") }); + let val_index: ValidatorIndexOf = val_index.try_into() + .unwrap_or_else(|_| { panic!("Failed to convert") }); + let nom_index: NominatorIndexOf = nom_index.try_into() + .unwrap_or_else(|_| { panic!("Failed to convert") }); let winners: Vec> = vec![val_index]; let mut compact: T::CompactSolution = Default::default(); @@ -376,7 +378,10 @@ pub fn create_assignments_for_offchain( ), &'static str > { - let ratio = >::from_rational_approximation(1, T::CompactSolution::LIMIT.try_into().unwrap()); + let ratio = >::from_rational_approximation( + 1, + T::CompactSolution::LIMIT.try_into().unwrap(), + ); let assignments: Vec>> = >::iter() .take(num_assignments as usize) .map(|(n, t)| Assignment { diff --git a/primitives/arithmetic/src/per_things.rs b/primitives/arithmetic/src/per_things.rs index fb091cf8de627..5c86e55c2f4e8 100644 --- a/primitives/arithmetic/src/per_things.rs +++ b/primitives/arithmetic/src/per_things.rs @@ -252,8 +252,7 @@ where part, rounding, ); - let part_n: N = part.into(); - (x / part_n).saturating_mul(maximum).saturating_add(c) + (x / part.into()).saturating_mul(maximum).saturating_add(c) } /// Overflow-prune multiplication. Accurately multiply a value by `self` without overflowing. From a128b7ac0c3c8ed554cb32b8ce1049fcafb81105 Mon Sep 17 00:00:00 2001 From: kianenigma Date: Thu, 21 Jan 2021 18:11:06 +0000 Subject: [PATCH 08/13] remove cfg --- primitives/npos-elections/compact/src/lib.rs | 1 - primitives/npos-elections/src/lib.rs | 5 +---- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/primitives/npos-elections/compact/src/lib.rs b/primitives/npos-elections/compact/src/lib.rs index 99a9db8ec1325..e930439a65d53 100644 --- a/primitives/npos-elections/compact/src/lib.rs +++ b/primitives/npos-elections/compact/src/lib.rs @@ -251,7 +251,6 @@ fn struct_def( Ok(assignments) } - #[cfg(any(feature = "std", test))] fn add_edge(&mut self, voter: Self::Voter, target: Self::Target) { self.#single_field_name.push((voter, target)); } diff --git a/primitives/npos-elections/src/lib.rs b/primitives/npos-elections/src/lib.rs index 0abd47f4d7d83..f2a663471b1c0 100644 --- a/primitives/npos-elections/src/lib.rs +++ b/primitives/npos-elections/src/lib.rs @@ -239,10 +239,7 @@ pub trait CompactSolution: Sized { } /// Add a single edge 1-to-1 edge. - #[cfg(any(feature = "std", test))] - fn add_edge(&mut self, _voter: Self::Voter, _target: Self::Target) { - panic!("add_edge not implemented and cannot be used.") - } + fn add_edge(&mut self, _voter: Self::Voter, _target: Self::Target); } // re-export the compact solution type. From ca0e5adf7b827b5d31ed59464a0b86476d1d3b60 Mon Sep 17 00:00:00 2001 From: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Date: Tue, 9 Feb 2021 17:49:29 +0000 Subject: [PATCH 09/13] Update frame/staking/src/lib.rs Co-authored-by: Guillaume Thiolliere --- frame/staking/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index fa9c230c1903f..591ecf53a20b5 100644 --- a/frame/staking/src/lib.rs +++ b/frame/staking/src/lib.rs @@ -2276,7 +2276,7 @@ decl_module! { } } -impl Module { +impl Module { /// The total balance that can be slashed from a stash account as of right now. pub fn slashable_balance_of(stash: &T::AccountId) -> BalanceOf { // Weight note: consider making the stake accessible through stash. From 1eccbae85a015bf3372762a768444e90a322c999 Mon Sep 17 00:00:00 2001 From: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Date: Tue, 9 Feb 2021 17:49:47 +0000 Subject: [PATCH 10/13] Update frame/staking/src/lib.rs Co-authored-by: Guillaume Thiolliere --- frame/staking/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index 591ecf53a20b5..2fd1d88ba4daf 100644 --- a/frame/staking/src/lib.rs +++ b/frame/staking/src/lib.rs @@ -1402,8 +1402,8 @@ decl_module! { } fn integrity_test() { - // Ensure the size of both ValidatorIndex and NominatorIndex. They both need to be well - // below usize. + // Ensure the size of both ValidatorIndex and NominatorIndex. They both need to be less or + // equal to usize. assert!(size_of::>() <= size_of::()); assert!(size_of::>() <= size_of::()); assert!(size_of::>() <= size_of::()); From ec3ad0828df0470940dd22bb5be22243429cb8d0 Mon Sep 17 00:00:00 2001 From: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Date: Tue, 9 Feb 2021 17:50:03 +0000 Subject: [PATCH 11/13] Update frame/staking/src/lib.rs Co-authored-by: Guillaume Thiolliere --- frame/staking/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index 2fd1d88ba4daf..e66229508c44b 100644 --- a/frame/staking/src/lib.rs +++ b/frame/staking/src/lib.rs @@ -333,7 +333,7 @@ use sp_npos_elections::{ }; pub use weights::WeightInfo; -/// The default solution type used in substrate-node with 24 maximum winners. A runtime can customize this to their needs. +/// The default solution type used in substrate-node with 24 maximum votes per voter. A runtime can customize this to their needs. pub mod default_solution { use super::*; pub use sp_npos_elections::CompactSolution; From 57cdfe5b2648fb95a33128e0ef16bbdcbc0b3808 Mon Sep 17 00:00:00 2001 From: kianenigma Date: Wed, 10 Feb 2021 17:04:14 +0000 Subject: [PATCH 12/13] make the line width happy. --- frame/staking/src/benchmarking.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/frame/staking/src/benchmarking.rs b/frame/staking/src/benchmarking.rs index df4f0b87e3e18..b82b814208cb7 100644 --- a/frame/staking/src/benchmarking.rs +++ b/frame/staking/src/benchmarking.rs @@ -226,7 +226,8 @@ benchmarks! { let mut nominator_stashes = Vec::with_capacity(k as usize); for i in 0 .. k { // create a nominator stash. - let (n_stash, n_controller) = create_stash_controller::(T::CompactSolution::LIMIT as u32 + i, 100, Default::default())?; + let (n_stash, n_controller) = + create_stash_controller::(T::CompactSolution::LIMIT as u32 + i, 100, Default::default())?; // bake the nominations; we first clone them from the rest of the validators. let mut nominations = rest_of_validators.clone(); @@ -442,7 +443,11 @@ benchmarks! { CurrentEra::put(e); for i in 0 .. e { >::insert(i, T::AccountId::default(), Exposure::>::default()); - >::insert(i, T::AccountId::default(), Exposure::>::default()); + >::insert( + i, + T::AccountId::default(), + Exposure::>::default(), + ); >::insert(i, T::AccountId::default(), ValidatorPrefs::default()); >::insert(i, BalanceOf::::one()); >::insert(i, EraRewardPoints::::default()); From 32f2c7fe2696efc116af3d1083c565ce6edebba3 Mon Sep 17 00:00:00 2001 From: kianenigma Date: Wed, 10 Feb 2021 17:09:03 +0000 Subject: [PATCH 13/13] Line width, again. --- frame/staking/src/lib.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index e66229508c44b..9c58b704d9273 100644 --- a/frame/staking/src/lib.rs +++ b/frame/staking/src/lib.rs @@ -333,7 +333,8 @@ use sp_npos_elections::{ }; pub use weights::WeightInfo; -/// The default solution type used in substrate-node with 24 maximum votes per voter. A runtime can customize this to their needs. +/// The default solution type used in substrate-node with 24 maximum votes per voter. A runtime can +/// customize this to their needs. pub mod default_solution { use super::*; pub use sp_npos_elections::CompactSolution;