From 9cb610c3043c8b63002f6edc865cba4e5fb9262d Mon Sep 17 00:00:00 2001 From: Georges Dib Date: Mon, 20 Sep 2021 22:11:31 +0100 Subject: [PATCH 01/80] Updating broken website link --- frame/staking/README.md | 2 +- frame/staking/src/lib.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/frame/staking/README.md b/frame/staking/README.md index 072353b1a586c..b341640a65d29 100644 --- a/frame/staking/README.md +++ b/frame/staking/README.md @@ -176,7 +176,7 @@ Validators and nominators are rewarded at the end of each era. The total reward calculated using the era duration and the staking rate (the total amount of tokens staked by nominators and validators, divided by the total token supply). It aims to incentivize toward a defined staking rate. The full specification can be found -[here](https://research.web3.foundation/en/latest/polkadot/economics/1-token-economics.html#inflation-model). +[here](https://w3f-research.readthedocs.io/en/latest/polkadot/overview/2-token-economics.html#inflation-model). Total reward is split among validators and their nominators depending on the number of points they received during the era. Points are added to a validator using diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index 136515a5d6168..7879f6dea074e 100644 --- a/frame/staking/src/lib.rs +++ b/frame/staking/src/lib.rs @@ -201,7 +201,7 @@ //! calculated using the era duration and the staking rate (the total amount of tokens staked by //! nominators and validators, divided by the total token supply). It aims to incentivize toward a //! defined staking rate. The full specification can be found -//! [here](https://research.web3.foundation/en/latest/polkadot/Token%20Economics.html#inflation-model). +//! [here](https://w3f-research.readthedocs.io/en/latest/polkadot/overview/2-token-economics.html#inflation-model). //! //! Total reward is split among validators and their nominators depending on the number of points //! they received during the era. Points are added to a validator using From 5fba3bb464fae2d154e132d6ad2d317fd824320f Mon Sep 17 00:00:00 2001 From: Georges Dib Date: Mon, 20 Sep 2021 22:20:03 +0100 Subject: [PATCH 02/80] Updating rust example to FRAME 2.0 syntax --- frame/staking/README.md | 33 +++++++++++++++++++++------------ frame/staking/src/lib.rs | 33 +++++++++++++++++++++------------ 2 files changed, 42 insertions(+), 24 deletions(-) diff --git a/frame/staking/README.md b/frame/staking/README.md index b341640a65d29..02cbe0cac86c2 100644 --- a/frame/staking/README.md +++ b/frame/staking/README.md @@ -133,22 +133,31 @@ The Staking module contains many public storage items and (im)mutable functions. ### Example: Rewarding a validator by id. ```rust -use frame_support::{decl_module, dispatch}; +use frame_support::pallet_prelude::*; use frame_system::ensure_signed; use pallet_staking::{self as staking}; -pub trait Config: staking::Config {} - -decl_module! { - pub struct Module for enum Call where origin: T::Origin { - /// Reward a validator. - #[weight = 0] - pub fn reward_myself(origin) -> dispatch::DispatchResult { - let reported = ensure_signed(origin)?; - >::reward_by_ids(vec![(reported, 10)]); - Ok(()) - } +#[frame_support::pallet] +pub mod pallet { + use super::*; + + #[pallet::pallet] + #[pallet::generate_store(pub(crate) trait Store)] + pub struct Pallet(_); + + #[pallet::config] + pub trait Config: staking::Config {} + + #[pallet::call] + impl Pallet { + /// Reward a validator. + #[weight = 0] + pub fn reward_myself(origin) -> dispatch::DispatchResult { + let reported = ensure_signed(origin)?; + >::reward_by_ids(vec![(reported, 10)]); + Ok(()) } + } } ``` diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index 7879f6dea074e..ef3a8af79bd19 100644 --- a/frame/staking/src/lib.rs +++ b/frame/staking/src/lib.rs @@ -157,22 +157,31 @@ //! ### Example: Rewarding a validator by id. //! //! ``` -//! use frame_support::{decl_module, dispatch}; +//! use frame_support::pallet_prelude::*; //! use frame_system::ensure_signed; //! use pallet_staking::{self as staking}; //! -//! pub trait Config: staking::Config {} -//! -//! decl_module! { -//! pub struct Module for enum Call where origin: T::Origin { -//! /// Reward a validator. -//! #[weight = 0] -//! pub fn reward_myself(origin) -> dispatch::DispatchResult { -//! let reported = ensure_signed(origin)?; -//! >::reward_by_ids(vec![(reported, 10)]); -//! Ok(()) -//! } +//! #[frame_support::pallet] +//! pub mod pallet { +//! use super::*; +//! +//! #[pallet::pallet] +//! #[pallet::generate_store(pub(crate) trait Store)] +//! pub struct Pallet(_); +//! +//! #[pallet::config] +//! pub trait Config: staking::Config {} +//! +//! #[pallet::call] +//! impl Pallet { +//! /// Reward a validator. +//! #[weight = 0] +//! pub fn reward_myself(origin) -> dispatch::DispatchResult { +//! let reported = ensure_signed(origin)?; +//! >::reward_by_ids(vec![(reported, 10)]); +//! Ok(()) //! } +//! } //! } //! # fn main() { } //! ``` From 6d4691010c9cb6bed6b4311d150403e593b2a221 Mon Sep 17 00:00:00 2001 From: Georges Dib Date: Mon, 20 Sep 2021 23:16:19 +0100 Subject: [PATCH 03/80] Start of the implementation of adding storage_info to pallet staking. Moved MAX_UNLOCKING_CHUNKS from being a constant to being a type called `MaxUnlockingChunks` --- frame/staking/src/lib.rs | 70 +++++++++++++++++++-------- frame/staking/src/pallet/impls.rs | 7 ++- frame/staking/src/pallet/mod.rs | 80 ++++++++++++++++++++++++------- 3 files changed, 118 insertions(+), 39 deletions(-) diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index ef3a8af79bd19..88059f0ea8d91 100644 --- a/frame/staking/src/lib.rs +++ b/frame/staking/src/lib.rs @@ -299,10 +299,11 @@ pub mod weights; mod pallet; -use codec::{Decode, Encode, HasCompact}; +use codec::{Decode, Encode, HasCompact, MaxEncodedLen}; use frame_support::{ traits::{Currency, Get}, weights::Weight, + BoundedVec, WeakBoundedVec, }; use scale_info::TypeInfo; use sp_runtime::{ @@ -314,7 +315,11 @@ use sp_staking::{ offence::{Offence, OffenceError, ReportOffence}, SessionIndex, }; -use sp_std::{collections::btree_map::BTreeMap, convert::From, prelude::*}; +use sp_std::{ + collections::btree_map::BTreeMap, + convert::{From, TryFrom}, + prelude::*, +}; pub use weights::WeightInfo; pub use pallet::{pallet::*, *}; @@ -436,9 +441,19 @@ pub struct UnlockChunk { } /// The ledger of a (bonded) stash. +/// `UnlockingLimit` is the size limit of the `WeakBoundedVec` representing `unlocking` +/// `RewardsLimit` is the size limit of the `WeakBoundedVec` representing `claimed_rewards` #[cfg_attr(feature = "runtime-benchmarks", derive(Default))] -#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, TypeInfo)] -pub struct StakingLedger { +#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, TypeInfo, MaxEncodedLen)] +#[codec(mel_bound(UnlockingLimit: Get, RewardsLimit: Get))] +pub struct StakingLedger +where + Balance: HasCompact, + UnlockingLimit: Get, + RewardsLimit: Get, + AccountId: MaxEncodedLen, + Balance: MaxEncodedLen, +{ /// The stash account whose balance is actually locked and at stake. pub stash: AccountId, /// The total amount of the stash's balance that we are currently accounting for. @@ -451,31 +466,39 @@ pub struct StakingLedger { pub active: Balance, /// Any balance that is becoming free, which may eventually be transferred out /// of the stash (assuming it doesn't get slashed first). - pub unlocking: Vec>, + pub unlocking: BoundedVec, UnlockingLimit>, /// List of eras for which the stakers behind a validator have claimed rewards. Only updated /// for validators. - pub claimed_rewards: Vec, + pub claimed_rewards: WeakBoundedVec, } -impl - StakingLedger +impl + StakingLedger +where + Balance: HasCompact + Copy + Saturating + AtLeast32BitUnsigned, + UnlockingLimit: Get, + RewardsLimit: Get, + AccountId: MaxEncodedLen, + Balance: MaxEncodedLen, { /// Remove entries from `unlocking` that are sufficiently old and reduce the /// total by the sum of their balances. fn consolidate_unlocked(self, current_era: EraIndex) -> Self { let mut total = self.total; - let unlocking = self - .unlocking - .into_iter() - .filter(|chunk| { - if chunk.era > current_era { - true - } else { - total = total.saturating_sub(chunk.value); - false - } - }) - .collect(); + let unlocking = BoundedVec::<_, UnlockingLimit>::try_from( + self.unlocking + .into_iter() + .filter(|chunk| { + if chunk.era > current_era { + true + } else { + total = total.saturating_sub(chunk.value); + false + } + }) + .collect::>>(), + ) + .expect("unlocking vector only reduced in size here."); Self { stash: self.stash, @@ -512,9 +535,14 @@ impl } } -impl StakingLedger +impl + StakingLedger where Balance: AtLeast32BitUnsigned + Saturating + Copy, + UnlockingLimit: Get, + RewardsLimit: Get, + AccountId: MaxEncodedLen, + Balance: MaxEncodedLen, { /// Slash the validator for a given amount of balance. This can grow the value /// of the slash in the case that the validator has less than `minimum_balance` diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index 3ae520872f278..3e5551a5057dc 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -203,7 +203,12 @@ impl Pallet { /// This will also update the stash lock. pub(crate) fn update_ledger( controller: &T::AccountId, - ledger: &StakingLedger>, + ledger: &StakingLedger< + T::AccountId, + BalanceOf, + T::MaxUnlockingChunks, + T::MaxErasForRewards, + >, ) { T::Currency::set_lock(STAKING_ID, &ledger.stash, ledger.total, WithdrawReasons::all()); >::insert(controller, ledger); diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index c71130a3492b1..0eb886e7c34e1 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -25,6 +25,7 @@ use frame_support::{ LockableCurrency, OnUnbalanced, UnixTime, }, weights::Weight, + BoundedVec, WeakBoundedVec, }; use frame_system::{ensure_root, ensure_signed, offchain::SendTransactionTypes, pallet_prelude::*}; use sp_runtime::{ @@ -32,7 +33,11 @@ use sp_runtime::{ DispatchError, Perbill, Percent, }; use sp_staking::SessionIndex; -use sp_std::{convert::From, prelude::*, result}; +use sp_std::{ + convert::{From, TryFrom}, + prelude::*, + result, +}; mod impls; @@ -45,7 +50,6 @@ use crate::{ ValidatorPrefs, }; -pub const MAX_UNLOCKING_CHUNKS: usize = 32; const STAKING_ID: LockIdentifier = *b"staking "; #[frame_support::pallet] @@ -54,6 +58,7 @@ pub mod pallet { #[pallet::pallet] #[pallet::generate_store(pub(crate) trait Store)] + #[pallet::generate_storage_info] pub struct Pallet(_); #[pallet::config] @@ -141,6 +146,23 @@ pub mod pallet { #[pallet::constant] type MaxNominatorRewardedPerValidator: Get; + /// The maximum number of unapplied slashes to be stored in `UnappliedSlashes` + #[pallet::constant] + type MaxUnappliedSlashes: Get; + + /// The maximum number of invulnerables, we expect no more than four invulnerables and + /// restricted to testnets. + #[pallet::constant] + type MaxNbOfInvulnerables: Get; + + /// Maximum number of unlocking chunks + #[pallet::constant] + type MaxUnlockingChunks: Get; + + /// Maximum number of eras for which the stakers behind a validator have claimed rewards. + #[pallet::constant] + type MaxErasForRewards: Get; + /// Something that can provide a sorted list of voters in a somewhat sorted way. The /// original use case for this was designed with [`pallet_bags_list::Pallet`] in mind. If /// the bags-list is not desired, [`impls::UseNominatorsMap`] is likely the desired option. @@ -185,12 +207,13 @@ pub mod pallet { #[pallet::getter(fn minimum_validator_count)] pub type MinimumValidatorCount = StorageValue<_, u32, ValueQuery>; - /// Any validators that may never be slashed or forcibly kicked. It's a Vec since they're - /// easy to initialize and the performance hit is minimal (we expect no more than four - /// invulnerables) and restricted to testnets. + /// Any validators that may never be slashed or forcibly kicked. It's a `BoundedVec` + /// since they're easy to initialize and are bounded in size, and the performance hit + /// is minimal (we expect no more than four invulnerables) and restricted to testnets. #[pallet::storage] #[pallet::getter(fn invulnerables)] - pub type Invulnerables = StorageValue<_, Vec, ValueQuery>; + pub type Invulnerables = + StorageValue<_, BoundedVec, ValueQuery>; /// Map from all locked "stash" accounts to the controller account. #[pallet::storage] @@ -208,8 +231,12 @@ pub mod pallet { /// Map from all (unlocked) "controller" accounts to the info regarding the staking. #[pallet::storage] #[pallet::getter(fn ledger)] - pub type Ledger = - StorageMap<_, Blake2_128Concat, T::AccountId, StakingLedger>>; + pub type Ledger = StorageMap< + _, + Blake2_128Concat, + T::AccountId, + StakingLedger, T::MaxUnlockingChunks, T::MaxErasForRewards>, + >; /// Where the reward payment should be made. Keyed by stash. #[pallet::storage] @@ -381,7 +408,7 @@ pub mod pallet { _, Twox64Concat, EraIndex, - Vec>>, + WeakBoundedVec>, T::MaxUnappliedSlashes>, ValueQuery, >; @@ -489,7 +516,6 @@ pub mod pallet { HistoryDepth::::put(self.history_depth); ValidatorCount::::put(self.validator_count); MinimumValidatorCount::::put(self.minimum_validator_count); - Invulnerables::::put(&self.invulnerables); ForceEra::::put(self.force_era); CanceledSlashPayout::::put(self.canceled_payout); SlashRewardFraction::::put(self.slash_reward_fraction); @@ -497,6 +523,12 @@ pub mod pallet { MinNominatorBond::::put(self.min_nominator_bond); MinValidatorBond::::put(self.min_validator_bond); + let invulnerables = BoundedVec::<_, T::MaxNbOfInvulnerables>::try_from( + self.invulnerables, + ) + .expect("Too many invulnerables passed, a runtime parameters adjustment may be needed"); + Invulnerables::::put(&invulnerables); + for &(ref stash, ref controller, balance, ref status) in &self.stakers { log!( trace, @@ -625,6 +657,8 @@ pub mod pallet { /// There are too many validators in the system. Governance needs to adjust the staking /// settings to keep things safe for the runtime. TooManyValidators, + /// Too many invulnerables are passed, a runtime configuration adjustment may be needed + TooManyInvulnerables, } #[pallet::hooks] @@ -736,12 +770,20 @@ pub mod pallet { let stash_balance = T::Currency::free_balance(&stash); let value = value.min(stash_balance); Self::deposit_event(Event::::Bonded(stash.clone(), value)); + + let claimed_rewards = WeakBoundedVec::<_, T::MaxErasForRewards>::force_from( + (last_reward_era..current_era).collect(), + Some( + "Warning: The size of the claimed rewards is bigger than expected. \ + A runtime configuration adjustment may be needed.", + ), + ); let item = StakingLedger { stash, total: value, active: value, - unlocking: vec![], - claimed_rewards: (last_reward_era..current_era).collect(), + unlocking: BoundedVec::<_, T::MaxUnlockingChunks>::default(), + claimed_rewards, }; Self::update_ledger(&controller, &item); Ok(()) @@ -805,7 +847,7 @@ pub mod pallet { /// Once the unlock period is done, you can call `withdraw_unbonded` to actually move /// the funds out of management ready for transfer. /// - /// No more than a limited number of unlocking chunks (see `MAX_UNLOCKING_CHUNKS`) + /// No more than a limited number of unlocking chunks (see `MaxUnlockingChunks`) /// can co-exists at the same time. In that case, [`Call::withdraw_unbonded`] need /// to be called first to remove some of the chunks (if possible). /// @@ -822,7 +864,6 @@ pub mod pallet { ) -> DispatchResult { let controller = ensure_signed(origin)?; let mut ledger = Self::ledger(&controller).ok_or(Error::::NotController)?; - ensure!(ledger.unlocking.len() < MAX_UNLOCKING_CHUNKS, Error::::NoMoreChunks,); let mut value = value.min(ledger.active); @@ -849,7 +890,10 @@ pub mod pallet { // Note: in case there is no current era it is fine to bond one era more. let era = Self::current_era().unwrap_or(0) + T::BondingDuration::get(); - ledger.unlocking.push(UnlockChunk { value, era }); + ledger + .unlocking + .try_push(UnlockChunk { value, era }) + .map_err(|_| Error::::NoMoreChunks); // NOTE: ledger must be updated prior to calling `Self::weight_of`. Self::update_ledger(&controller, &ledger); @@ -1208,6 +1252,8 @@ pub mod pallet { invulnerables: Vec, ) -> DispatchResult { ensure_root(origin)?; + let invulnerables = BoundedVec::<_, T::MaxNbOfInvulnerables>::try_from(invulnerables) + .map_err(|_| Error::::TooManyInvulnerables)?; >::put(invulnerables); Ok(()) } @@ -1335,10 +1381,10 @@ pub mod pallet { /// /// # /// - Time complexity: O(L), where L is unlocking chunks - /// - Bounded by `MAX_UNLOCKING_CHUNKS`. + /// - Bounded by `MaxUnlockingChunks`. /// - Storage changes: Can't increase storage, only decrease it. /// # - #[pallet::weight(T::WeightInfo::rebond(MAX_UNLOCKING_CHUNKS as u32))] + #[pallet::weight(T::WeightInfo::rebond(T::MaxUnlockingChunks::get()))] pub fn rebond( origin: OriginFor, #[pallet::compact] value: BalanceOf, From 04d55f3839cde2b80ef471a7bbf52b498b6e6a42 Mon Sep 17 00:00:00 2001 From: Georges Dib Date: Tue, 21 Sep 2021 20:19:49 +0100 Subject: [PATCH 04/80] Continuing adding storage_info to pallet staking --- frame/staking/src/lib.rs | 42 +++++++++++++++++++++++-------- frame/staking/src/pallet/impls.rs | 42 +++++++++++++++++++++++++------ frame/staking/src/pallet/mod.rs | 4 +-- frame/staking/src/slashing.rs | 18 +++++++++++-- 4 files changed, 83 insertions(+), 23 deletions(-) diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index 88059f0ea8d91..40d7c65f62d73 100644 --- a/frame/staking/src/lib.rs +++ b/frame/staking/src/lib.rs @@ -355,7 +355,7 @@ type NegativeImbalanceOf = <::Currency as Currency< >>::NegativeImbalance; /// Information regarding the active era (era in used in session). -#[derive(Encode, Decode, RuntimeDebug, TypeInfo)] +#[derive(Encode, Decode, RuntimeDebug, TypeInfo, MaxEncodedLen)] pub struct ActiveEraInfo { /// Index of era. pub index: EraIndex, @@ -390,7 +390,7 @@ pub enum StakerStatus { } /// A destination account for payment. -#[derive(PartialEq, Eq, Copy, Clone, Encode, Decode, RuntimeDebug, TypeInfo)] +#[derive(PartialEq, Eq, Copy, Clone, Encode, Decode, RuntimeDebug, TypeInfo, MaxEncodedLen)] pub enum RewardDestination { /// Pay into the stash account, increasing the amount at stake accordingly. Staked, @@ -411,7 +411,7 @@ impl Default for RewardDestination { } /// Preference of what happens regarding validation. -#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, TypeInfo)] +#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, TypeInfo, MaxEncodedLen)] pub struct ValidatorPrefs { /// Reward that validator takes up-front; only the rest is split between themselves and /// nominators. @@ -593,7 +593,7 @@ where } /// A record of the nominations made by a specific account. -#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, TypeInfo)] +#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, TypeInfo, MaxEncodedLen)] pub struct Nominations { /// The targets of nomination. pub targets: Vec, @@ -619,10 +619,21 @@ pub struct IndividualExposure { } /// A snapshot of the stake backing a single validator in the system. +/// `Limit` is the size limit of `others` bounded by `MaxNominatorRewardedPerValidator` #[derive( - PartialEq, Eq, PartialOrd, Ord, Clone, Encode, Decode, Default, RuntimeDebug, TypeInfo, + PartialEq, + Eq, + PartialOrd, + Ord, + Clone, + Encode, + Decode, + Default, + RuntimeDebug, + TypeInfo, + MaxEncodedLen, )] -pub struct Exposure { +pub struct Exposure> { /// The total balance backing this validator. #[codec(compact)] pub total: Balance, @@ -630,7 +641,7 @@ pub struct Exposure { #[codec(compact)] pub own: Balance, /// The portions of nominators stashes that are exposed. - pub others: Vec>, + pub others: WeakBoundedVec, Limit>, } /// A pending slash record. The value of the slash has been computed but not applied yet, @@ -669,7 +680,11 @@ impl SessionInterface<::AccountId> for T where T: pallet_session::Config::AccountId>, T: pallet_session::historical::Config< - FullIdentification = Exposure<::AccountId, BalanceOf>, + FullIdentification = Exposure< + ::AccountId, + BalanceOf, + T::MaxNominatorRewardedPerValidator, + >, FullIdentificationOf = ExposureOf, >, T::SessionHandler: pallet_session::SessionHandler<::AccountId>, @@ -798,10 +813,15 @@ impl Convert> for StashOf { /// `active_era`. It can differ from the latest planned exposure in `current_era`. pub struct ExposureOf(sp_std::marker::PhantomData); -impl Convert>>> - for ExposureOf +impl + Convert< + T::AccountId, + Option, T::MaxNominatorRewardedPerValidator>>, + > for ExposureOf { - fn convert(validator: T::AccountId) -> Option>> { + fn convert( + validator: T::AccountId, + ) -> Option, T::MaxNominatorRewardedPerValidator>> { >::active_era() .map(|active_era| >::eras_stakers(active_era.index, &validator)) } diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index 3e5551a5057dc..42c0a1b63aac2 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -392,7 +392,10 @@ impl Pallet { /// Returns the new validator set. pub fn trigger_new_era( start_session_index: SessionIndex, - exposures: Vec<(T::AccountId, Exposure>)>, + exposures: Vec<( + T::AccountId, + Exposure, T::MaxNominatorRewardedPerValidator>, + )>, ) -> Vec { // Increment or set current era. let new_planned_era = CurrentEra::::mutate(|s| { @@ -468,7 +471,10 @@ impl Pallet { /// /// Store staking information for the new planned era pub fn store_stakers_info( - exposures: Vec<(T::AccountId, Exposure>)>, + exposures: Vec<( + T::AccountId, + Exposure, T::MaxNominatorRewardedPerValidator>, + )>, new_planned_era: EraIndex, ) -> Vec { let elected_stashes = exposures.iter().cloned().map(|(x, _)| x).collect::>(); @@ -513,7 +519,10 @@ impl Pallet { /// [`Exposure`]. fn collect_exposures( supports: Supports, - ) -> Vec<(T::AccountId, Exposure>)> { + ) -> Vec<( + T::AccountId, + Exposure, T::MaxNominatorRewardedPerValidator>, + )> { let total_issuance = T::Currency::total_issuance(); let to_currency = |e: frame_election_provider_support::ExtendedBalance| { T::CurrencyToVote::to_currency(e, total_issuance) @@ -1038,12 +1047,20 @@ impl pallet_session::SessionManager for Pallet { } } -impl historical::SessionManager>> - for Pallet +impl + historical::SessionManager< + T::AccountId, + Exposure, T::MaxNominatorRewardedPerValidator>, + > for Pallet { fn new_session( new_index: SessionIndex, - ) -> Option>)>> { + ) -> Option< + Vec<( + T::AccountId, + Exposure, T::MaxNominatorRewardedPerValidator>, + )>, + > { >::new_session(new_index).map(|validators| { let current_era = Self::current_era() // Must be some as a new era has been created. @@ -1060,7 +1077,12 @@ impl historical::SessionManager Option>)>> { + ) -> Option< + Vec<( + T::AccountId, + Exposure, T::MaxNominatorRewardedPerValidator>, + )>, + > { >::new_session_genesis(new_index).map( |validators| { let current_era = Self::current_era() @@ -1108,7 +1130,11 @@ impl where T: pallet_session::Config::AccountId>, T: pallet_session::historical::Config< - FullIdentification = Exposure<::AccountId, BalanceOf>, + FullIdentification = Exposure< + ::AccountId, + BalanceOf, + T::MaxNominatorRewardedPerValidator, + >, FullIdentificationOf = ExposureOf, >, T::SessionHandler: pallet_session::SessionHandler<::AccountId>, diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index 0eb886e7c34e1..f7a4027086c07 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -318,7 +318,7 @@ pub mod pallet { EraIndex, Twox64Concat, T::AccountId, - Exposure>, + Exposure, T::MaxNominatorRewardedPerValidator>, ValueQuery, >; @@ -341,7 +341,7 @@ pub mod pallet { EraIndex, Twox64Concat, T::AccountId, - Exposure>, + Exposure, T::MaxNominatorRewardedPerValidator>, ValueQuery, >; diff --git a/frame/staking/src/slashing.rs b/frame/staking/src/slashing.rs index 15ca85b4d046f..c38fdf1e6453c 100644 --- a/frame/staking/src/slashing.rs +++ b/frame/staking/src/slashing.rs @@ -196,14 +196,14 @@ impl SpanRecord { } /// Parameters for performing a slash. -#[derive(Clone)] pub(crate) struct SlashParams<'a, T: 'a + Config> { /// The stash account being slashed. pub(crate) stash: &'a T::AccountId, /// The proportion of the slash. pub(crate) slash: Perbill, /// The exposure of the stash and all nominators. - pub(crate) exposure: &'a Exposure>, + pub(crate) exposure: + &'a Exposure, T::MaxNominatorRewardedPerValidator>, /// The era where the offence occurred. pub(crate) slash_era: EraIndex, /// The first era in the current bonding period. @@ -215,6 +215,20 @@ pub(crate) struct SlashParams<'a, T: 'a + Config> { pub(crate) reward_proportion: Perbill, } +impl<'a, T: 'a + Config> Clone for SlashParams<'a, T> { + fn clone(&self) -> Self { + Self { + stash: &self.stash.clone(), + slash: self.slash.clone(), + exposure: self.exposure.clone(), + slash_era: self.slash_era.clone(), + window_start: self.window_start.clone(), + now: self.now.clone(), + reward_proportion: self.reward_proportion.clone(), + } + } +} + /// Computes a slash of a validator and nominators. It returns an unapplied /// record to be applied at some later point. Slashing metadata is updated in storage, /// since unapplied records are only rarely intended to be dropped. From a55274abc26d4a35d2c91456e2dc1c2c32b76e10 Mon Sep 17 00:00:00 2001 From: Georges Dib Date: Tue, 21 Sep 2021 22:52:27 +0100 Subject: [PATCH 05/80] Implementing `MaxEncodedLen` on `PerThing` --- primitives/arithmetic/src/per_things.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/primitives/arithmetic/src/per_things.rs b/primitives/arithmetic/src/per_things.rs index f388c19de6b43..de56341874b26 100644 --- a/primitives/arithmetic/src/per_things.rs +++ b/primitives/arithmetic/src/per_things.rs @@ -22,7 +22,7 @@ use crate::traits::{ BaseArithmetic, Bounded, CheckedAdd, CheckedMul, CheckedSub, One, SaturatedConversion, Saturating, UniqueSaturatedInto, Unsigned, Zero, }; -use codec::{CompactAs, Encode}; +use codec::{CompactAs, Encode, MaxEncodedLen}; use num_traits::{Pow, SaturatingAdd, SaturatingSub}; use sp_debug_derive::RuntimeDebug; use sp_std::{ @@ -425,7 +425,7 @@ macro_rules! implement_per_thing { /// #[doc = $title] #[cfg_attr(feature = "std", derive(Serialize, Deserialize))] - #[derive(Encode, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, RuntimeDebug, scale_info::TypeInfo)] + #[derive(Encode, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, RuntimeDebug, scale_info::TypeInfo, MaxEncodedLen)] pub struct $name($type); /// Implementation makes any compact encoding of `PerThing::Inner` valid, From 578284fec797cf075f179e0317141c477425732e Mon Sep 17 00:00:00 2001 From: Georges Dib Date: Tue, 21 Sep 2021 23:38:55 +0100 Subject: [PATCH 06/80] Adding `force_push` to `WeakBoundedVec` --- frame/support/src/storage/weak_bounded_vec.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/frame/support/src/storage/weak_bounded_vec.rs b/frame/support/src/storage/weak_bounded_vec.rs index 9c30c45c3e2e1..393c4e451f1cc 100644 --- a/frame/support/src/storage/weak_bounded_vec.rs +++ b/frame/support/src/storage/weak_bounded_vec.rs @@ -120,6 +120,22 @@ impl> WeakBoundedVec { Self::unchecked_from(t) } + /// Exactly the same semantics as [`Vec::push`], this function unlike `try_push` + /// does no check, but only logs warnings if the bound is not being respected. + /// The additional scope can be used to indicate where a potential overflow is + /// happening. + pub fn force_push(&mut self, element: T, scope: Option<&'static str>) { + if self.len() > Self::bound() { + log::warn!( + target: crate::LOG_TARGET, + "length of a bounded vector in scope {} is not respected.", + scope.unwrap_or("UNKNOWN"), + ); + } + + self.0.push(element); + } + /// Consumes self and mutates self via the given `mutate` function. /// /// If the outcome of mutation is within bounds, `Some(Self)` is returned. Else, `None` is From 6a2a06ea264070d84a5adf4f104a594c81d192f1 Mon Sep 17 00:00:00 2001 From: Georges Dib Date: Wed, 22 Sep 2021 20:27:57 +0100 Subject: [PATCH 07/80] Continue adding storage_info to staking pallet --- frame/staking/src/lib.rs | 93 +++++++++++++++++++++++-------- frame/staking/src/pallet/impls.rs | 25 +++++++-- frame/staking/src/pallet/mod.rs | 49 +++++++++++----- frame/staking/src/slashing.rs | 36 +++++++++--- 4 files changed, 153 insertions(+), 50 deletions(-) diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index 40d7c65f62d73..9d51a6f8dbae6 100644 --- a/frame/staking/src/lib.rs +++ b/frame/staking/src/lib.rs @@ -301,6 +301,7 @@ mod pallet; use codec::{Decode, Encode, HasCompact, MaxEncodedLen}; use frame_support::{ + storage::bounded_btree_map::BoundedBTreeMap, traits::{Currency, Get}, weights::Weight, BoundedVec, WeakBoundedVec, @@ -316,7 +317,6 @@ use sp_staking::{ SessionIndex, }; use sp_std::{ - collections::btree_map::BTreeMap, convert::{From, TryFrom}, prelude::*, }; @@ -369,12 +369,28 @@ pub struct ActiveEraInfo { /// Reward points of an era. Used to split era total payout between validators. /// /// This points will be used to reward validators and their respective nominators. -#[derive(PartialEq, Encode, Decode, Default, RuntimeDebug, TypeInfo)] -pub struct EraRewardPoints { +/// `Limit` bounds the number of points earned by a given validator +#[derive(PartialEq, Encode, Decode, RuntimeDebug, TypeInfo, MaxEncodedLen)] +#[codec(mel_bound(Limit: Get))] +pub struct EraRewardPoints +where + AccountId: Ord + MaxEncodedLen, + Limit: Get, +{ /// Total number of points. Equals the sum of reward points for each validator. total: RewardPoint, /// The reward points earned by a given validator. - individual: BTreeMap, + individual: BoundedBTreeMap, +} + +impl Default for EraRewardPoints +where + AccountId: Ord + MaxEncodedLen, + Limit: Get, +{ + fn default() -> Self { + Self { total: RewardPoint::default(), individual: BoundedBTreeMap::default() } + } } /// Indicates the initial status of the staker. @@ -620,20 +636,14 @@ pub struct IndividualExposure { /// A snapshot of the stake backing a single validator in the system. /// `Limit` is the size limit of `others` bounded by `MaxNominatorRewardedPerValidator` -#[derive( - PartialEq, - Eq, - PartialOrd, - Ord, - Clone, - Encode, - Decode, - Default, - RuntimeDebug, - TypeInfo, - MaxEncodedLen, -)] -pub struct Exposure> { +#[derive(PartialEq, Eq, PartialOrd, Ord, Encode, Decode, RuntimeDebug, TypeInfo, MaxEncodedLen)] +#[codec(mel_bound(Limit: Get, Balance: HasCompact))] +pub struct Exposure +where + AccountId: MaxEncodedLen, + Balance: HasCompact + MaxEncodedLen, + Limit: Get, +{ /// The total balance backing this validator. #[codec(compact)] pub total: Balance, @@ -644,18 +654,55 @@ pub struct Exposure> { pub others: WeakBoundedVec, Limit>, } +// NOTE: maybe use derivative to avoid this +impl Default for Exposure +where + AccountId: MaxEncodedLen, + Balance: HasCompact + MaxEncodedLen + Default, + Limit: Get, +{ + fn default() -> Self { + Self { + total: Balance::default(), + own: Balance::default(), + others: WeakBoundedVec::default(), + } + } +} + +impl Clone for Exposure +where + AccountId: MaxEncodedLen, + Balance: HasCompact + MaxEncodedLen + Clone, + Limit: Get, + WeakBoundedVec, Limit>: Clone, +{ + fn clone(&self) -> Self { + Self { total: self.total.clone(), own: self.own.clone(), others: self.others.clone() } + } +} + /// A pending slash record. The value of the slash has been computed but not applied yet, /// rather deferred for several eras. -#[derive(Encode, Decode, Default, RuntimeDebug, TypeInfo)] -pub struct UnappliedSlash { +/// `SlahedLimit` bounds the number of slashed accounts +/// `ReportersLimit` bounds the number of reporters +#[derive(Encode, Decode, Default, RuntimeDebug, TypeInfo, MaxEncodedLen)] +#[codec(mel_bound(SlashedLimit: Get, ReportersLimit: Get))] +pub struct UnappliedSlash +where + AccountId: MaxEncodedLen, + Balance: HasCompact + MaxEncodedLen, + SlashedLimit: Get, + ReportersLimit: Get, +{ /// The stash ID of the offending validator. validator: AccountId, /// The validator's own slash. own: Balance, /// All other slashed stakers and amounts. - others: Vec<(AccountId, Balance)>, + others: WeakBoundedVec<(AccountId, Balance), SlashedLimit>, /// Reporters of the offence; bounty payout recipients. - reporters: Vec, + reporters: WeakBoundedVec, /// The amount of payout. payout: Balance, } @@ -754,7 +801,7 @@ impl Pallet { ledger: &StakingLedger< T::AccountId, BalanceOf, - T::MaxUnlockingChunks, + ConstU32, T::MaxErasForRewards, >, ) { @@ -340,7 +341,7 @@ impl Pallet { let bonding_duration = T::BondingDuration::get(); BondedEras::::mutate(|bonded| { - bonded.push((active_era, start_session)); + bonded.force_push((active_era, start_session), None); if active_era > bonding_duration { let first_kept = active_era - bonding_duration; @@ -548,10 +549,18 @@ impl Pallet { total = total.saturating_add(stake); }); + let others = WeakBoundedVec::<_, T::MaxNominatorRewardedPerValidator>::force_from( + others, + Some( + "Warning: The number of nominators is bigger than expected. \ + A runtime configuration adjustment may be needed.", + ), + ); + let exposure = Exposure { own, others, total }; (validator, exposure) }) - .collect::)>>() + .collect::)>>() } /// Remove all associated data of a stash account from the staking system. @@ -1231,7 +1240,13 @@ where let rw = upper_bound + nominators_len * upper_bound; add_db_reads_writes(rw, rw); } - unapplied.reporters = details.reporters.clone(); + unapplied.reporters = WeakBoundedVec::<_, T::MaxNbOfReporters>::force_from( + details.reporters, + Some( + "Warning: Number of reporters is bigger than expected. \ + A runtime parameter adjustment may be needed.", + ), + ); if slash_defer_duration == 0 { // Apply right away. slashing::apply_slash::(unapplied); diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index f7a4027086c07..bc664791424f9 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -50,6 +50,7 @@ use crate::{ ValidatorPrefs, }; +pub const MAX_UNLOCKING_CHUNKS: u32 = 32; const STAKING_ID: LockIdentifier = *b"staking "; #[frame_support::pallet] @@ -155,14 +156,18 @@ pub mod pallet { #[pallet::constant] type MaxNbOfInvulnerables: Get; - /// Maximum number of unlocking chunks - #[pallet::constant] - type MaxUnlockingChunks: Get; - /// Maximum number of eras for which the stakers behind a validator have claimed rewards. #[pallet::constant] type MaxErasForRewards: Get; + /// Maximum number of validators. + #[pallet::constant] + type MaxNbOfValidators: Get; + + /// Maximum number of reporters for slashing. + #[pallet::constant] + type MaxNbOfReporters: Get; + /// Something that can provide a sorted list of voters in a somewhat sorted way. The /// original use case for this was designed with [`pallet_bags_list::Pallet`] in mind. If /// the bags-list is not desired, [`impls::UseNominatorsMap`] is likely the desired option. @@ -235,7 +240,12 @@ pub mod pallet { _, Blake2_128Concat, T::AccountId, - StakingLedger, T::MaxUnlockingChunks, T::MaxErasForRewards>, + StakingLedger< + T::AccountId, + BalanceOf, + ConstU32, + T::MaxErasForRewards, + >, >; /// Where the reward payment should be made. Keyed by stash. @@ -374,8 +384,13 @@ pub mod pallet { /// If reward hasn't been set or has been removed then 0 reward is returned. #[pallet::storage] #[pallet::getter(fn eras_reward_points)] - pub type ErasRewardPoints = - StorageMap<_, Twox64Concat, EraIndex, EraRewardPoints, ValueQuery>; + pub type ErasRewardPoints = StorageMap< + _, + Twox64Concat, + EraIndex, + EraRewardPoints, + ValueQuery, + >; /// The total amount staked for the last `HISTORY_DEPTH` eras. /// If total hasn't been set or has been removed then 0 stake is returned. @@ -408,7 +423,15 @@ pub mod pallet { _, Twox64Concat, EraIndex, - WeakBoundedVec>, T::MaxUnappliedSlashes>, + WeakBoundedVec< + UnappliedSlash< + T::AccountId, + BalanceOf, + T::MaxNominatorRewardedPerValidator, + T::MaxNbOfReporters, + >, + T::MaxUnappliedSlashes, + >, ValueQuery, >; @@ -418,7 +441,7 @@ pub mod pallet { /// `[active_era - bounding_duration; active_era]` #[pallet::storage] pub(crate) type BondedEras = - StorageValue<_, Vec<(EraIndex, SessionIndex)>, ValueQuery>; + StorageValue<_, WeakBoundedVec<(EraIndex, SessionIndex), T::BondingDuration>, ValueQuery>; /// All slashing events on validators, mapped by era to the highest slash proportion /// and slash value of the era. @@ -782,7 +805,7 @@ pub mod pallet { stash, total: value, active: value, - unlocking: BoundedVec::<_, T::MaxUnlockingChunks>::default(), + unlocking: BoundedVec::<_, ConstU32>::default(), claimed_rewards, }; Self::update_ledger(&controller, &item); @@ -847,7 +870,7 @@ pub mod pallet { /// Once the unlock period is done, you can call `withdraw_unbonded` to actually move /// the funds out of management ready for transfer. /// - /// No more than a limited number of unlocking chunks (see `MaxUnlockingChunks`) + /// No more than a limited number of unlocking chunks (see `MAX_UNLOCKING_CHUNKS`) /// can co-exists at the same time. In that case, [`Call::withdraw_unbonded`] need /// to be called first to remove some of the chunks (if possible). /// @@ -1381,10 +1404,10 @@ pub mod pallet { /// /// # /// - Time complexity: O(L), where L is unlocking chunks - /// - Bounded by `MaxUnlockingChunks`. + /// - Bounded by `MAX_UNLOCKING_CHUNKS`. /// - Storage changes: Can't increase storage, only decrease it. /// # - #[pallet::weight(T::WeightInfo::rebond(T::MaxUnlockingChunks::get()))] + #[pallet::weight(T::WeightInfo::rebond(MAX_UNLOCKING_CHUNKS))] pub fn rebond( origin: OriginFor, #[pallet::compact] value: BalanceOf, diff --git a/frame/staking/src/slashing.rs b/frame/staking/src/slashing.rs index c38fdf1e6453c..e55794e09fb9a 100644 --- a/frame/staking/src/slashing.rs +++ b/frame/staking/src/slashing.rs @@ -57,13 +57,14 @@ use codec::{Decode, Encode}; use frame_support::{ ensure, traits::{Currency, Imbalance, OnUnbalanced}, + WeakBoundedVec, }; use scale_info::TypeInfo; use sp_runtime::{ traits::{Saturating, Zero}, DispatchResult, RuntimeDebug, }; -use sp_std::vec::Vec; +use sp_std::{ops::Deref, vec::Vec}; /// The proportion of the slashing reward to be paid out on the first slashing detection. /// This is f_1 in the paper. @@ -220,7 +221,7 @@ impl<'a, T: 'a + Config> Clone for SlashParams<'a, T> { Self { stash: &self.stash.clone(), slash: self.slash.clone(), - exposure: self.exposure.clone(), + exposure: &self.exposure.clone(), slash_era: self.slash_era.clone(), window_start: self.window_start.clone(), now: self.now.clone(), @@ -237,7 +238,14 @@ impl<'a, T: 'a + Config> Clone for SlashParams<'a, T> { /// to be set at a higher level, if any. pub(crate) fn compute_slash( params: SlashParams, -) -> Option>> { +) -> Option< + UnappliedSlash< + T::AccountId, + BalanceOf, + T::MaxNominatorRewardedPerValidator, + T::MaxNbOfReporters, + >, +> { let SlashParams { stash, slash, exposure, slash_era, window_start, now, reward_proportion } = params.clone(); @@ -301,14 +309,14 @@ pub(crate) fn compute_slash( } } - let mut nominators_slashed = Vec::new(); + let mut nominators_slashed = WeakBoundedVec::default(); reward_payout += slash_nominators::(params, prior_slash_p, &mut nominators_slashed); Some(UnappliedSlash { validator: stash.clone(), own: val_slashed, others: nominators_slashed, - reporters: Vec::new(), + reporters: WeakBoundedVec::default(), payout: reward_payout, }) } @@ -345,7 +353,10 @@ fn kick_out_if_recent(params: SlashParams) { fn slash_nominators( params: SlashParams, prior_slash_p: Perbill, - nominators_slashed: &mut Vec<(T::AccountId, BalanceOf)>, + nominators_slashed: &mut WeakBoundedVec< + (T::AccountId, BalanceOf), + T::MaxNominatorRewardedPerValidator, + >, ) -> BalanceOf { let SlashParams { stash: _, slash, exposure, slash_era, window_start, now, reward_proportion } = params; @@ -353,7 +364,7 @@ fn slash_nominators( let mut reward_payout = Zero::zero(); nominators_slashed.reserve(exposure.others.len()); - for nominator in &exposure.others { + for nominator in exposure.others.into_iter() { let stash = &nominator.who; let mut nom_slashed = Zero::zero(); @@ -604,7 +615,14 @@ 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< + T::AccountId, + BalanceOf, + T::MaxNominatorRewardedPerValidator, + T::MaxNbOfReporters, + >, +) { let mut slashed_imbalance = NegativeImbalanceOf::::zero(); let mut reward_payout = unapplied_slash.payout; @@ -615,7 +633,7 @@ pub(crate) fn apply_slash(unapplied_slash: UnappliedSlash(&nominator, nominator_slash, &mut reward_payout, &mut slashed_imbalance); } From 97c4c9f59aafd4abc4c5325f3a6fb2713cf8f415 Mon Sep 17 00:00:00 2001 From: Georges Dib Date: Wed, 22 Sep 2021 22:26:55 +0100 Subject: [PATCH 08/80] Implementing `PartialOrd` on `WeakBoundedVec` --- frame/support/src/storage/weak_bounded_vec.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/frame/support/src/storage/weak_bounded_vec.rs b/frame/support/src/storage/weak_bounded_vec.rs index 393c4e451f1cc..a08bad162fbe0 100644 --- a/frame/support/src/storage/weak_bounded_vec.rs +++ b/frame/support/src/storage/weak_bounded_vec.rs @@ -27,7 +27,7 @@ use core::{ ops::{Deref, Index, IndexMut}, slice::SliceIndex, }; -use sp_std::{convert::TryFrom, fmt, marker::PhantomData, prelude::*}; +use sp_std::{cmp::Ordering, convert::TryFrom, fmt, marker::PhantomData, prelude::*}; /// A weakly bounded vector. /// @@ -286,6 +286,12 @@ impl codec::DecodeLength for WeakBoundedVec { } } +impl PartialOrd for WeakBoundedVec { + fn partial_cmp(&self, other: &Self) -> Option { + PartialOrd::partial_cmp(&self.0, &other.0) + } +} + // NOTE: we could also implement this as: // impl, S2: Get> PartialEq> for WeakBoundedVec to allow comparison of bounded vectors with different bounds. From d6ebf745969fcad7c4734dd47704ff23dffbe4aa Mon Sep 17 00:00:00 2001 From: Georges Dib Date: Wed, 22 Sep 2021 22:29:29 +0100 Subject: [PATCH 09/80] Implementing `Ord` for `WeakBoundedVec` --- frame/support/src/storage/weak_bounded_vec.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/frame/support/src/storage/weak_bounded_vec.rs b/frame/support/src/storage/weak_bounded_vec.rs index a08bad162fbe0..d492514bfe7da 100644 --- a/frame/support/src/storage/weak_bounded_vec.rs +++ b/frame/support/src/storage/weak_bounded_vec.rs @@ -292,6 +292,12 @@ impl PartialOrd for WeakBoundedVec { } } +impl Ord for WeakBoundedVec { + fn cmp(&self, other: &Self) -> Ordering { + Ord::cmp(&self.0, &other.0) + } +} + // NOTE: we could also implement this as: // impl, S2: Get> PartialEq> for WeakBoundedVec to allow comparison of bounded vectors with different bounds. From 7c60ac5f7420c5e5525e545329ab0a1bfd97ba4a Mon Sep 17 00:00:00 2001 From: Georges Dib Date: Wed, 22 Sep 2021 22:37:44 +0100 Subject: [PATCH 10/80] Implementing `force_insert` on `WeakBoundedVec` --- frame/support/src/storage/weak_bounded_vec.rs | 30 ++++++++++++------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/frame/support/src/storage/weak_bounded_vec.rs b/frame/support/src/storage/weak_bounded_vec.rs index d492514bfe7da..0e0e75dca4bf7 100644 --- a/frame/support/src/storage/weak_bounded_vec.rs +++ b/frame/support/src/storage/weak_bounded_vec.rs @@ -105,10 +105,7 @@ impl> WeakBoundedVec { S::get() as usize } - /// Create `Self` from `t` without any checks. Logs warnings if the bound is not being - /// respected. The additional scope can be used to indicate where a potential overflow is - /// happening. - pub fn force_from(t: Vec, scope: Option<&'static str>) -> Self { + fn check_bound_and_log(t: &Vec, scope: Option<&'static str>) { if t.len() > Self::bound() { log::warn!( target: crate::LOG_TARGET, @@ -116,6 +113,13 @@ impl> WeakBoundedVec { scope.unwrap_or("UNKNOWN"), ); } + } + + /// Create `Self` from `t` without any checks. Logs warnings if the bound is not being + /// respected. The additional scope can be used to indicate where a potential overflow is + /// happening. + pub fn force_from(t: Vec, scope: Option<&'static str>) -> Self { + Self::check_bound_and_log(&t, scope); Self::unchecked_from(t) } @@ -125,17 +129,21 @@ impl> WeakBoundedVec { /// The additional scope can be used to indicate where a potential overflow is /// happening. pub fn force_push(&mut self, element: T, scope: Option<&'static str>) { - if self.len() > Self::bound() { - log::warn!( - target: crate::LOG_TARGET, - "length of a bounded vector in scope {} is not respected.", - scope.unwrap_or("UNKNOWN"), - ); - } + Self::check_bound_and_log(self, scope); self.0.push(element); } + /// Exactly the same semantics as [`Vec::insert`], this function unlike `try_insert` + /// does no check, but only logs warnings if the bound is not being respected. + /// The additional scope can be used to indicate where a potential overflow is + /// happening. + pub fn force_insert(&mut self, index: usize, element: T, scope: Option<&'static str>) { + Self::check_bound_and_log(self, scope); + + self.0.insert(index, element); + } + /// Consumes self and mutates self via the given `mutate` function. /// /// If the outcome of mutation is within bounds, `Some(Self)` is returned. Else, `None` is From 1fc848fa32e45732eb6ae3dd48ba9db20b8215e9 Mon Sep 17 00:00:00 2001 From: Georges Dib Date: Wed, 22 Sep 2021 22:44:47 +0100 Subject: [PATCH 11/80] Implementing `truncate` on `WeakBoundedVec` --- frame/support/src/storage/weak_bounded_vec.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/frame/support/src/storage/weak_bounded_vec.rs b/frame/support/src/storage/weak_bounded_vec.rs index 0e0e75dca4bf7..62f4567d71557 100644 --- a/frame/support/src/storage/weak_bounded_vec.rs +++ b/frame/support/src/storage/weak_bounded_vec.rs @@ -76,6 +76,15 @@ impl WeakBoundedVec { self.0.remove(index) } + /// Exactly the same semantics as [`Vec::truncate`]. + /// + /// # Panics + /// + /// Panics if `index` is out of bounds. + pub fn truncate(&mut self, index: usize) { + self.0.truncate(index) + } + /// Exactly the same semantics as [`Vec::swap_remove`]. /// /// # Panics From 06830eb3b49ca68f763af7896b803bef9ba9d53b Mon Sep 17 00:00:00 2001 From: Georges Dib Date: Thu, 23 Sep 2021 21:51:50 +0100 Subject: [PATCH 12/80] Moved const `MAX_NOMINATIONS` to be a type `MaxNominations` to allow it to be a bound for a `BoundedVec` --- frame/staking/src/benchmarking.rs | 28 +++++++++---------- frame/staking/src/lib.rs | 23 ++++++++++++---- frame/staking/src/mock.rs | 3 +- frame/staking/src/pallet/impls.rs | 18 +++++++++--- frame/staking/src/pallet/mod.rs | 29 +++++++++++++------ frame/staking/src/slashing.rs | 46 ++++++++++++++++++++----------- 6 files changed, 99 insertions(+), 48 deletions(-) diff --git a/frame/staking/src/benchmarking.rs b/frame/staking/src/benchmarking.rs index f3def7206320c..64fe158fcbfa3 100644 --- a/frame/staking/src/benchmarking.rs +++ b/frame/staking/src/benchmarking.rs @@ -354,17 +354,17 @@ 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::MAX_NOMINATIONS` validators nominated, and our validator + // each nominator should have `T::MaxNominations` validators nominated, and our validator // should be somewhere in there. let k in 1 .. 128; - // these are the other validators; there are `T::MAX_NOMINATIONS - 1` of them, so - // there are a total of `T::MAX_NOMINATIONS` validators in the system. - let rest_of_validators = create_validators_with_seed::(T::MAX_NOMINATIONS - 1, 100, 415)?; + // these are the other validators; there are `T::MaxNominations - 1` of them, so + // there are a total of `T::MaxNominations` validators in the system. + let rest_of_validators = create_validators_with_seed::(T::MaxNominations::get() - 1, 100, 415)?; // this is the validator that will be kicking. let (stash, controller) = create_stash_controller::( - T::MAX_NOMINATIONS - 1, + T::MaxNominations::get() - 1, 100, Default::default(), )?; @@ -379,7 +379,7 @@ benchmarks! { for i in 0 .. k { // create a nominator stash. let (n_stash, n_controller) = create_stash_controller::( - T::MAX_NOMINATIONS + i, + T::MaxNominations::get() + i, 100, Default::default(), )?; @@ -414,9 +414,9 @@ benchmarks! { } } - // Worst case scenario, T::MAX_NOMINATIONS + // Worst case scenario, T::MaxNominations nominate { - let n in 1 .. T::MAX_NOMINATIONS; + let n in 1 .. T::MaxNominations::get(); // clean up any existing state. clear_validators_and_nominators::(); @@ -427,7 +427,7 @@ benchmarks! { // we are just doing an insert into the origin position. let scenario = ListScenario::::new(origin_weight, true)?; let (stash, controller) = create_stash_controller_with_balance::( - SEED + T::MAX_NOMINATIONS + 1, // make sure the account does not conflict with others + SEED + T::MaxNominations::get() + 1, // make sure the account does not conflict with others origin_weight, Default::default(), ).unwrap(); @@ -714,7 +714,7 @@ benchmarks! { create_validators_with_nominators_for_era::( v, n, - ::MAX_NOMINATIONS as usize, + ::MaxNominations::get() as usize, false, None, )?; @@ -732,7 +732,7 @@ benchmarks! { create_validators_with_nominators_for_era::( v, n, - ::MAX_NOMINATIONS as usize, + ::MaxNominations::get() as usize, false, None, )?; @@ -806,7 +806,7 @@ benchmarks! { let s in 1 .. 20; let validators = create_validators_with_nominators_for_era::( - v, n, T::MAX_NOMINATIONS as usize, false, None + v, n, T::MaxNominations::get() as usize, false, None )? .into_iter() .map(|v| T::Lookup::lookup(v).unwrap()) @@ -829,7 +829,7 @@ benchmarks! { let n = MAX_NOMINATORS; let _ = create_validators_with_nominators_for_era::( - v, n, T::MAX_NOMINATIONS as usize, false, None + v, n, T::MaxNominations::get() as usize, false, None )?; }: { let targets = >::get_npos_targets(); @@ -897,7 +897,7 @@ mod tests { create_validators_with_nominators_for_era::( v, n, - ::MAX_NOMINATIONS as usize, + ::MaxNominations::get() as usize, false, None, ) diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index 9d51a6f8dbae6..2d8824e779eef 100644 --- a/frame/staking/src/lib.rs +++ b/frame/staking/src/lib.rs @@ -371,6 +371,7 @@ pub struct ActiveEraInfo { /// This points will be used to reward validators and their respective nominators. /// `Limit` bounds the number of points earned by a given validator #[derive(PartialEq, Encode, Decode, RuntimeDebug, TypeInfo, MaxEncodedLen)] +#[scale_info(skip_type_params(Limit))] #[codec(mel_bound(Limit: Get))] pub struct EraRewardPoints where @@ -446,7 +447,7 @@ impl Default for ValidatorPrefs { } /// Just a Balance/BlockNumber tuple to encode when a chunk of funds will be unlocked. -#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, TypeInfo)] +#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, TypeInfo, MaxEncodedLen)] pub struct UnlockChunk { /// Amount of funds to be unlocked. #[codec(compact)] @@ -462,6 +463,7 @@ pub struct UnlockChunk { #[cfg_attr(feature = "runtime-benchmarks", derive(Default))] #[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, TypeInfo, MaxEncodedLen)] #[codec(mel_bound(UnlockingLimit: Get, RewardsLimit: Get))] +#[scale_info(skip_type_params(UnlockingLimit, RewardsLimit))] pub struct StakingLedger where Balance: HasCompact, @@ -609,10 +611,17 @@ where } /// A record of the nominations made by a specific account. +/// `Limit` bounds the number of `targets` #[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, TypeInfo, MaxEncodedLen)] -pub struct Nominations { +#[scale_info(skip_type_params(Limit))] +#[codec(mel_bound(Limit: Get))] +pub struct Nominations +where + AccountId: MaxEncodedLen, + Limit: Get, +{ /// The targets of nomination. - pub targets: Vec, + pub targets: BoundedVec, /// The era the nominations were submitted. /// /// Except for initial nominations which are considered submitted at era 0. @@ -625,7 +634,9 @@ pub struct Nominations { } /// The amount of exposure (to slashing) than an individual nominator has. -#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Encode, Decode, RuntimeDebug, TypeInfo)] +#[derive( + PartialEq, Eq, PartialOrd, Ord, Clone, Encode, Decode, RuntimeDebug, TypeInfo, MaxEncodedLen, +)] pub struct IndividualExposure { /// The stash account of the nominator in question. pub who: AccountId, @@ -637,6 +648,7 @@ pub struct IndividualExposure { /// A snapshot of the stake backing a single validator in the system. /// `Limit` is the size limit of `others` bounded by `MaxNominatorRewardedPerValidator` #[derive(PartialEq, Eq, PartialOrd, Ord, Encode, Decode, RuntimeDebug, TypeInfo, MaxEncodedLen)] +#[scale_info(skip_type_params(Limit))] #[codec(mel_bound(Limit: Get, Balance: HasCompact))] pub struct Exposure where @@ -688,6 +700,7 @@ where /// `ReportersLimit` bounds the number of reporters #[derive(Encode, Decode, Default, RuntimeDebug, TypeInfo, MaxEncodedLen)] #[codec(mel_bound(SlashedLimit: Get, ReportersLimit: Get))] +#[scale_info(skip_type_params(SlashedLimit, ReportersLimit))] pub struct UnappliedSlash where AccountId: MaxEncodedLen, @@ -825,7 +838,7 @@ impl Default for Forcing { // A value placed in storage that represents the current version of the Staking storage. This value // is used by the `on_runtime_upgrade` logic to determine whether we run storage migration logic. // This should match directly with the semantic versions of the Rust crate. -#[derive(Encode, Decode, Clone, Copy, PartialEq, Eq, RuntimeDebug, TypeInfo)] +#[derive(Encode, Decode, Clone, Copy, PartialEq, Eq, RuntimeDebug, TypeInfo, MaxEncodedLen)] enum Releases { V1_0_0Ancient, V2_0_0, diff --git a/frame/staking/src/mock.rs b/frame/staking/src/mock.rs index b3ce8e063cb61..5bf54a9c0ef88 100644 --- a/frame/staking/src/mock.rs +++ b/frame/staking/src/mock.rs @@ -247,6 +247,7 @@ const THRESHOLDS: [sp_npos_elections::VoteWeight; 9] = parameter_types! { pub static BagThresholds: &'static [sp_npos_elections::VoteWeight] = &THRESHOLDS; + pub const MaxNominations: u32 = 16; } impl pallet_bags_list::Config for Test { @@ -262,7 +263,6 @@ impl onchain::Config for Test { } impl crate::pallet::pallet::Config for Test { - const MAX_NOMINATIONS: u32 = 16; type Currency = Balances; type UnixTime = Timestamp; type CurrencyToVote = frame_support::traits::SaturatingCurrencyToVote; @@ -283,6 +283,7 @@ impl crate::pallet::pallet::Config for Test { type WeightInfo = (); // NOTE: consider a macro and use `UseNominatorsMap` as well. type SortedListProvider = BagsList; + type MaxNominations = MaxNominations; } impl frame_system::offchain::SendTransactionTypes for Test diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index 2b018fe1b556f..806fad9e55ef2 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -118,7 +118,10 @@ impl Pallet { match ledger.claimed_rewards.binary_search(&era) { Ok(_) => Err(Error::::AlreadyClaimed .with_weight(T::WeightInfo::payout_stakers_alive_staked(0)))?, - Err(pos) => ledger.claimed_rewards.insert(pos, era), + Err(pos) => ledger + .claimed_rewards + .try_insert(pos, era) + .map_err(|_| Error::::TooManyRewardsEras)?, } let exposure = >::get(&era, &ledger.stash); @@ -724,7 +727,11 @@ impl Pallet { .map_or(true, |spans| submitted_in >= spans.last_nonzero_slash()) }); if !targets.len().is_zero() { - all_voters.push((nominator.clone(), Self::weight_of(&nominator), targets)); + all_voters.push(( + nominator.clone(), + Self::weight_of(&nominator), + targets.to_vec(), + )); nominators_taken.saturating_inc(); } } else { @@ -776,7 +783,10 @@ impl Pallet { /// NOTE: you must ALWAYS use this function to add nominator or update their targets. Any access /// to `Nominators`, its counter, or `VoterList` outside of this function is almost certainly /// wrong. - pub fn do_add_nominator(who: &T::AccountId, nominations: Nominations) { + pub fn do_add_nominator( + who: &T::AccountId, + nominations: Nominations, + ) { if !Nominators::::contains_key(who) { // maybe update the counter. CounterForNominators::::mutate(|x| x.saturating_inc()); @@ -859,7 +869,7 @@ impl Pallet { } impl ElectionDataProvider> for Pallet { - const MAXIMUM_VOTES_PER_VOTER: u32 = T::MAX_NOMINATIONS; + const MAXIMUM_VOTES_PER_VOTER: u32 = T::MaxNominations::get(); fn desired_targets() -> data_provider::Result { Self::register_weight(T::DbWeight::get().reads(1)); diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index bc664791424f9..da7c9ed0b7f2e 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -96,7 +96,8 @@ pub mod pallet { >; /// Maximum number of nominations per nominator. - const MAX_NOMINATIONS: u32; + #[pallet::constant] + type MaxNominations: Get; /// Tokens have been minted and are unused for validator-reward. /// See [Era payout](./index.html#era-payout). @@ -168,6 +169,10 @@ pub mod pallet { #[pallet::constant] type MaxNbOfReporters: Get; + /// Maximum number of slashing spans that is stored. + #[pallet::constant] + type MaxPriorSlashingSpans: Get; + /// Something that can provide a sorted list of voters in a somewhat sorted way. The /// original use case for this was designed with [`pallet_bags_list::Pallet`] in mind. If /// the bags-list is not desired, [`impls::UseNominatorsMap`] is likely the desired option. @@ -182,7 +187,7 @@ pub mod pallet { // TODO: rename to snake case after https://github.com/paritytech/substrate/issues/8826 fixed. #[allow(non_snake_case)] fn MaxNominations() -> u32 { - T::MAX_NOMINATIONS + T::MaxNominations::get() } } @@ -278,7 +283,7 @@ pub mod pallet { #[pallet::storage] #[pallet::getter(fn nominators)] pub type Nominators = - StorageMap<_, Twox64Concat, T::AccountId, Nominations>; + StorageMap<_, Twox64Concat, T::AccountId, Nominations>; /// A tracker to keep count of the number of items in the `Nominators` map. #[pallet::storage] @@ -462,8 +467,12 @@ pub mod pallet { /// Slashing spans for stash accounts. #[pallet::storage] - pub(crate) type SlashingSpans = - StorageMap<_, Twox64Concat, T::AccountId, slashing::SlashingSpans>; + pub(crate) type SlashingSpans = StorageMap< + _, + Twox64Concat, + T::AccountId, + slashing::SlashingSpans, + >; /// Records information about the maximum slash of a stash within a slashing span, /// as well as how much reward has been paid out. @@ -682,6 +691,8 @@ pub mod pallet { TooManyValidators, /// Too many invulnerables are passed, a runtime configuration adjustment may be needed TooManyInvulnerables, + /// Too many Rewards Eras are passed, a runtime configuration adjustment may be needed + TooManyRewardsEras, } #[pallet::hooks] @@ -1026,7 +1037,7 @@ pub mod pallet { /// /// # /// - The transaction's complexity is proportional to the size of `targets` (N) - /// which is capped at CompactAssignments::LIMIT (MAX_NOMINATIONS). + /// which is capped at CompactAssignments::LIMIT (T::MaxNominations). /// - Both the reads and writes follow a similar pattern. /// # #[pallet::weight(T::WeightInfo::nominate(targets.len() as u32))] @@ -1054,9 +1065,8 @@ pub mod pallet { } ensure!(!targets.is_empty(), Error::::EmptyTargets); - ensure!(targets.len() <= T::MAX_NOMINATIONS as usize, Error::::TooManyTargets); - let old = Nominators::::get(stash).map_or_else(Vec::new, |x| x.targets); + let old = Nominators::::get(stash).map_or_else(Vec::new, |x| x.targets.to_vec()); let targets = targets .into_iter() @@ -1072,6 +1082,9 @@ pub mod pallet { }) .collect::, _>>()?; + let targets = BoundedVec::<_, T::MaxNominations>::try_from(targets) + .map_err(|_| Error::::TooManyTargets)?; + let nominations = Nominations { targets, // Initial nominations are considered submitted at era 0. See `Nominations` doc diff --git a/frame/staking/src/slashing.rs b/frame/staking/src/slashing.rs index e55794e09fb9a..b4340cf1691fb 100644 --- a/frame/staking/src/slashing.rs +++ b/frame/staking/src/slashing.rs @@ -50,10 +50,10 @@ //! Based on research at use crate::{ - BalanceOf, Config, EraIndex, Error, Exposure, NegativeImbalanceOf, Pallet, Perbill, + BalanceOf, Config, EraIndex, Error, Exposure, Get, NegativeImbalanceOf, Pallet, Perbill, SessionInterface, Store, UnappliedSlash, }; -use codec::{Decode, Encode}; +use codec::{Decode, Encode, MaxEncodedLen}; use frame_support::{ ensure, traits::{Currency, Imbalance, OnUnbalanced}, @@ -64,7 +64,7 @@ use sp_runtime::{ traits::{Saturating, Zero}, DispatchResult, RuntimeDebug, }; -use sp_std::{ops::Deref, vec::Vec}; +use sp_std::{convert::TryFrom, ops::Deref}; /// The proportion of the slashing reward to be paid out on the first slashing detection. /// This is f_1 in the paper. @@ -89,8 +89,11 @@ impl SlashingSpan { } /// An encoding of all of a nominator's slashing spans. -#[derive(Encode, Decode, RuntimeDebug, TypeInfo)] -pub struct SlashingSpans { +/// `Limit` bounds the size of the prior slashing spans vector +#[derive(Encode, Decode, RuntimeDebug, TypeInfo, MaxEncodedLen)] +#[scale_info(skip_type_params(Limit))] +#[codec(mel_bound(Limit: Get))] +pub struct SlashingSpans> { // the index of the current slashing span of the nominator. different for // every stash, resets when the account hits free balance 0. span_index: SpanIndex, @@ -100,10 +103,10 @@ pub struct SlashingSpans { last_nonzero_slash: EraIndex, // all prior slashing spans' start indices, in reverse order (most recent first) // encoded as offsets relative to the slashing span after it. - prior: Vec, + prior: WeakBoundedVec, } -impl SlashingSpans { +impl> SlashingSpans { // creates a new record of slashing spans for a stash, starting at the beginning // of the bonding period, relative to now. pub(crate) fn new(window_start: EraIndex) -> Self { @@ -114,7 +117,7 @@ impl SlashingSpans { // the first slash is applied. setting equal to `window_start` would // put a time limit on nominations. last_nonzero_slash: 0, - prior: Vec::new(), + prior: WeakBoundedVec::default(), } } @@ -128,7 +131,14 @@ impl SlashingSpans { } let last_length = next_start - self.last_start; - self.prior.insert(0, last_length); + self.prior.force_insert( + 0, + last_length, + Some( + "Warning: Size of the the prior slashing spans bigger than expected. \ + A runtime adjustment may be needed.", + ), + ); self.last_start = next_start; self.span_index += 1; true @@ -182,7 +192,7 @@ impl SlashingSpans { } /// A slashing-span record for a particular stash. -#[derive(Encode, Decode, Default, TypeInfo)] +#[derive(Encode, Decode, Default, TypeInfo, MaxEncodedLen)] pub(crate) struct SpanRecord { slashed: Balance, paid_out: Balance, @@ -219,9 +229,9 @@ pub(crate) struct SlashParams<'a, T: 'a + Config> { impl<'a, T: 'a + Config> Clone for SlashParams<'a, T> { fn clone(&self) -> Self { Self { - stash: &self.stash.clone(), + stash: self.stash, slash: self.slash.clone(), - exposure: &self.exposure.clone(), + exposure: self.exposure, slash_era: self.slash_era.clone(), window_start: self.window_start.clone(), now: self.now.clone(), @@ -363,8 +373,9 @@ fn slash_nominators( let mut reward_payout = Zero::zero(); - nominators_slashed.reserve(exposure.others.len()); - for nominator in exposure.others.into_iter() { + let mut slashed_nominators = Vec::with_capacity(exposure.others.len()); + + for nominator in exposure.others.to_vec().into_iter() { let stash = &nominator.who; let mut nom_slashed = Zero::zero(); @@ -404,9 +415,12 @@ fn slash_nominators( } } - nominators_slashed.push((stash.clone(), nom_slashed)); + slashed_nominators.push((stash.clone(), nom_slashed)); } + *nominators_slashed = WeakBoundedVec::<_, T::MaxNominatorRewardedPerValidator>::try_from(slashed_nominators) + .expect("slashed_nominators has a size of exposure.others which is MaxNominatorRewardedPerValidator"); + reward_payout } @@ -421,7 +435,7 @@ struct InspectingSpans<'a, T: Config + 'a> { dirty: bool, window_start: EraIndex, stash: &'a T::AccountId, - spans: SlashingSpans, + spans: SlashingSpans, paid_out: &'a mut BalanceOf, slash_of: &'a mut BalanceOf, reward_proportion: Perbill, From df969c687a4ddc8ee0da77f41d6502ec16f3aad6 Mon Sep 17 00:00:00 2001 From: Georges Dib Date: Thu, 23 Sep 2021 22:21:57 +0100 Subject: [PATCH 13/80] Add `drain` to `BoundedVec` and `WeakBoundedVec` --- frame/support/src/storage/bounded_vec.rs | 12 +++++++++++- frame/support/src/storage/weak_bounded_vec.rs | 12 ++++++++++-- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/frame/support/src/storage/bounded_vec.rs b/frame/support/src/storage/bounded_vec.rs index b45c294f8d4a4..48bf12cbfc921 100644 --- a/frame/support/src/storage/bounded_vec.rs +++ b/frame/support/src/storage/bounded_vec.rs @@ -28,7 +28,9 @@ use core::{ ops::{Deref, Index, IndexMut}, slice::SliceIndex, }; -use sp_std::{convert::TryFrom, fmt, marker::PhantomData, prelude::*}; +use sp_std::{ + convert::TryFrom, fmt, marker::PhantomData, ops::RangeBounds, prelude::*, vec::Drain, +}; /// A bounded vector. /// @@ -115,6 +117,14 @@ impl BoundedVec { self.0.remove(index) } + /// Exactly the same semantics as [`Vec::drain`]. + pub fn drain(&mut self, range: R) -> Drain<'_, T> + where + R: RangeBounds, + { + self.0.drain(range) + } + /// Exactly the same semantics as [`Vec::swap_remove`]. /// /// # Panics diff --git a/frame/support/src/storage/weak_bounded_vec.rs b/frame/support/src/storage/weak_bounded_vec.rs index 62f4567d71557..4cecee6b3fdb4 100644 --- a/frame/support/src/storage/weak_bounded_vec.rs +++ b/frame/support/src/storage/weak_bounded_vec.rs @@ -22,9 +22,9 @@ use crate::{ storage::{StorageDecodeLength, StorageTryAppend}, traits::Get, }; -use codec::{Decode, Encode, MaxEncodedLen}; +use codec::{alloc::vec::Drain, Decode, Encode, MaxEncodedLen}; use core::{ - ops::{Deref, Index, IndexMut}, + ops::{Deref, Index, IndexMut, RangeBounds}, slice::SliceIndex, }; use sp_std::{cmp::Ordering, convert::TryFrom, fmt, marker::PhantomData, prelude::*}; @@ -76,6 +76,14 @@ impl WeakBoundedVec { self.0.remove(index) } + /// Exactly the same semantics as [`Vec::drain`]. + pub fn drain(&mut self, range: R) -> Drain<'_, T> + where + R: RangeBounds, + { + self.0.drain(range) + } + /// Exactly the same semantics as [`Vec::truncate`]. /// /// # Panics From 8b4392a1bd091159f9d582c8cc74cc77bc5081c1 Mon Sep 17 00:00:00 2001 From: Georges Dib Date: Fri, 24 Sep 2021 20:57:07 +0100 Subject: [PATCH 14/80] Implementing `sort_by` on `WeakBoundedVec` --- frame/support/src/storage/weak_bounded_vec.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/frame/support/src/storage/weak_bounded_vec.rs b/frame/support/src/storage/weak_bounded_vec.rs index 4cecee6b3fdb4..19463ecb7e078 100644 --- a/frame/support/src/storage/weak_bounded_vec.rs +++ b/frame/support/src/storage/weak_bounded_vec.rs @@ -84,6 +84,14 @@ impl WeakBoundedVec { self.0.drain(range) } + /// Exactly the same semantics as [`Vec::sort_by`]. + pub fn sort_by(&mut self, compare: F) + where + F: FnMut(&T, &T) -> Ordering, + { + self.0.sort_by(compare); + } + /// Exactly the same semantics as [`Vec::truncate`]. /// /// # Panics From fc54a6631931648ab80246daaf20a6829f5d95b1 Mon Sep 17 00:00:00 2001 From: Georges Dib Date: Fri, 24 Sep 2021 21:03:38 +0100 Subject: [PATCH 15/80] Implement `entry` on `BoundedBTreeMap` --- frame/support/src/storage/bounded_btree_map.rs | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/frame/support/src/storage/bounded_btree_map.rs b/frame/support/src/storage/bounded_btree_map.rs index d0c0aa7c4f155..b60ac57c45bac 100644 --- a/frame/support/src/storage/bounded_btree_map.rs +++ b/frame/support/src/storage/bounded_btree_map.rs @@ -20,7 +20,11 @@ use crate::{storage::StorageDecodeLength, traits::Get}; use codec::{Decode, Encode, MaxEncodedLen}; use sp_std::{ - borrow::Borrow, collections::btree_map::BTreeMap, convert::TryFrom, fmt, marker::PhantomData, + borrow::Borrow, + collections::btree_map::{BTreeMap, Entry}, + convert::TryFrom, + fmt, + marker::PhantomData, ops::Deref, }; @@ -151,6 +155,15 @@ where { self.0.remove_entry(key) } + + /// Exactly the same semantics as [`BTreeMap::entry`] + /// Gets the given key's corresponding entry in the map for in-place manipulation. + pub fn entry(&mut self, key: K) -> Entry<'_, K, V> + where + K: Ord, + { + self.0.entry(key) + } } impl Default for BoundedBTreeMap From 8e358e5f702a78eb39bc15a23f4fa5dc3be208ea Mon Sep 17 00:00:00 2001 From: Georges Dib Date: Fri, 24 Sep 2021 21:57:20 +0100 Subject: [PATCH 16/80] Implement `last_mut` on `BoundedVec` --- frame/support/src/storage/bounded_vec.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/frame/support/src/storage/bounded_vec.rs b/frame/support/src/storage/bounded_vec.rs index 48bf12cbfc921..d29858f27269b 100644 --- a/frame/support/src/storage/bounded_vec.rs +++ b/frame/support/src/storage/bounded_vec.rs @@ -125,6 +125,11 @@ impl BoundedVec { self.0.drain(range) } + /// Exactly the same semantics as [`Vec::last_mut`]. + pub fn last_mut(&mut self) -> Option<&mut T> { + self.0.last_mut() + } + /// Exactly the same semantics as [`Vec::swap_remove`]. /// /// # Panics From 6f10ad36709a3cd6c587fb01e717ee4edec05ed7 Mon Sep 17 00:00:00 2001 From: Georges Dib Date: Fri, 24 Sep 2021 21:59:55 +0100 Subject: [PATCH 17/80] Implement `pop` on `BoundedVec` --- frame/support/src/storage/bounded_vec.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/frame/support/src/storage/bounded_vec.rs b/frame/support/src/storage/bounded_vec.rs index d29858f27269b..1f429f67d1672 100644 --- a/frame/support/src/storage/bounded_vec.rs +++ b/frame/support/src/storage/bounded_vec.rs @@ -117,6 +117,11 @@ impl BoundedVec { self.0.remove(index) } + /// Exactly the same semantics as [`Vec::pop`]. + pub fn pop(&mut self) -> Option { + self.0.pop() + } + /// Exactly the same semantics as [`Vec::drain`]. pub fn drain(&mut self, range: R) -> Drain<'_, T> where From d415c3bd416f2394e498117f9436e0be17ad3d12 Mon Sep 17 00:00:00 2001 From: Georges Dib Date: Sat, 25 Sep 2021 09:23:32 +0100 Subject: [PATCH 18/80] Implement `iter_mut` on `BoundedVec` --- frame/support/src/storage/bounded_vec.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/frame/support/src/storage/bounded_vec.rs b/frame/support/src/storage/bounded_vec.rs index 1f429f67d1672..0830c20f84242 100644 --- a/frame/support/src/storage/bounded_vec.rs +++ b/frame/support/src/storage/bounded_vec.rs @@ -26,7 +26,7 @@ use crate::{ use codec::{Decode, Encode, EncodeLike, MaxEncodedLen}; use core::{ ops::{Deref, Index, IndexMut}, - slice::SliceIndex, + slice::{IterMut, SliceIndex}, }; use sp_std::{ convert::TryFrom, fmt, marker::PhantomData, ops::RangeBounds, prelude::*, vec::Drain, @@ -135,6 +135,11 @@ impl BoundedVec { self.0.last_mut() } + /// Exactly the same semantics as [`Vec::iter_mut`] + pub fn iter_mut(&mut self) -> IterMut<'_, T> { + self.0.iter_mut() + } + /// Exactly the same semantics as [`Vec::swap_remove`]. /// /// # Panics From 4563cab2301f8a55e7f39ec1fac065d247aee6dd Mon Sep 17 00:00:00 2001 From: Georges Dib Date: Sat, 25 Sep 2021 09:25:30 +0100 Subject: [PATCH 19/80] Adding `storage_info` to pallet `staking` pallet compiles! --- .../src/benchmarking.rs | 6 +++--- frame/election-provider-multi-phase/src/lib.rs | 2 +- frame/election-provider-multi-phase/src/mock.rs | 2 +- frame/election-provider-support/src/lib.rs | 8 ++++---- frame/election-provider-support/src/onchain.rs | 2 +- frame/staking/src/pallet/impls.rs | 12 +++++++++--- frame/staking/src/pallet/mod.rs | 6 +++--- 7 files changed, 22 insertions(+), 16 deletions(-) diff --git a/frame/election-provider-multi-phase/src/benchmarking.rs b/frame/election-provider-multi-phase/src/benchmarking.rs index fb5adda52e166..13bce10229698 100644 --- a/frame/election-provider-multi-phase/src/benchmarking.rs +++ b/frame/election-provider-multi-phase/src/benchmarking.rs @@ -156,7 +156,7 @@ fn set_up_data_provider(v: u32, t: u32) { info, "setting up with voters = {} [degree = {}], targets = {}", v, - T::DataProvider::MAXIMUM_VOTES_PER_VOTER, + T::DataProvider::MaximumVotesPerVoter::get(), t ); @@ -169,8 +169,8 @@ fn set_up_data_provider(v: u32, t: u32) { }) .collect::>(); // we should always have enough voters to fill. - assert!(targets.len() > T::DataProvider::MAXIMUM_VOTES_PER_VOTER as usize); - targets.truncate(T::DataProvider::MAXIMUM_VOTES_PER_VOTER as usize); + assert!(targets.len() > T::DataProvider::MaximumVotesPerVoter::get() as usize); + targets.truncate(T::DataProvider::MaximumVotesPerVoter::get() as usize); // fill voters. (0..v).for_each(|i| { diff --git a/frame/election-provider-multi-phase/src/lib.rs b/frame/election-provider-multi-phase/src/lib.rs index e83c49433e2bb..2259c34e8d8e7 100644 --- a/frame/election-provider-multi-phase/src/lib.rs +++ b/frame/election-provider-multi-phase/src/lib.rs @@ -807,7 +807,7 @@ pub mod pallet { // NOTE that this pallet does not really need to enforce this in runtime. The // solution cannot represent any voters more than `LIMIT` anyhow. assert_eq!( - >::MAXIMUM_VOTES_PER_VOTER, + >::MaximumVotesPerVoter::get(), as NposSolution>::LIMIT as u32, ); } diff --git a/frame/election-provider-multi-phase/src/mock.rs b/frame/election-provider-multi-phase/src/mock.rs index 0d563955595a8..af92566ed49ad 100644 --- a/frame/election-provider-multi-phase/src/mock.rs +++ b/frame/election-provider-multi-phase/src/mock.rs @@ -421,7 +421,7 @@ pub struct ExtBuilder {} pub struct StakingMock; impl ElectionDataProvider for StakingMock { - const MAXIMUM_VOTES_PER_VOTER: u32 = ::LIMIT as u32; + type MaximumVotesPerVoter = ConstU32<::LIMIT as u32>; fn targets(maybe_max_len: Option) -> data_provider::Result> { let targets = Targets::get(); diff --git a/frame/election-provider-support/src/lib.rs b/frame/election-provider-support/src/lib.rs index cb36e025c3bee..5dc4acb0e3fbd 100644 --- a/frame/election-provider-support/src/lib.rs +++ b/frame/election-provider-support/src/lib.rs @@ -99,7 +99,7 @@ //! pub struct Module(std::marker::PhantomData); //! //! impl ElectionDataProvider for Module { -//! const MAXIMUM_VOTES_PER_VOTER: u32 = 1; +//! type MaximumVotesPerVoter = ConstU32<1>; //! fn desired_targets() -> data_provider::Result { //! Ok(1) //! } @@ -161,7 +161,7 @@ #![cfg_attr(not(feature = "std"), no_std)] pub mod onchain; -use frame_support::traits::Get; +use frame_support::{pallet_prelude::ConstU32, traits::Get}; use sp_std::{fmt::Debug, prelude::*}; /// Re-export some type as they are used in the interface. @@ -180,7 +180,7 @@ pub mod data_provider { /// Something that can provide the data to an [`ElectionProvider`]. pub trait ElectionDataProvider { /// Maximum number of votes per voter that this data provider is providing. - const MAXIMUM_VOTES_PER_VOTER: u32; + type MaximumVotesPerVoter: Get; /// All possible targets for the election, i.e. the candidates. /// @@ -249,7 +249,7 @@ pub trait ElectionDataProvider { #[cfg(feature = "std")] impl ElectionDataProvider for () { - const MAXIMUM_VOTES_PER_VOTER: u32 = 0; + type MaximumVotesPerVoter = ConstU32<0>; fn targets(_maybe_max_len: Option) -> data_provider::Result> { Ok(Default::default()) } diff --git a/frame/election-provider-support/src/onchain.rs b/frame/election-provider-support/src/onchain.rs index fb1ccfdfe2566..babc1b2c81c5e 100644 --- a/frame/election-provider-support/src/onchain.rs +++ b/frame/election-provider-support/src/onchain.rs @@ -160,7 +160,7 @@ mod tests { pub struct DataProvider; impl ElectionDataProvider for DataProvider { - const MAXIMUM_VOTES_PER_VOTER: u32 = 2; + type MaximumVotesPerVoter = ConstU32<2>; fn voters( _: Option, ) -> data_provider::Result)>> { diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index 806fad9e55ef2..985c20a70538c 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -869,7 +869,7 @@ impl Pallet { } impl ElectionDataProvider> for Pallet { - const MAXIMUM_VOTES_PER_VOTER: u32 = T::MaxNominations::get(); + type MaximumVotesPerVoter = T::MaxNominations; fn desired_targets() -> data_provider::Result { Self::register_weight(T::DbWeight::get().reads(1)); @@ -1251,7 +1251,7 @@ where add_db_reads_writes(rw, rw); } unapplied.reporters = WeakBoundedVec::<_, T::MaxNbOfReporters>::force_from( - details.reporters, + details.reporters.clone(), Some( "Warning: Number of reporters is bigger than expected. \ A runtime parameter adjustment may be needed.", @@ -1271,7 +1271,13 @@ where } else { // Defer to end of some `slash_defer_duration` from now. ::UnappliedSlashes::mutate(active_era, move |for_later| { - for_later.push(unapplied) + for_later.force_push( + unapplied, + Some( + "Warning: More unapplied stashes than expected. \ + A runtime parameter adjustment may be needed.", + ), + ) }); add_db_reads_writes(1, 1); } diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index da7c9ed0b7f2e..b72126e0b55df 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -97,7 +97,7 @@ pub mod pallet { /// Maximum number of nominations per nominator. #[pallet::constant] - type MaxNominations: Get; + type MaxNominations: Get; /// Tokens have been minted and are unused for validator-reward. /// See [Era payout](./index.html#era-payout). @@ -556,7 +556,7 @@ pub mod pallet { MinValidatorBond::::put(self.min_validator_bond); let invulnerables = BoundedVec::<_, T::MaxNbOfInvulnerables>::try_from( - self.invulnerables, + self.invulnerables.clone(), ) .expect("Too many invulnerables passed, a runtime parameters adjustment may be needed"); Invulnerables::::put(&invulnerables); @@ -927,7 +927,7 @@ pub mod pallet { ledger .unlocking .try_push(UnlockChunk { value, era }) - .map_err(|_| Error::::NoMoreChunks); + .map_err(|_| Error::::NoMoreChunks)?; // NOTE: ledger must be updated prior to calling `Self::weight_of`. Self::update_ledger(&controller, &ledger); From 7d6c9b69f0cbddff30f0a56fc7c7c37accfddea4 Mon Sep 17 00:00:00 2001 From: Georges Dib Date: Sat, 25 Sep 2021 17:11:03 +0100 Subject: [PATCH 20/80] Radical change: moving `MaxValidatorsCount` from storage to being a runtime parameter `MaxNbOfValidators` Fixing various other compile errors --- bin/node/runtime/src/lib.rs | 18 ++- frame/election-provider-support/src/lib.rs | 5 +- frame/offences/benchmarking/src/lib.rs | 19 ++- frame/session/benchmarking/src/lib.rs | 10 +- frame/staking/src/benchmarking.rs | 40 +++--- frame/staking/src/lib.rs | 136 +++++++++++++----- frame/staking/src/pallet/impls.rs | 36 +++-- frame/staking/src/pallet/mod.rs | 32 ++--- frame/staking/src/slashing.rs | 2 +- frame/staking/src/tests.rs | 8 +- frame/staking/src/weights.rs | 12 +- .../support/src/storage/bounded_btree_map.rs | 4 +- 12 files changed, 203 insertions(+), 119 deletions(-) diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 28f8e5dc3fd6a..4cd02c2f7f6e5 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -474,7 +474,8 @@ impl pallet_session::Config for Runtime { } impl pallet_session::historical::Config for Runtime { - type FullIdentification = pallet_staking::Exposure; + type FullIdentification = + pallet_staking::Exposure; type FullIdentificationOf = pallet_staking::ExposureOf; } @@ -496,6 +497,13 @@ parameter_types! { pub const RewardCurve: &'static PiecewiseLinear<'static> = &REWARD_CURVE; pub const MaxNominatorRewardedPerValidator: u32 = 256; pub OffchainRepeat: BlockNumber = 5; + pub const MaxNominations: u32 = MAX_NOMINATIONS; + pub const MaxUnappliedSlashes: u32 = 1_000; + pub const MaxNbOfInvulnerables: u32 = 10; + pub const MaxErasForRewards: u32 = 10_000; + pub const MaxNbOfReporters: u32 = 1_000; + pub const MaxPriorSlashingSpans: u32 = 1_000; + pub const MaxNbOfValidators: u32 = 4_000; } use frame_election_provider_support::onchain; @@ -505,7 +513,6 @@ impl onchain::Config for Runtime { } impl pallet_staking::Config for Runtime { - const MAX_NOMINATIONS: u32 = MAX_NOMINATIONS; type Currency = Balances; type UnixTime = Timestamp; type CurrencyToVote = U128CurrencyToVote; @@ -532,6 +539,13 @@ impl pallet_staking::Config for Runtime { // Note that the aforementioned does not scale to a very large number of nominators. type SortedListProvider = BagsList; type WeightInfo = pallet_staking::weights::SubstrateWeight; + type MaxNominations = MaxNominations; + type MaxUnappliedSlashes = MaxUnappliedSlashes; + type MaxNbOfInvulnerables = MaxNbOfInvulnerables; + type MaxErasForRewards = MaxErasForRewards; + type MaxNbOfReporters = MaxNbOfReporters; + type MaxPriorSlashingSpans = MaxPriorSlashingSpans; + type MaxNbOfValidators = MaxNbOfValidators; } parameter_types! { diff --git a/frame/election-provider-support/src/lib.rs b/frame/election-provider-support/src/lib.rs index 5dc4acb0e3fbd..9954deb036f84 100644 --- a/frame/election-provider-support/src/lib.rs +++ b/frame/election-provider-support/src/lib.rs @@ -161,7 +161,7 @@ #![cfg_attr(not(feature = "std"), no_std)] pub mod onchain; -use frame_support::{pallet_prelude::ConstU32, traits::Get}; +use frame_support::traits::Get; use sp_std::{fmt::Debug, prelude::*}; /// Re-export some type as they are used in the interface. @@ -171,6 +171,9 @@ pub use sp_npos_elections::{ VoteWeight, }; +#[cfg(feature = "std")] +use frame_support::pallet_prelude::ConstU32; + /// Types that are used by the data provider trait. pub mod data_provider { /// Alias for the result type of the election data provider. diff --git a/frame/offences/benchmarking/src/lib.rs b/frame/offences/benchmarking/src/lib.rs index 35e3c1aec9403..5d860b0a4729d 100644 --- a/frame/offences/benchmarking/src/lib.rs +++ b/frame/offences/benchmarking/src/lib.rs @@ -21,10 +21,13 @@ mod mock; -use sp_std::{prelude::*, vec}; +use sp_std::{convert::TryFrom, prelude::*, vec}; use frame_benchmarking::{account, benchmarks, impl_benchmark_test_suite}; -use frame_support::traits::{Currency, ValidatorSet, ValidatorSetWithIdentification}; +use frame_support::{ + traits::{Currency, Get, ValidatorSet, ValidatorSetWithIdentification}, + WeakBoundedVec, +}; use frame_system::{Config as SystemConfig, Pallet as System, RawOrigin}; use sp_runtime::{ @@ -147,8 +150,10 @@ fn create_offender(n: u32, nominators: u32) -> Result, &' nominator_stashes.push(nominator_stash.clone()); } - let exposure = - Exposure { total: amount.clone() * n.into(), own: amount, others: individual_exposures }; + let others = + WeakBoundedVec::<_, T::MaxNominatorRewardedPerValidator>::try_from(individual_exposures) + .expect("nominators too big, runtime benchmarks may need adjustment"); + let exposure = Exposure { total: amount.clone() * n.into(), own: amount, others }; let current_era = 0u32; Staking::::add_era_stakers(current_era.into(), stash.clone().into(), exposure); @@ -253,7 +258,7 @@ benchmarks! { let r in 1 .. MAX_REPORTERS; // we skip 1 offender, because in such case there is no slashing let o in 2 .. MAX_OFFENDERS; - let n in 0 .. MAX_NOMINATORS.min(::MAX_NOMINATIONS); + let n in 0 .. MAX_NOMINATORS.min(::MaxNominations::get()); // Make r reporters let mut reporters = vec![]; @@ -331,7 +336,7 @@ benchmarks! { } report_offence_grandpa { - let n in 0 .. MAX_NOMINATORS.min(::MAX_NOMINATIONS); + let n in 0 .. MAX_NOMINATORS.min(::MaxNominations::get()); // for grandpa equivocation reports the number of reporters // and offenders is always 1 @@ -366,7 +371,7 @@ benchmarks! { } report_offence_babe { - let n in 0 .. MAX_NOMINATORS.min(::MAX_NOMINATIONS); + let n in 0 .. MAX_NOMINATORS.min(::MaxNominations::get()); // for babe equivocation reports the number of reporters // and offenders is always 1 diff --git a/frame/session/benchmarking/src/lib.rs b/frame/session/benchmarking/src/lib.rs index 8b84145c1acfd..9dcbe1033867f 100644 --- a/frame/session/benchmarking/src/lib.rs +++ b/frame/session/benchmarking/src/lib.rs @@ -27,7 +27,7 @@ use sp_std::{prelude::*, vec}; use frame_benchmarking::{benchmarks, impl_benchmark_test_suite}; use frame_support::{ codec::Decode, - traits::{KeyOwnerProofSystem, OnInitialize}, + traits::{Get, KeyOwnerProofSystem, OnInitialize}, }; use frame_system::RawOrigin; use pallet_session::{historical::Module as Historical, Module as Session, *}; @@ -53,10 +53,10 @@ impl OnInitialize for Pallet { benchmarks! { set_keys { - let n = ::MAX_NOMINATIONS; + let n = ::MaxNominations::get(); let (v_stash, _) = create_validator_with_nominators::( n, - ::MAX_NOMINATIONS, + ::MaxNominations::get(), false, RewardDestination::Staked, )?; @@ -69,10 +69,10 @@ benchmarks! { }: _(RawOrigin::Signed(v_controller), keys, proof) purge_keys { - let n = ::MAX_NOMINATIONS; + let n = ::MaxNominations::get(); let (v_stash, _) = create_validator_with_nominators::( n, - ::MAX_NOMINATIONS, + ::MaxNominations::get(), false, RewardDestination::Staked )?; diff --git a/frame/staking/src/benchmarking.rs b/frame/staking/src/benchmarking.rs index 64fe158fcbfa3..5766429aba072 100644 --- a/frame/staking/src/benchmarking.rs +++ b/frame/staking/src/benchmarking.rs @@ -31,7 +31,7 @@ use sp_runtime::{ Perbill, Percent, }; use sp_staking::SessionIndex; -use sp_std::prelude::*; +use sp_std::{collections::btree_map::BTreeMap, prelude::*}; pub use frame_benchmarking::{ account, benchmarks, impl_benchmark_test_suite, whitelist_account, whitelisted_caller, @@ -115,10 +115,12 @@ pub fn create_validator_with_nominators( assert_ne!(CounterForNominators::::get(), 0); // Give Era Points - let reward = EraRewardPoints:: { - total: points_total, - individual: points_individual.into_iter().collect(), - }; + let individual = BoundedBTreeMap::<_, _, T::MaxNbOfValidators>::try_from( + points_individual.into_iter().collect::>(), + ) + .map_err(|_| "Something weird, this means T:MaxNbOfValidators is zero")?; + let reward = + EraRewardPoints:: { total: points_total, individual }; let current_era = CurrentEra::::get().unwrap(); ErasRewardPoints::::insert(current_era, reward); @@ -536,8 +538,11 @@ benchmarks! { let mut unapplied_slashes = Vec::new(); let era = EraIndex::one(); for _ in 0 .. MAX_SLASHES { - unapplied_slashes.push(UnappliedSlash::>::default()); + unapplied_slashes.push(UnappliedSlash::, T::MaxNominatorRewardedPerValidator, + T::MaxNbOfReporters>::default()); } + let unapplied_slashes = WeakBoundedVec::<_, T::MaxUnappliedSlashes>::try_from(unapplied_slashes) + .expect("MAX_SLASHES should be <= MaxUnappliedSlashes, runtime benchmarks need adjustment"); UnappliedSlashes::::insert(era, &unapplied_slashes); let slash_indices: Vec = (0 .. s).collect(); @@ -650,7 +655,8 @@ benchmarks! { let mut staking_ledger = Ledger::::get(controller.clone()).unwrap(); for _ in 0 .. l { - staking_ledger.unlocking.push(unlock_chunk.clone()) + staking_ledger.unlocking.try_push(unlock_chunk.clone()) + .expect("Size is smaller than MAX_UNLOCKING_CHUNKS, qed"); } Ledger::::insert(controller.clone(), staking_ledger.clone()); let original_bonded: BalanceOf = staking_ledger.active; @@ -668,11 +674,11 @@ benchmarks! { HistoryDepth::::put(e); 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(), Exposure::default()); >::insert(i, T::AccountId::default(), ValidatorPrefs::default()); >::insert(i, BalanceOf::::one()); - >::insert(i, EraRewardPoints::::default()); + >::insert(i, EraRewardPoints::default()); >::insert(i, BalanceOf::::one()); ErasStartSessionIndex::::insert(i, i); } @@ -752,9 +758,13 @@ benchmarks! { } // Give Era Points - let reward = EraRewardPoints:: { + let individual = BoundedBTreeMap::<_, _, T::MaxNbOfValidators>::try_from( + points_individual.into_iter().collect::>(), + ) + .map_err(|_| "Too many validators, some runtime benchmarks may need adjustment")?; + let reward = EraRewardPoints { total: points_total, - individual: points_individual.into_iter().collect(), + individual, }; ErasRewardPoints::::insert(current_era, reward); @@ -780,7 +790,8 @@ benchmarks! { era: EraIndex::zero(), }; for _ in 0 .. l { - staking_ledger.unlocking.push(unlock_chunk.clone()) + staking_ledger.unlocking.try_push(unlock_chunk.clone()) + .expect("Size is smaller than MAX_UNLOCKING_CHUNKS, qed"); } Ledger::::insert(controller, staking_ledger); let slash_amount = T::Currency::minimum_balance() * 10u32.into(); @@ -843,13 +854,11 @@ benchmarks! { BalanceOf::::max_value(), BalanceOf::::max_value(), Some(u32::MAX), - Some(u32::MAX), Some(Percent::max_value()) ) verify { assert_eq!(MinNominatorBond::::get(), BalanceOf::::max_value()); assert_eq!(MinValidatorBond::::get(), BalanceOf::::max_value()); assert_eq!(MaxNominatorsCount::::get(), Some(u32::MAX)); - assert_eq!(MaxValidatorsCount::::get(), Some(u32::MAX)); assert_eq!(ChillThreshold::::get(), Some(Percent::from_percent(100))); } @@ -871,7 +880,6 @@ benchmarks! { BalanceOf::::max_value(), BalanceOf::::max_value(), Some(0), - Some(0), Some(Percent::from_percent(0)) )?; diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index 2d8824e779eef..341cf5635d744 100644 --- a/frame/staking/src/lib.rs +++ b/frame/staking/src/lib.rs @@ -304,7 +304,8 @@ use frame_support::{ storage::bounded_btree_map::BoundedBTreeMap, traits::{Currency, Get}, weights::Weight, - BoundedVec, WeakBoundedVec, + BoundedVec, CloneNoBound, DefaultNoBound, EqNoBound, PartialEqNoBound, RuntimeDebugNoBound, + WeakBoundedVec, }; use scale_info::TypeInfo; use sp_runtime::{ @@ -317,7 +318,9 @@ use sp_staking::{ SessionIndex, }; use sp_std::{ + cmp::Ordering, convert::{From, TryFrom}, + fmt, prelude::*, }; pub use weights::WeightInfo; @@ -370,12 +373,12 @@ pub struct ActiveEraInfo { /// /// This points will be used to reward validators and their respective nominators. /// `Limit` bounds the number of points earned by a given validator -#[derive(PartialEq, Encode, Decode, RuntimeDebug, TypeInfo, MaxEncodedLen)] +#[derive(PartialEq, Encode, Decode, DefaultNoBound, RuntimeDebug, TypeInfo, MaxEncodedLen)] #[scale_info(skip_type_params(Limit))] #[codec(mel_bound(Limit: Get))] pub struct EraRewardPoints where - AccountId: Ord + MaxEncodedLen, + AccountId: Ord + MaxEncodedLen + Default, Limit: Get, { /// Total number of points. Equals the sum of reward points for each validator. @@ -384,16 +387,6 @@ where individual: BoundedBTreeMap, } -impl Default for EraRewardPoints -where - AccountId: Ord + MaxEncodedLen, - Limit: Get, -{ - fn default() -> Self { - Self { total: RewardPoint::default(), individual: BoundedBTreeMap::default() } - } -} - /// Indicates the initial status of the staker. #[derive(RuntimeDebug, TypeInfo)] #[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))] @@ -460,17 +453,15 @@ pub struct UnlockChunk { /// The ledger of a (bonded) stash. /// `UnlockingLimit` is the size limit of the `WeakBoundedVec` representing `unlocking` /// `RewardsLimit` is the size limit of the `WeakBoundedVec` representing `claimed_rewards` -#[cfg_attr(feature = "runtime-benchmarks", derive(Default))] -#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, TypeInfo, MaxEncodedLen)] +#[derive(PartialEq, Eq, Encode, Decode, RuntimeDebug, TypeInfo, MaxEncodedLen)] #[codec(mel_bound(UnlockingLimit: Get, RewardsLimit: Get))] #[scale_info(skip_type_params(UnlockingLimit, RewardsLimit))] pub struct StakingLedger where - Balance: HasCompact, + Balance: HasCompact + MaxEncodedLen, UnlockingLimit: Get, RewardsLimit: Get, AccountId: MaxEncodedLen, - Balance: MaxEncodedLen, { /// The stash account whose balance is actually locked and at stake. pub stash: AccountId, @@ -490,6 +481,45 @@ where pub claimed_rewards: WeakBoundedVec, } +#[cfg(feature = "runtime-benchmarks")] +impl Default + for StakingLedger +where + Balance: HasCompact + MaxEncodedLen + Default, + AccountId: MaxEncodedLen + Default, + UnlockingLimit: Get, + RewardsLimit: Get, +{ + fn default() -> Self { + Self { + stash: AccountId::default(), + total: Balance::default(), + active: Balance::default(), + unlocking: BoundedVec::default(), + claimed_rewards: WeakBoundedVec::default(), + } + } +} + +impl Clone + for StakingLedger +where + Balance: HasCompact + MaxEncodedLen + Clone, + AccountId: MaxEncodedLen + Clone, + UnlockingLimit: Get, + RewardsLimit: Get, +{ + fn clone(&self) -> Self { + Self { + stash: self.stash.clone(), + total: self.total.clone(), + active: self.active.clone(), + unlocking: self.unlocking.clone(), + claimed_rewards: self.claimed_rewards.clone(), + } + } +} + impl StakingLedger where @@ -647,13 +677,23 @@ pub struct IndividualExposure { /// A snapshot of the stake backing a single validator in the system. /// `Limit` is the size limit of `others` bounded by `MaxNominatorRewardedPerValidator` -#[derive(PartialEq, Eq, PartialOrd, Ord, Encode, Decode, RuntimeDebug, TypeInfo, MaxEncodedLen)] +#[derive( + PartialEqNoBound, + EqNoBound, + Encode, + Decode, + CloneNoBound, + DefaultNoBound, + RuntimeDebugNoBound, + TypeInfo, + MaxEncodedLen, +)] #[scale_info(skip_type_params(Limit))] #[codec(mel_bound(Limit: Get, Balance: HasCompact))] pub struct Exposure where - AccountId: MaxEncodedLen, - Balance: HasCompact + MaxEncodedLen, + AccountId: MaxEncodedLen + Eq + Default + Clone + fmt::Debug, + Balance: HasCompact + MaxEncodedLen + Eq + Default + Clone + fmt::Debug, Limit: Get, { /// The total balance backing this validator. @@ -666,39 +706,40 @@ where pub others: WeakBoundedVec, Limit>, } -// NOTE: maybe use derivative to avoid this -impl Default for Exposure +impl PartialOrd for Exposure where - AccountId: MaxEncodedLen, - Balance: HasCompact + MaxEncodedLen + Default, + AccountId: MaxEncodedLen + Eq + Default + Clone + Ord + fmt::Debug, + Balance: HasCompact + MaxEncodedLen + Eq + Default + Clone + Ord + fmt::Debug, Limit: Get, { - fn default() -> Self { - Self { - total: Balance::default(), - own: Balance::default(), - others: WeakBoundedVec::default(), - } + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) } } -impl Clone for Exposure +impl Ord for Exposure where - AccountId: MaxEncodedLen, - Balance: HasCompact + MaxEncodedLen + Clone, + AccountId: MaxEncodedLen + Eq + Default + Clone + Ord + fmt::Debug, + Balance: HasCompact + MaxEncodedLen + Eq + Default + Clone + Ord + fmt::Debug, Limit: Get, - WeakBoundedVec, Limit>: Clone, { - fn clone(&self) -> Self { - Self { total: self.total.clone(), own: self.own.clone(), others: self.others.clone() } + fn cmp(&self, other: &Self) -> Ordering { + let mut result = Ord::cmp(&self.total, &other.total); + if result == Ordering::Equal { + result = Ord::cmp(&self.own, &other.own); + if result == Ordering::Equal { + return Ord::cmp(&self.others, &other.others) + } + } + return result } } /// A pending slash record. The value of the slash has been computed but not applied yet, /// rather deferred for several eras. -/// `SlahedLimit` bounds the number of slashed accounts +/// `SlashedLimit` bounds the number of slashed accounts /// `ReportersLimit` bounds the number of reporters -#[derive(Encode, Decode, Default, RuntimeDebug, TypeInfo, MaxEncodedLen)] +#[derive(Encode, Decode, RuntimeDebug, TypeInfo, MaxEncodedLen)] #[codec(mel_bound(SlashedLimit: Get, ReportersLimit: Get))] #[scale_info(skip_type_params(SlashedLimit, ReportersLimit))] pub struct UnappliedSlash @@ -720,6 +761,25 @@ where payout: Balance, } +impl Default + for UnappliedSlash +where + Balance: HasCompact + MaxEncodedLen + Default, + AccountId: MaxEncodedLen + Default, + SlashedLimit: Get, + ReportersLimit: Get, +{ + fn default() -> Self { + Self { + validator: AccountId::default(), + own: Balance::default(), + others: WeakBoundedVec::default(), + reporters: WeakBoundedVec::default(), + payout: Balance::default(), + } + } +} + /// Means for interacting with a specialized version of the `session` trait. /// /// This is needed because `Staking` sets the `ValidatorIdOf` of the `pallet_session::Config` diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index 985c20a70538c..dcff4f370371a 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -653,7 +653,7 @@ impl Pallet { pub fn add_era_stakers( current_era: EraIndex, controller: T::AccountId, - exposure: Exposure>, + exposure: Exposure, T::MaxNominatorRewardedPerValidator>, ) { >::insert(¤t_era, &controller, &exposure); } @@ -938,6 +938,10 @@ impl ElectionDataProvider> for Pallet ) } + /// # Panic + /// + /// Panics if `targets` size is bigger than T::MaxNominations. + /// Or if it cannot convert `weight` into a `BalanceOf` #[cfg(feature = "runtime-benchmarks")] fn add_voter(voter: T::AccountId, weight: VoteWeight, targets: Vec) { use sp_std::convert::TryFrom; @@ -951,10 +955,13 @@ impl ElectionDataProvider> for Pallet stash: voter.clone(), active: stake, total: stake, - unlocking: vec![], - claimed_rewards: vec![], + unlocking: BoundedVec::default(), + claimed_rewards: WeakBoundedVec::default(), }, ); + + let targets = BoundedVec::<_, T::MaxNominations>::try_from(targets) + .expect("targets Vec length too large, benchmark needs reconfiguring"); Self::do_add_nominator(&voter, Nominations { targets, submitted_in: 0, suppressed: false }); } @@ -968,8 +975,8 @@ impl ElectionDataProvider> for Pallet stash: target.clone(), active: stake, total: stake, - unlocking: vec![], - claimed_rewards: vec![], + unlocking: BoundedVec::default(), + claimed_rewards: WeakBoundedVec::default(), }, ); Self::do_add_validator( @@ -989,6 +996,10 @@ impl ElectionDataProvider> for Pallet let _ = T::SortedListProvider::clear(None); } + /// # Panic + /// + /// Panics if `voters` 3rd element is larger than T::MaxNominations. + /// Or if the 2nd element cannot be converted into a `BalanceOf` #[cfg(feature = "runtime-benchmarks")] fn put_snapshot( voters: Vec<(T::AccountId, VoteWeight, Vec)>, @@ -1007,8 +1018,8 @@ impl ElectionDataProvider> for Pallet stash: v.clone(), active: stake, total: stake, - unlocking: vec![], - claimed_rewards: vec![], + unlocking: BoundedVec::default(), + claimed_rewards: WeakBoundedVec::default(), }, ); Self::do_add_validator( @@ -1028,14 +1039,13 @@ impl ElectionDataProvider> for Pallet stash: v.clone(), active: stake, total: stake, - unlocking: vec![], - claimed_rewards: vec![], + unlocking: BoundedVec::default(), + claimed_rewards: WeakBoundedVec::default(), }, ); - Self::do_add_nominator( - &v, - Nominations { targets: t, submitted_in: 0, suppressed: false }, - ); + let targets = BoundedVec::<_, T::MaxNominations>::try_from(t) + .expect("targets vec too large, benchmark needs reconfiguring."); + Self::do_add_nominator(&v, Nominations { targets, submitted_in: 0, suppressed: false }); }); } } diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index b72126e0b55df..3ef5ed78ba10a 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -271,12 +271,6 @@ pub mod pallet { #[pallet::storage] pub type CounterForValidators = StorageValue<_, u32, ValueQuery>; - /// The maximum validator count before we stop allowing new validators to join. - /// - /// When this value is not set, no limits are enforced. - #[pallet::storage] - pub type MaxValidatorsCount = StorageValue<_, u32, OptionQuery>; - /// The map from nominator stash key to the set of stash keys of all validators to nominate. /// /// When updating this storage item, you must also update the `CounterForNominators`. @@ -289,7 +283,7 @@ pub mod pallet { #[pallet::storage] pub type CounterForNominators = StorageValue<_, u32, ValueQuery>; - /// The maximum nominator count before we stop allowing new validators to join. + /// The maximum nominator count before we stop allowing new nominators to join. /// /// When this value is not set, no limits are enforced. #[pallet::storage] @@ -555,10 +549,11 @@ pub mod pallet { MinNominatorBond::::put(self.min_nominator_bond); MinValidatorBond::::put(self.min_validator_bond); - let invulnerables = BoundedVec::<_, T::MaxNbOfInvulnerables>::try_from( - self.invulnerables.clone(), - ) - .expect("Too many invulnerables passed, a runtime parameters adjustment may be needed"); + let invulnerables = + BoundedVec::<_, T::MaxNbOfInvulnerables>::try_from(self.invulnerables.clone()) + .expect( + "Too many invulnerables passed, a runtime parameters adjustment may be needed", + ); Invulnerables::::put(&invulnerables); for &(ref stash, ref controller, balance, ref status) in &self.stakers { @@ -1016,12 +1011,10 @@ pub mod pallet { // If this error is reached, we need to adjust the `MinValidatorBond` and start // calling `chill_other`. Until then, we explicitly block new validators to protect // the runtime. - if let Some(max_validators) = MaxValidatorsCount::::get() { - ensure!( - CounterForValidators::::get() < max_validators, - Error::::TooManyValidators - ); - } + ensure!( + CounterForValidators::::get() < T::MaxNbOfValidators::get(), + Error::::TooManyValidators + ); } Self::do_remove_nominator(stash); @@ -1580,14 +1573,12 @@ pub mod pallet { min_nominator_bond: BalanceOf, min_validator_bond: BalanceOf, max_nominator_count: Option, - max_validator_count: Option, threshold: Option, ) -> DispatchResult { ensure_root(origin)?; MinNominatorBond::::set(min_nominator_bond); MinValidatorBond::::set(min_validator_bond); MaxNominatorsCount::::set(max_nominator_count); - MaxValidatorsCount::::set(max_validator_count); ChillThreshold::::set(threshold); Ok(()) } @@ -1642,8 +1633,7 @@ pub mod pallet { ); MinNominatorBond::::get() } else if Validators::::contains_key(&stash) { - let max_validator_count = - MaxValidatorsCount::::get().ok_or(Error::::CannotChillOther)?; + let max_validator_count = T::MaxNbOfValidators::get(); let current_validator_count = CounterForValidators::::get(); ensure!( threshold * max_validator_count < current_validator_count, diff --git a/frame/staking/src/slashing.rs b/frame/staking/src/slashing.rs index b4340cf1691fb..261f451b5825d 100644 --- a/frame/staking/src/slashing.rs +++ b/frame/staking/src/slashing.rs @@ -51,7 +51,7 @@ use crate::{ BalanceOf, Config, EraIndex, Error, Exposure, Get, NegativeImbalanceOf, Pallet, Perbill, - SessionInterface, Store, UnappliedSlash, + SessionInterface, Store, UnappliedSlash, Vec, }; use codec::{Decode, Encode, MaxEncodedLen}; use frame_support::{ diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index 5e7fe3d6266aa..e902a6de315cd 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -4187,7 +4187,7 @@ fn chill_other_works() { ); // Change the minimum bond... but no limits. - assert_ok!(Staking::set_staking_limits(Origin::root(), 1_500, 2_000, None, None, None)); + assert_ok!(Staking::set_staking_limits(Origin::root(), 1_500, 2_000, None, None)); // Still can't chill these users assert_noop!( @@ -4205,7 +4205,6 @@ fn chill_other_works() { 1_500, 2_000, Some(10), - Some(10), None )); @@ -4225,7 +4224,6 @@ fn chill_other_works() { 1_500, 2_000, None, - None, Some(Percent::from_percent(0)) )); @@ -4245,7 +4243,6 @@ fn chill_other_works() { 1_500, 2_000, Some(10), - Some(10), Some(Percent::from_percent(75)) )); @@ -4289,7 +4286,6 @@ fn capped_stakers_works() { 10, 10, Some(max), - Some(max), Some(Percent::from_percent(0)) )); @@ -4353,7 +4349,7 @@ fn capped_stakers_works() { )); // No problem when we set to `None` again - assert_ok!(Staking::set_staking_limits(Origin::root(), 10, 10, None, None, None)); + assert_ok!(Staking::set_staking_limits(Origin::root(), 10, 10, None, None)); assert_ok!(Staking::nominate(Origin::signed(last_nominator), vec![1])); assert_ok!(Staking::validate(Origin::signed(last_validator), ValidatorPrefs::default())); }) diff --git a/frame/staking/src/weights.rs b/frame/staking/src/weights.rs index 32c8dc80da158..6524bc9684a97 100644 --- a/frame/staking/src/weights.rs +++ b/frame/staking/src/weights.rs @@ -145,7 +145,6 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking Ledger (r:1 w:0) // Storage: Staking MinValidatorBond (r:1 w:0) // Storage: Staking Validators (r:1 w:1) - // Storage: Staking MaxValidatorsCount (r:1 w:0) // Storage: Staking Nominators (r:1 w:1) // Storage: Staking CounterForNominators (r:1 w:1) // Storage: BagsList ListNodes (r:2 w:2) @@ -154,7 +153,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking CounterForValidators (r:1 w:1) fn validate() -> Weight { (69_092_000 as Weight) - .saturating_add(T::DbWeight::get().reads(11 as Weight)) + .saturating_add(T::DbWeight::get().reads(10 as Weight)) .saturating_add(T::DbWeight::get().writes(8 as Weight)) } // Storage: Staking Ledger (r:1 w:0) @@ -419,13 +418,12 @@ impl WeightInfo for SubstrateWeight { .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(v as Weight))) } // Storage: Staking MinValidatorBond (r:0 w:1) - // Storage: Staking MaxValidatorsCount (r:0 w:1) // Storage: Staking ChillThreshold (r:0 w:1) // Storage: Staking MaxNominatorsCount (r:0 w:1) // Storage: Staking MinNominatorBond (r:0 w:1) fn set_staking_limits() -> Weight { (6_353_000 as Weight) - .saturating_add(T::DbWeight::get().writes(5 as Weight)) + .saturating_add(T::DbWeight::get().writes(4 as Weight)) } // Storage: Staking Ledger (r:1 w:0) // Storage: Staking ChillThreshold (r:1 w:0) @@ -513,7 +511,6 @@ impl WeightInfo for () { // Storage: Staking Ledger (r:1 w:0) // Storage: Staking MinValidatorBond (r:1 w:0) // Storage: Staking Validators (r:1 w:1) - // Storage: Staking MaxValidatorsCount (r:1 w:0) // Storage: Staking Nominators (r:1 w:1) // Storage: Staking CounterForNominators (r:1 w:1) // Storage: BagsList ListNodes (r:2 w:2) @@ -522,7 +519,7 @@ impl WeightInfo for () { // Storage: Staking CounterForValidators (r:1 w:1) fn validate() -> Weight { (69_092_000 as Weight) - .saturating_add(RocksDbWeight::get().reads(11 as Weight)) + .saturating_add(RocksDbWeight::get().reads(10 as Weight)) .saturating_add(RocksDbWeight::get().writes(8 as Weight)) } // Storage: Staking Ledger (r:1 w:0) @@ -787,13 +784,12 @@ impl WeightInfo for () { .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(v as Weight))) } // Storage: Staking MinValidatorBond (r:0 w:1) - // Storage: Staking MaxValidatorsCount (r:0 w:1) // Storage: Staking ChillThreshold (r:0 w:1) // Storage: Staking MaxNominatorsCount (r:0 w:1) // Storage: Staking MinNominatorBond (r:0 w:1) fn set_staking_limits() -> Weight { (6_353_000 as Weight) - .saturating_add(RocksDbWeight::get().writes(5 as Weight)) + .saturating_add(RocksDbWeight::get().writes(4 as Weight)) } // Storage: Staking Ledger (r:1 w:0) // Storage: Staking ChillThreshold (r:1 w:0) diff --git a/frame/support/src/storage/bounded_btree_map.rs b/frame/support/src/storage/bounded_btree_map.rs index b60ac57c45bac..244391f26cd13 100644 --- a/frame/support/src/storage/bounded_btree_map.rs +++ b/frame/support/src/storage/bounded_btree_map.rs @@ -23,11 +23,13 @@ use sp_std::{ borrow::Borrow, collections::btree_map::{BTreeMap, Entry}, convert::TryFrom, - fmt, marker::PhantomData, ops::Deref, }; +#[cfg(feature = "std")] +use sp_std::fmt; + /// A bounded map based on a B-Tree. /// /// B-Trees represent a fundamental compromise between cache-efficiency and actually minimizing From 243e0386ec55aa945b1562372bd3f15b9c1b450a Mon Sep 17 00:00:00 2001 From: Georges Dib Date: Sat, 25 Sep 2021 17:30:31 +0100 Subject: [PATCH 21/80] Cleanups --- frame/staking/src/slashing.rs | 17 ++--------------- frame/support/src/storage/bounded_btree_map.rs | 3 --- frame/support/src/storage/bounded_vec.rs | 2 +- frame/support/src/storage/weak_bounded_vec.rs | 2 +- 4 files changed, 4 insertions(+), 20 deletions(-) diff --git a/frame/staking/src/slashing.rs b/frame/staking/src/slashing.rs index 261f451b5825d..5f62566f02068 100644 --- a/frame/staking/src/slashing.rs +++ b/frame/staking/src/slashing.rs @@ -57,7 +57,7 @@ use codec::{Decode, Encode, MaxEncodedLen}; use frame_support::{ ensure, traits::{Currency, Imbalance, OnUnbalanced}, - WeakBoundedVec, + CloneNoBound, WeakBoundedVec, }; use scale_info::TypeInfo; use sp_runtime::{ @@ -207,6 +207,7 @@ impl SpanRecord { } /// Parameters for performing a slash. +#[derive(CloneNoBound)] pub(crate) struct SlashParams<'a, T: 'a + Config> { /// The stash account being slashed. pub(crate) stash: &'a T::AccountId, @@ -226,20 +227,6 @@ pub(crate) struct SlashParams<'a, T: 'a + Config> { pub(crate) reward_proportion: Perbill, } -impl<'a, T: 'a + Config> Clone for SlashParams<'a, T> { - fn clone(&self) -> Self { - Self { - stash: self.stash, - slash: self.slash.clone(), - exposure: self.exposure, - slash_era: self.slash_era.clone(), - window_start: self.window_start.clone(), - now: self.now.clone(), - reward_proportion: self.reward_proportion.clone(), - } - } -} - /// Computes a slash of a validator and nominators. It returns an unapplied /// record to be applied at some later point. Slashing metadata is updated in storage, /// since unapplied records are only rarely intended to be dropped. diff --git a/frame/support/src/storage/bounded_btree_map.rs b/frame/support/src/storage/bounded_btree_map.rs index 9968217c32b4f..e0ae13066cc5d 100644 --- a/frame/support/src/storage/bounded_btree_map.rs +++ b/frame/support/src/storage/bounded_btree_map.rs @@ -27,9 +27,6 @@ use sp_std::{ ops::Deref, }; -#[cfg(feature = "std")] -use sp_std::fmt; - /// A bounded map based on a B-Tree. /// /// B-Trees represent a fundamental compromise between cache-efficiency and actually minimizing diff --git a/frame/support/src/storage/bounded_vec.rs b/frame/support/src/storage/bounded_vec.rs index f8e32b025888c..694b9498ab6a7 100644 --- a/frame/support/src/storage/bounded_vec.rs +++ b/frame/support/src/storage/bounded_vec.rs @@ -29,7 +29,7 @@ use core::{ slice::{IterMut, SliceIndex}, }; use sp_std::{ - convert::TryFrom, fmt, marker::PhantomData, ops::RangeBounds, prelude::*, vec::Drain, + convert::TryFrom, marker::PhantomData, ops::RangeBounds, prelude::*, vec::Drain, }; /// A bounded vector. diff --git a/frame/support/src/storage/weak_bounded_vec.rs b/frame/support/src/storage/weak_bounded_vec.rs index aac6e767db266..f3f73606c3e13 100644 --- a/frame/support/src/storage/weak_bounded_vec.rs +++ b/frame/support/src/storage/weak_bounded_vec.rs @@ -27,7 +27,7 @@ use core::{ ops::{Deref, Index, IndexMut, RangeBounds}, slice::SliceIndex, }; -use sp_std::{cmp::Ordering, convert::TryFrom, fmt, marker::PhantomData, prelude::*}; +use sp_std::{cmp::Ordering, convert::TryFrom, marker::PhantomData, prelude::*}; /// A weakly bounded vector. /// From e16f9956ac906685f0ff996b01ee73fe52662897 Mon Sep 17 00:00:00 2001 From: Georges Dib Date: Sat, 25 Sep 2021 20:40:22 +0100 Subject: [PATCH 22/80] Fixing tests and some refactoring --- frame/staking/src/lib.rs | 78 ++----- frame/staking/src/mock.rs | 19 +- frame/staking/src/slashing.rs | 17 +- frame/staking/src/tests.rs | 381 +++++++++++++++++++++------------- 4 files changed, 290 insertions(+), 205 deletions(-) diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index 341cf5635d744..b6539065c6684 100644 --- a/frame/staking/src/lib.rs +++ b/frame/staking/src/lib.rs @@ -373,12 +373,14 @@ pub struct ActiveEraInfo { /// /// This points will be used to reward validators and their respective nominators. /// `Limit` bounds the number of points earned by a given validator -#[derive(PartialEq, Encode, Decode, DefaultNoBound, RuntimeDebug, TypeInfo, MaxEncodedLen)] +#[derive( + PartialEqNoBound, Encode, Decode, DefaultNoBound, RuntimeDebugNoBound, TypeInfo, MaxEncodedLen, +)] #[scale_info(skip_type_params(Limit))] #[codec(mel_bound(Limit: Get))] pub struct EraRewardPoints where - AccountId: Ord + MaxEncodedLen + Default, + AccountId: Ord + MaxEncodedLen + Default + PartialEq + fmt::Debug, Limit: Get, { /// Total number of points. Equals the sum of reward points for each validator. @@ -453,15 +455,25 @@ pub struct UnlockChunk { /// The ledger of a (bonded) stash. /// `UnlockingLimit` is the size limit of the `WeakBoundedVec` representing `unlocking` /// `RewardsLimit` is the size limit of the `WeakBoundedVec` representing `claimed_rewards` -#[derive(PartialEq, Eq, Encode, Decode, RuntimeDebug, TypeInfo, MaxEncodedLen)] +#[derive( + PartialEqNoBound, + EqNoBound, + Encode, + Decode, + CloneNoBound, + RuntimeDebugNoBound, + TypeInfo, + MaxEncodedLen, +)] +#[cfg_attr(feature = "runtime-benchmarks", derive(DefaultNoBound))] #[codec(mel_bound(UnlockingLimit: Get, RewardsLimit: Get))] #[scale_info(skip_type_params(UnlockingLimit, RewardsLimit))] pub struct StakingLedger where - Balance: HasCompact + MaxEncodedLen, + Balance: HasCompact + MaxEncodedLen + Clone + Default + Eq + fmt::Debug, + AccountId: MaxEncodedLen + Clone + Default + Eq + fmt::Debug, UnlockingLimit: Get, RewardsLimit: Get, - AccountId: MaxEncodedLen, { /// The stash account whose balance is actually locked and at stake. pub stash: AccountId, @@ -481,53 +493,15 @@ where pub claimed_rewards: WeakBoundedVec, } -#[cfg(feature = "runtime-benchmarks")] -impl Default - for StakingLedger -where - Balance: HasCompact + MaxEncodedLen + Default, - AccountId: MaxEncodedLen + Default, - UnlockingLimit: Get, - RewardsLimit: Get, -{ - fn default() -> Self { - Self { - stash: AccountId::default(), - total: Balance::default(), - active: Balance::default(), - unlocking: BoundedVec::default(), - claimed_rewards: WeakBoundedVec::default(), - } - } -} - -impl Clone - for StakingLedger -where - Balance: HasCompact + MaxEncodedLen + Clone, - AccountId: MaxEncodedLen + Clone, - UnlockingLimit: Get, - RewardsLimit: Get, -{ - fn clone(&self) -> Self { - Self { - stash: self.stash.clone(), - total: self.total.clone(), - active: self.active.clone(), - unlocking: self.unlocking.clone(), - claimed_rewards: self.claimed_rewards.clone(), - } - } -} - impl StakingLedger where - Balance: HasCompact + Copy + Saturating + AtLeast32BitUnsigned, + Balance: + HasCompact + Copy + Saturating + AtLeast32BitUnsigned + Clone + Default + Eq + fmt::Debug, + AccountId: MaxEncodedLen + Clone + Default + Eq + fmt::Debug, + Balance: MaxEncodedLen + Clone + Default, UnlockingLimit: Get, RewardsLimit: Get, - AccountId: MaxEncodedLen, - Balance: MaxEncodedLen, { /// Remove entries from `unlocking` that are sufficiently old and reduce the /// total by the sum of their balances. @@ -581,17 +555,7 @@ where self } -} -impl - StakingLedger -where - Balance: AtLeast32BitUnsigned + Saturating + Copy, - UnlockingLimit: Get, - RewardsLimit: Get, - AccountId: MaxEncodedLen, - Balance: MaxEncodedLen, -{ /// Slash the validator for a given amount of balance. This can grow the value /// of the slash in the case that the validator has less than `minimum_balance` /// active funds. Returns the amount of funds actually slashed. diff --git a/frame/staking/src/mock.rs b/frame/staking/src/mock.rs index 5bf54a9c0ef88..0696e5979fa00 100644 --- a/frame/staking/src/mock.rs +++ b/frame/staking/src/mock.rs @@ -35,7 +35,10 @@ use sp_runtime::{ traits::{IdentityLookup, Zero}, }; use sp_staking::offence::{OffenceDetails, OnOffenceHandler}; -use std::{cell::RefCell, collections::HashSet}; +use std::{ + cell::RefCell, + collections::{BTreeMap, HashSet}, +}; pub const INIT_TIMESTAMP: u64 = 30_000; pub const BLOCK_TIME: u64 = 1000; @@ -193,7 +196,7 @@ impl pallet_session::Config for Test { } impl pallet_session::historical::Config for Test { - type FullIdentification = crate::Exposure; + type FullIdentification = crate::Exposure; type FullIdentificationOf = crate::ExposureOf; } impl pallet_authorship::Config for Test { @@ -248,6 +251,12 @@ const THRESHOLDS: [sp_npos_elections::VoteWeight; 9] = parameter_types! { pub static BagThresholds: &'static [sp_npos_elections::VoteWeight] = &THRESHOLDS; pub const MaxNominations: u32 = 16; + pub const MaxUnappliedSlashes: u32 = 1_000; + pub const MaxNbOfInvulnerables: u32 = 10; + pub const MaxErasForRewards: u32 = 10_000; + pub const MaxNbOfReporters: u32 = 1_000; + pub const MaxPriorSlashingSpans: u32 = 1_000; + pub const MaxNbOfValidators: u32 = 4_000; } impl pallet_bags_list::Config for Test { @@ -284,6 +293,12 @@ impl crate::pallet::pallet::Config for Test { // NOTE: consider a macro and use `UseNominatorsMap` as well. type SortedListProvider = BagsList; type MaxNominations = MaxNominations; + type MaxUnappliedSlashes = MaxUnappliedSlashes; + type MaxNbOfInvulnerables = MaxNbOfInvulnerables; + type MaxErasForRewards = MaxErasForRewards; + type MaxNbOfReporters = MaxNbOfReporters; + type MaxPriorSlashingSpans = MaxPriorSlashingSpans; + type MaxNbOfValidators = MaxNbOfValidators; } impl frame_system::offchain::SendTransactionTypes for Test diff --git a/frame/staking/src/slashing.rs b/frame/staking/src/slashing.rs index 5f62566f02068..27b9aa3f2d4af 100644 --- a/frame/staking/src/slashing.rs +++ b/frame/staking/src/slashing.rs @@ -66,6 +66,9 @@ use sp_runtime::{ }; use sp_std::{convert::TryFrom, ops::Deref}; +#[cfg(test)] +use frame_support::pallet_prelude::ConstU32; + /// The proportion of the slashing reward to be paid out on the first slashing detection. /// This is f_1 in the paper. const REWARD_F1: Perbill = Perbill::from_percent(50); @@ -702,11 +705,11 @@ mod tests { #[test] fn single_slashing_span() { - let spans = SlashingSpans { + let spans = SlashingSpans::> { span_index: 0, last_start: 1000, last_nonzero_slash: 0, - prior: Vec::new(), + prior: WeakBoundedVec::default(), }; assert_eq!( @@ -721,7 +724,7 @@ mod tests { span_index: 10, last_start: 1000, last_nonzero_slash: 0, - prior: vec![10, 9, 8, 10], + prior: WeakBoundedVec::<_, ConstU32<10>>::try_from(vec![10, 9, 8, 10]).expect("10>3"), }; assert_eq!( @@ -742,7 +745,7 @@ mod tests { span_index: 10, last_start: 1000, last_nonzero_slash: 0, - prior: vec![10, 9, 8, 10], + prior: WeakBoundedVec::<_, ConstU32<10>>::try_from(vec![10, 9, 8, 10]).expect("10>3"), }; assert_eq!(spans.prune(981), Some((6, 8))); @@ -792,7 +795,7 @@ mod tests { span_index: 10, last_start: 1000, last_nonzero_slash: 0, - prior: vec![10, 9, 8, 10], + prior: WeakBoundedVec::<_, ConstU32<10>>::try_from(vec![10, 9, 8, 10]).expect("10>4"), }; assert_eq!(spans.prune(2000), Some((6, 10))); assert_eq!( @@ -803,11 +806,11 @@ mod tests { #[test] fn ending_span() { - let mut spans = SlashingSpans { + let mut spans = SlashingSpans::> { span_index: 1, last_start: 10, last_nonzero_slash: 0, - prior: Vec::new(), + prior: WeakBoundedVec::default(), }; assert!(spans.end_span(10)); diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index e902a6de315cd..f5e067ce6f3d9 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -37,7 +37,7 @@ use sp_staking::{ offence::{OffenceDetails, OnOffenceHandler}, SessionIndex, }; -use sp_std::prelude::*; +use sp_std::{collections::btree_map::BTreeMap, prelude::*}; use substrate_test_utils::assert_eq_uvec; #[test] @@ -104,8 +104,8 @@ fn basic_setup_works() { stash: 11, total: 1000, active: 1000, - unlocking: vec![], - claimed_rewards: vec![] + unlocking: BoundedVec::default(), + claimed_rewards: WeakBoundedVec::default(), }) ); // Account 20 controls the stash from account 21, which is 200 * balance_factor units @@ -115,8 +115,8 @@ fn basic_setup_works() { stash: 21, total: 1000, active: 1000, - unlocking: vec![], - claimed_rewards: vec![] + unlocking: BoundedVec::default(), + claimed_rewards: WeakBoundedVec::default(), }) ); // Account 1 does not control any stash @@ -138,8 +138,8 @@ fn basic_setup_works() { stash: 101, total: 500, active: 500, - unlocking: vec![], - claimed_rewards: vec![] + unlocking: BoundedVec::default(), + claimed_rewards: WeakBoundedVec::default(), }) ); assert_eq!(Staking::nominators(101).unwrap().targets, vec![11, 21]); @@ -149,7 +149,10 @@ fn basic_setup_works() { Exposure { total: 1125, own: 1000, - others: vec![IndividualExposure { who: 101, value: 125 }] + others: WeakBoundedVec::<_, ::MaxNominatorRewardedPerValidator>::try_from( + vec![IndividualExposure { who: 101, value: 125 }] + ) + .expect("Please adjust testing parameters"), }, ); assert_eq!( @@ -157,7 +160,10 @@ fn basic_setup_works() { Exposure { total: 1375, own: 1000, - others: vec![IndividualExposure { who: 101, value: 375 }] + others: WeakBoundedVec::<_, ::MaxNominatorRewardedPerValidator>::try_from( + vec![IndividualExposure { who: 101, value: 375}] + ) + .expect("Please adjust testing parameters"), }, ); @@ -235,12 +241,13 @@ fn rewards_should_work() { assert_eq!(Balances::total_balance(&100), init_balance_100); assert_eq!(Balances::total_balance(&101), init_balance_101); assert_eq_uvec!(Session::validators(), vec![11, 21]); + let individual = BoundedBTreeMap::<_, _, ::MaxNbOfValidators>::try_from( + vec![(11, 100), (21, 50)].into_iter().collect::>(), + ) + .expect("Test configuration needs amendment"); assert_eq!( Staking::eras_reward_points(active_era()), - EraRewardPoints { - total: 50 * 3, - individual: vec![(11, 100), (21, 50)].into_iter().collect(), - } + EraRewardPoints { total: 50 * 3, individual } ); let part_for_10 = Perbill::from_rational::(1000, 1125); let part_for_20 = Perbill::from_rational::(1000, 1375); @@ -381,8 +388,10 @@ fn staking_should_work() { stash: 3, total: 1500, active: 1500, - unlocking: vec![], - claimed_rewards: vec![0], + unlocking: BoundedVec::default(), + claimed_rewards: + WeakBoundedVec::<_, ::MaxErasForRewards>::try_from(vec![0]) + .expect("Test configuration needs changing"), }) ); // e.g. it cannot reserve more than 500 that it has free from the total 2000 @@ -535,28 +544,26 @@ fn nominating_and_rewards_should_work() { assert_eq!(Balances::total_balance(&20), initial_balance_20 + total_payout_0 / 2); initial_balance_20 = Balances::total_balance(&20); + let mut others = WeakBoundedVec::<_, MaxNominatorRewardedPerValidator>::try_from(vec![ + IndividualExposure { who: 1, value: 400 }, + IndividualExposure { who: 3, value: 400 }, + ]) + .expect("Test parameter needs changing"); + assert_eq!(ErasStakers::::iter_prefix_values(active_era()).count(), 2); assert_eq!( Staking::eras_stakers(active_era(), 11), - Exposure { - total: 1000 + 800, - own: 1000, - others: vec![ - IndividualExposure { who: 1, value: 400 }, - IndividualExposure { who: 3, value: 400 }, - ] - }, + Exposure { total: 1000 + 800, own: 1000, others }, ); + + others = WeakBoundedVec::<_, MaxNominatorRewardedPerValidator>::try_from(vec![ + IndividualExposure { who: 1, value: 600 }, + IndividualExposure { who: 3, value: 600 }, + ]) + .expect("Test parameter needs changing"); assert_eq!( Staking::eras_stakers(active_era(), 21), - Exposure { - total: 1000 + 1200, - own: 1000, - others: vec![ - IndividualExposure { who: 1, value: 600 }, - IndividualExposure { who: 3, value: 600 }, - ] - }, + Exposure { total: 1000 + 1200, own: 1000, others }, ); // the total reward for era 1 @@ -935,8 +942,8 @@ fn reward_destination_works() { stash: 11, total: 1000, active: 1000, - unlocking: vec![], - claimed_rewards: vec![], + unlocking: BoundedVec::default(), + claimed_rewards: WeakBoundedVec::default(), }) ); @@ -958,8 +965,10 @@ fn reward_destination_works() { stash: 11, total: 1000 + total_payout_0, active: 1000 + total_payout_0, - unlocking: vec![], - claimed_rewards: vec![0], + unlocking: BoundedVec::default(), + claimed_rewards: + WeakBoundedVec::<_, ::MaxErasForRewards>::try_from(vec![0]) + .expect("Test configuration needs changing"), }) ); @@ -986,8 +995,10 @@ fn reward_destination_works() { stash: 11, total: 1000 + total_payout_0, active: 1000 + total_payout_0, - unlocking: vec![], - claimed_rewards: vec![0, 1], + unlocking: BoundedVec::default(), + claimed_rewards: + WeakBoundedVec::<_, ::MaxErasForRewards>::try_from(vec![0, 1]) + .expect("Test configuration needs changing"), }) ); @@ -1015,8 +1026,12 @@ fn reward_destination_works() { stash: 11, total: 1000 + total_payout_0, active: 1000 + total_payout_0, - unlocking: vec![], - claimed_rewards: vec![0, 1, 2], + unlocking: BoundedVec::default(), + claimed_rewards: + WeakBoundedVec::<_, ::MaxErasForRewards>::try_from(vec![ + 0, 1, 2 + ]) + .expect("Test configuration needs changing"), }) ); // Check that amount in staked account is NOT increased. @@ -1080,8 +1095,8 @@ fn bond_extra_works() { stash: 11, total: 1000, active: 1000, - unlocking: vec![], - claimed_rewards: vec![], + unlocking: BoundedVec::default(), + claimed_rewards: WeakBoundedVec::default(), }) ); @@ -1097,8 +1112,8 @@ fn bond_extra_works() { stash: 11, total: 1000 + 100, active: 1000 + 100, - unlocking: vec![], - claimed_rewards: vec![], + unlocking: BoundedVec::default(), + claimed_rewards: WeakBoundedVec::default(), }) ); @@ -1111,8 +1126,8 @@ fn bond_extra_works() { stash: 11, total: 1000000, active: 1000000, - unlocking: vec![], - claimed_rewards: vec![], + unlocking: BoundedVec::default(), + claimed_rewards: WeakBoundedVec::default(), }) ); }); @@ -1149,13 +1164,13 @@ fn bond_extra_and_withdraw_unbonded_works() { stash: 11, total: 1000, active: 1000, - unlocking: vec![], - claimed_rewards: vec![], + unlocking: BoundedVec::default(), + claimed_rewards: WeakBoundedVec::default(), }) ); assert_eq!( Staking::eras_stakers(active_era(), 11), - Exposure { total: 1000, own: 1000, others: vec![] } + Exposure { total: 1000, own: 1000, others: WeakBoundedVec::default() } ); // deposit the extra 100 units @@ -1167,14 +1182,14 @@ fn bond_extra_and_withdraw_unbonded_works() { stash: 11, total: 1000 + 100, active: 1000 + 100, - unlocking: vec![], - claimed_rewards: vec![], + unlocking: BoundedVec::default(), + claimed_rewards: WeakBoundedVec::default(), }) ); // Exposure is a snapshot! only updated after the next era update. assert_ne!( Staking::eras_stakers(active_era(), 11), - Exposure { total: 1000 + 100, own: 1000 + 100, others: vec![] } + Exposure { total: 1000 + 100, own: 1000 + 100, others: WeakBoundedVec::default() } ); // trigger next era. @@ -1188,14 +1203,14 @@ fn bond_extra_and_withdraw_unbonded_works() { stash: 11, total: 1000 + 100, active: 1000 + 100, - unlocking: vec![], - claimed_rewards: vec![], + unlocking: BoundedVec::default(), + claimed_rewards: WeakBoundedVec::default(), }) ); // Exposure is now updated. assert_eq!( Staking::eras_stakers(active_era(), 11), - Exposure { total: 1000 + 100, own: 1000 + 100, others: vec![] } + Exposure { total: 1000 + 100, own: 1000 + 100, others: WeakBoundedVec::default() } ); // Unbond almost all of the funds in stash. @@ -1206,8 +1221,12 @@ fn bond_extra_and_withdraw_unbonded_works() { stash: 11, total: 1000 + 100, active: 100, - unlocking: vec![UnlockChunk { value: 1000, era: 2 + 3 }], - claimed_rewards: vec![] + unlocking: BoundedVec::<_, ConstU32<32>>::try_from(vec![UnlockChunk { + value: 1000, + era: 2 + 3 + }]) + .expect("32>1"), + claimed_rewards: WeakBoundedVec::default(), }), ); @@ -1219,8 +1238,12 @@ fn bond_extra_and_withdraw_unbonded_works() { stash: 11, total: 1000 + 100, active: 100, - unlocking: vec![UnlockChunk { value: 1000, era: 2 + 3 }], - claimed_rewards: vec![] + unlocking: BoundedVec::<_, ConstU32<32>>::try_from(vec![UnlockChunk { + value: 1000, + era: 2 + 3 + }]) + .expect("32>1"), + claimed_rewards: WeakBoundedVec::default(), }), ); @@ -1235,8 +1258,12 @@ fn bond_extra_and_withdraw_unbonded_works() { stash: 11, total: 1000 + 100, active: 100, - unlocking: vec![UnlockChunk { value: 1000, era: 2 + 3 }], - claimed_rewards: vec![] + unlocking: BoundedVec::<_, ConstU32<32>>::try_from(vec![UnlockChunk { + value: 1000, + era: 2 + 3 + }]) + .expect("32>1"), + claimed_rewards: WeakBoundedVec::default(), }), ); @@ -1251,8 +1278,8 @@ fn bond_extra_and_withdraw_unbonded_works() { stash: 11, total: 100, active: 100, - unlocking: vec![], - claimed_rewards: vec![] + unlocking: BoundedVec::default(), + claimed_rewards: WeakBoundedVec::default(), }), ); }) @@ -1309,8 +1336,8 @@ fn rebond_works() { stash: 11, total: 1000, active: 1000, - unlocking: vec![], - claimed_rewards: vec![], + unlocking: BoundedVec::default(), + claimed_rewards: WeakBoundedVec::default(), }) ); @@ -1328,8 +1355,12 @@ fn rebond_works() { stash: 11, total: 1000, active: 100, - unlocking: vec![UnlockChunk { value: 900, era: 2 + 3 }], - claimed_rewards: vec![], + unlocking: BoundedVec::<_, ConstU32<32>>::try_from(vec![UnlockChunk { + value: 900, + era: 2 + 3 + }]) + .expect("32>1"), + claimed_rewards: WeakBoundedVec::default(), }) ); @@ -1341,8 +1372,8 @@ fn rebond_works() { stash: 11, total: 1000, active: 1000, - unlocking: vec![], - claimed_rewards: vec![], + unlocking: BoundedVec::default(), + claimed_rewards: WeakBoundedVec::default(), }) ); @@ -1354,8 +1385,12 @@ fn rebond_works() { stash: 11, total: 1000, active: 100, - unlocking: vec![UnlockChunk { value: 900, era: 5 }], - claimed_rewards: vec![], + unlocking: BoundedVec::<_, ConstU32<32>>::try_from(vec![UnlockChunk { + value: 900, + era: 5 + }]) + .expect("32>1"), + claimed_rewards: WeakBoundedVec::default(), }) ); @@ -1367,8 +1402,12 @@ fn rebond_works() { stash: 11, total: 1000, active: 600, - unlocking: vec![UnlockChunk { value: 400, era: 5 }], - claimed_rewards: vec![], + unlocking: BoundedVec::<_, ConstU32<32>>::try_from(vec![UnlockChunk { + value: 400, + era: 5 + }]) + .expect("32>1"), + claimed_rewards: WeakBoundedVec::default(), }) ); @@ -1380,8 +1419,8 @@ fn rebond_works() { stash: 11, total: 1000, active: 1000, - unlocking: vec![], - claimed_rewards: vec![], + unlocking: BoundedVec::default(), + claimed_rewards: WeakBoundedVec::default(), }) ); @@ -1395,12 +1434,13 @@ fn rebond_works() { stash: 11, total: 1000, active: 100, - unlocking: vec![ + unlocking: BoundedVec::<_, ConstU32<32>>::try_from(vec![ UnlockChunk { value: 300, era: 5 }, UnlockChunk { value: 300, era: 5 }, UnlockChunk { value: 300, era: 5 }, - ], - claimed_rewards: vec![], + ]) + .expect("32>3"), + claimed_rewards: WeakBoundedVec::default(), }) ); @@ -1412,11 +1452,12 @@ fn rebond_works() { stash: 11, total: 1000, active: 600, - unlocking: vec![ + unlocking: BoundedVec::<_, ConstU32<32>>::try_from(vec![ UnlockChunk { value: 300, era: 5 }, UnlockChunk { value: 100, era: 5 }, - ], - claimed_rewards: vec![], + ]) + .expect("32>2"), + claimed_rewards: WeakBoundedVec::default(), }) ); }) @@ -1442,8 +1483,8 @@ fn rebond_is_fifo() { stash: 11, total: 1000, active: 1000, - unlocking: vec![], - claimed_rewards: vec![], + unlocking: BoundedVec::default(), + claimed_rewards: WeakBoundedVec::default(), }) ); @@ -1457,8 +1498,12 @@ fn rebond_is_fifo() { stash: 11, total: 1000, active: 600, - unlocking: vec![UnlockChunk { value: 400, era: 2 + 3 },], - claimed_rewards: vec![], + unlocking: BoundedVec::<_, ConstU32<32>>::try_from(vec![UnlockChunk { + value: 400, + era: 2 + 3 + },]) + .expect("32>1"), + claimed_rewards: WeakBoundedVec::default(), }) ); @@ -1472,11 +1517,12 @@ fn rebond_is_fifo() { stash: 11, total: 1000, active: 300, - unlocking: vec![ + unlocking: BoundedVec::<_, ConstU32<32>>::try_from(vec![ UnlockChunk { value: 400, era: 2 + 3 }, UnlockChunk { value: 300, era: 3 + 3 }, - ], - claimed_rewards: vec![], + ]) + .expect("32>2"), + claimed_rewards: WeakBoundedVec::default(), }) ); @@ -1490,12 +1536,13 @@ fn rebond_is_fifo() { stash: 11, total: 1000, active: 100, - unlocking: vec![ + unlocking: BoundedVec::<_, ConstU32<32>>::try_from(vec![ UnlockChunk { value: 400, era: 2 + 3 }, UnlockChunk { value: 300, era: 3 + 3 }, UnlockChunk { value: 200, era: 4 + 3 }, - ], - claimed_rewards: vec![], + ]) + .expect("32>3"), + claimed_rewards: WeakBoundedVec::default(), }) ); @@ -1507,11 +1554,12 @@ fn rebond_is_fifo() { stash: 11, total: 1000, active: 500, - unlocking: vec![ + unlocking: BoundedVec::<_, ConstU32<32>>::try_from(vec![ UnlockChunk { value: 400, era: 2 + 3 }, UnlockChunk { value: 100, era: 3 + 3 }, - ], - claimed_rewards: vec![], + ]) + .expect("32>2"), + claimed_rewards: WeakBoundedVec::default(), }) ); }) @@ -1537,15 +1585,19 @@ fn reward_to_stake_works() { let _ = Balances::make_free_balance_be(&20, 1000); // Bypass logic and change current exposure - ErasStakers::::insert(0, 21, Exposure { total: 69, own: 69, others: vec![] }); + ErasStakers::::insert( + 0, + 21, + Exposure { total: 69, own: 69, others: WeakBoundedVec::default() }, + ); >::insert( &20, StakingLedger { stash: 21, total: 69, active: 69, - unlocking: vec![], - claimed_rewards: vec![], + unlocking: BoundedVec::default(), + claimed_rewards: WeakBoundedVec::default(), }, ); @@ -1788,8 +1840,12 @@ fn bond_with_no_staked_value() { stash: 1, active: 0, total: 5, - unlocking: vec![UnlockChunk { value: 5, era: 3 }], - claimed_rewards: vec![], + unlocking: BoundedVec::<_, ConstU32<32>>::try_from(vec![UnlockChunk { + value: 5, + era: 3 + }]) + .expect("32>1"), + claimed_rewards: WeakBoundedVec::default(), }) ); @@ -2007,10 +2063,18 @@ fn reward_validator_slashing_validator_does_not_overflow() { // Set staker let _ = Balances::make_free_balance_be(&11, stake); - let exposure = Exposure:: { total: stake, own: stake, others: vec![] }; - let reward = EraRewardPoints:: { + let exposure = + Exposure::::MaxNominatorRewardedPerValidator> { + total: stake, + own: stake, + others: WeakBoundedVec::default(), + }; + let reward = EraRewardPoints { total: 1, - individual: vec![(11, 1)].into_iter().collect(), + individual: BoundedBTreeMap::<_, _, ::MaxNbOfValidators>::try_from( + vec![(11, 1)].into_iter().collect::>(), + ) + .expect("MaxNbOfValidators>0"), }; // Check reward @@ -2035,7 +2099,8 @@ fn reward_validator_slashing_validator_does_not_overflow() { Exposure { total: stake, own: 1, - others: vec![IndividualExposure { who: 2, value: stake - 1 }], + others: WeakBoundedVec::<_, ::MaxNominatorRewardedPerValidator>::try_from( + vec![IndividualExposure { who: 2, value: stake - 1 }]).expect("MaxNominatorRewardedPerValidator>0"), }, ); @@ -2073,7 +2138,10 @@ fn reward_from_authorship_event_handler_works() { assert_eq!( ErasRewardPoints::::get(active_era()), EraRewardPoints { - individual: vec![(11, 20 + 2 * 2 + 1), (21, 1)].into_iter().collect(), + individual: BoundedBTreeMap::<_, _, ::MaxNbOfValidators>::try_from( + vec![(11, 20 + 2 * 2 + 1), (21, 1)].into_iter().collect::>() + ) + .expect("MaxNbOfValidators should be > 1"), total: 26, }, ); @@ -2092,7 +2160,13 @@ fn add_reward_points_fns_works() { assert_eq!( ErasRewardPoints::::get(active_era()), - EraRewardPoints { individual: vec![(11, 4), (21, 2)].into_iter().collect(), total: 6 }, + EraRewardPoints { + individual: BoundedBTreeMap::<_, _, ::MaxNbOfValidators>::try_from( + vec![(11, 4), (21, 2)].into_iter().collect::>() + ) + .expect("MaxNbOfValidators>1"), + total: 6 + }, ); }) } @@ -2208,7 +2282,10 @@ fn slashing_performed_according_exposure() { // Handle an offence with a historical exposure. on_offence_now( &[OffenceDetails { - offender: (11, Exposure { total: 500, own: 500, others: vec![] }), + offender: ( + 11, + Exposure { total: 500, own: 500, others: WeakBoundedVec::default() }, + ), reporters: vec![], }], &[Perbill::from_percent(50)], @@ -3183,8 +3260,10 @@ fn test_payout_stakers() { stash: 11, total: 1000, active: 1000, - unlocking: vec![], - claimed_rewards: vec![1] + unlocking: BoundedVec::default(), + claimed_rewards: + WeakBoundedVec::<_, ::MaxErasForRewards>::try_from(vec![1]) + .expect("MaxErasForRewards>1"), }) ); @@ -3205,8 +3284,12 @@ fn test_payout_stakers() { stash: 11, total: 1000, active: 1000, - unlocking: vec![], - claimed_rewards: (1..=14).collect() + unlocking: BoundedVec::default(), + claimed_rewards: + WeakBoundedVec::<_, ::MaxErasForRewards>::try_from( + (1..=14).collect::>() + ) + .expect("Test configuration should be changed") }) ); @@ -3226,8 +3309,10 @@ fn test_payout_stakers() { stash: 11, total: 1000, active: 1000, - unlocking: vec![], - claimed_rewards: vec![15, 98] + unlocking: BoundedVec::default(), + claimed_rewards: + WeakBoundedVec::<_, ::MaxErasForRewards>::try_from(vec![15, 98]) + .expect("MaxErasForRewards should be > 1"), }) ); @@ -3241,8 +3326,12 @@ fn test_payout_stakers() { stash: 11, total: 1000, active: 1000, - unlocking: vec![], - claimed_rewards: vec![15, 23, 42, 69, 98] + unlocking: BoundedVec::default(), + claimed_rewards: + WeakBoundedVec::<_, ::MaxErasForRewards>::try_from(vec![ + 15, 23, 42, 69, 98 + ]) + .expect("MaxErasForRewards should be > 4") }) ); }); @@ -3436,8 +3525,8 @@ fn bond_during_era_correctly_populates_claimed_rewards() { stash: 9, total: 1000, active: 1000, - unlocking: vec![], - claimed_rewards: vec![], + unlocking: BoundedVec::default(), + claimed_rewards: WeakBoundedVec::default(), }) ); mock::start_active_era(5); @@ -3448,8 +3537,12 @@ fn bond_during_era_correctly_populates_claimed_rewards() { stash: 11, total: 1000, active: 1000, - unlocking: vec![], - claimed_rewards: (0..5).collect(), + unlocking: BoundedVec::default(), + claimed_rewards: + WeakBoundedVec::<_, ::MaxErasForRewards>::try_from( + (0..5).collect::>() + ) + .expect("MaxErasForRewards should be >= 5"), }) ); mock::start_active_era(99); @@ -3460,8 +3553,12 @@ fn bond_during_era_correctly_populates_claimed_rewards() { stash: 13, total: 1000, active: 1000, - unlocking: vec![], - claimed_rewards: (15..99).collect(), + unlocking: BoundedVec::default(), + claimed_rewards: + WeakBoundedVec::<_, ::MaxErasForRewards>::try_from( + (15..99).collect::>() + ) + .expect("Some test configuration may need changing"), }) ); }); @@ -3679,8 +3776,8 @@ fn cannot_rebond_to_lower_than_ed() { stash: 21, total: 10 * 1000, active: 10 * 1000, - unlocking: vec![], - claimed_rewards: vec![] + unlocking: BoundedVec::default(), + claimed_rewards: WeakBoundedVec::default(), } ); @@ -3693,8 +3790,12 @@ fn cannot_rebond_to_lower_than_ed() { stash: 21, total: 10 * 1000, active: 0, - unlocking: vec![UnlockChunk { value: 10 * 1000, era: 3 }], - claimed_rewards: vec![] + unlocking: BoundedVec::<_, ConstU32<32>>::try_from(vec![UnlockChunk { + value: 10 * 1000, + era: 3 + }]) + .expect("32>1"), + claimed_rewards: WeakBoundedVec::default(), } ); @@ -3716,8 +3817,8 @@ fn cannot_bond_extra_to_lower_than_ed() { stash: 21, total: 10 * 1000, active: 10 * 1000, - unlocking: vec![], - claimed_rewards: vec![] + unlocking: BoundedVec::default(), + claimed_rewards: WeakBoundedVec::default(), } ); @@ -3730,8 +3831,12 @@ fn cannot_bond_extra_to_lower_than_ed() { stash: 21, total: 10 * 1000, active: 0, - unlocking: vec![UnlockChunk { value: 10 * 1000, era: 3 }], - claimed_rewards: vec![] + unlocking: BoundedVec::<_, ConstU32<32>>::try_from(vec![UnlockChunk { + value: 10 * 1000, + era: 3 + }]) + .expect("32>1"), + claimed_rewards: WeakBoundedVec::default(), } ); @@ -3757,8 +3862,8 @@ fn do_not_die_when_active_is_ed() { stash: 21, total: 1000 * ed, active: 1000 * ed, - unlocking: vec![], - claimed_rewards: vec![] + unlocking: BoundedVec::default(), + claimed_rewards: WeakBoundedVec::default(), } ); @@ -3774,8 +3879,8 @@ fn do_not_die_when_active_is_ed() { stash: 21, total: ed, active: ed, - unlocking: vec![], - claimed_rewards: vec![] + unlocking: BoundedVec::default(), + claimed_rewards: WeakBoundedVec::default(), } ); }) @@ -4078,7 +4183,11 @@ fn count_check_works() { Validators::::insert(987654321, ValidatorPrefs::default()); Nominators::::insert( 987654321, - Nominations { targets: vec![], submitted_in: Default::default(), suppressed: false }, + Nominations { + targets: BoundedVec::default(), + submitted_in: Default::default(), + suppressed: false, + }, ); }) } @@ -4200,13 +4309,7 @@ fn chill_other_works() { ); // Add limits, but no threshold - assert_ok!(Staking::set_staking_limits( - Origin::root(), - 1_500, - 2_000, - Some(10), - None - )); + assert_ok!(Staking::set_staking_limits(Origin::root(), 1_500, 2_000, Some(10), None)); // Still can't chill these users assert_noop!( From 5604e903975c2df90322c2d64983fdde052f551b Mon Sep 17 00:00:00 2001 From: Georges Dib Date: Sat, 25 Sep 2021 21:38:22 +0100 Subject: [PATCH 23/80] Fixed test cases --- frame/staking/src/mock.rs | 2 +- frame/staking/src/pallet/mod.rs | 7 ++--- frame/staking/src/tests.rs | 53 ++++++++++++++++++++++----------- 3 files changed, 39 insertions(+), 23 deletions(-) diff --git a/frame/staking/src/mock.rs b/frame/staking/src/mock.rs index 0696e5979fa00..5d665f5fe8825 100644 --- a/frame/staking/src/mock.rs +++ b/frame/staking/src/mock.rs @@ -256,7 +256,7 @@ parameter_types! { pub const MaxErasForRewards: u32 = 10_000; pub const MaxNbOfReporters: u32 = 1_000; pub const MaxPriorSlashingSpans: u32 = 1_000; - pub const MaxNbOfValidators: u32 = 4_000; + pub const MaxNbOfValidators: u32 = 100; } impl pallet_bags_list::Config for Test { diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index 3ef5ed78ba10a..ff6d13c8f9df0 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -1596,8 +1596,8 @@ pub mod pallet { /// must be met: /// * A `ChillThreshold` must be set and checked which defines how close to the max /// nominators or validators we must reach before users can start chilling one-another. - /// * A `MaxNominatorCount` and `MaxValidatorCount` must be set which is used to determine - /// how close we are to the threshold. + /// * A `MaxNominatorCount` must be set which is used to determine how close we are to the + /// threshold. /// * A `MinNominatorBond` and `MinValidatorBond` must be set and checked, which determines /// if this is a person that should be chilled because they have not met the threshold /// bond required. @@ -1614,8 +1614,7 @@ pub mod pallet { // In order for one user to chill another user, the following conditions must be met: // * A `ChillThreshold` is set which defines how close to the max nominators or // validators we must reach before users can start chilling one-another. - // * A `MaxNominatorCount` and `MaxValidatorCount` which is used to determine how close - // we are to the threshold. + // * A `MaxNominatorCount` which is used to determine how close we are to the threshold. // * A `MinNominatorBond` and `MinValidatorBond` which is the final condition checked to // determine this is a person that should be chilled because they have not met the // threshold bond required. diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index f5e067ce6f3d9..3336b1c1558da 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -4335,10 +4335,8 @@ fn chill_other_works() { Staking::chill_other(Origin::signed(1337), 1), Error::::CannotChillOther ); - assert_noop!( - Staking::chill_other(Origin::signed(1337), 3), - Error::::CannotChillOther - ); + // But validator will succeed because MaxNbOfValidators is always set + assert_ok!(Staking::chill_other(Origin::signed(1337), 3)); // Add threshold and limits assert_ok!(Staking::set_staking_limits( @@ -4349,17 +4347,15 @@ fn chill_other_works() { Some(Percent::from_percent(75)) )); - // 16 people total because tests start with 2 active one + // 16 nominators and 17 validators left (test starts with 1 nominator and 3 validator) assert_eq!(CounterForNominators::::get(), 15 + initial_nominators); - assert_eq!(CounterForValidators::::get(), 15 + initial_validators); + assert_eq!(CounterForValidators::::get(), 14 + initial_validators); // 1 was chilled - // Users can now be chilled down to 7 people, so we try to remove 9 of them (starting - // with 16) + // Nominators can now be chilled down to 7 people, so we try to remove 9 of them + // (starting with 16) for i in 6..15 { let b = 4 * i + 1; - let d = 4 * i + 3; assert_ok!(Staking::chill_other(Origin::signed(1337), b)); - assert_ok!(Staking::chill_other(Origin::signed(1337), d)); } // chill a nominator. Limit is not reached, not chill-able @@ -4368,9 +4364,27 @@ fn chill_other_works() { Staking::chill_other(Origin::signed(1337), 1), Error::::CannotChillOther ); - // chill a validator. Limit is reached, chill-able. - assert_eq!(CounterForValidators::::get(), 9); - assert_ok!(Staking::chill_other(Origin::signed(1337), 3)); + + // Max number of validators is set externally to 100, so need to change threshold + assert_ok!(Staking::set_staking_limits( + Origin::root(), + 1_500, + 2_000, + Some(10), + Some(Percent::from_percent(7)) + )); + + for i in 6..15 { + let d = 4 * i + 3; + assert_ok!(Staking::chill_other(Origin::signed(1337), d)); + } + + // chill a validator. Limit is not reached, not chill-able + assert_eq!(CounterForValidators::::get(), 8); + assert_noop!( + Staking::chill_other(Origin::signed(1337), 3), + Error::::CannotChillOther + ); }) } @@ -4383,18 +4397,17 @@ fn capped_stakers_works() { assert_eq!(nominator_count, 1); // Change the maximums - let max = 10; assert_ok!(Staking::set_staking_limits( Origin::root(), 10, 10, - Some(max), + Some(10), Some(Percent::from_percent(0)) )); // can create `max - validator_count` validators let mut some_existing_validator = AccountId::default(); - for i in 0..max - validator_count { + for i in 0..::MaxNbOfValidators::get() - validator_count { let (_, controller) = testing_utils::create_stash_controller::( i + 10_000_000, 100, @@ -4420,7 +4433,7 @@ fn capped_stakers_works() { // same with nominators let mut some_existing_nominator = AccountId::default(); - for i in 0..max - nominator_count { + for i in 0..10 - nominator_count { let (_, controller) = testing_utils::create_stash_controller::( i + 20_000_000, 100, @@ -4454,7 +4467,11 @@ fn capped_stakers_works() { // No problem when we set to `None` again assert_ok!(Staking::set_staking_limits(Origin::root(), 10, 10, None, None)); assert_ok!(Staking::nominate(Origin::signed(last_nominator), vec![1])); - assert_ok!(Staking::validate(Origin::signed(last_validator), ValidatorPrefs::default())); + // But fail validators given limit is set externally + assert_noop!( + Staking::validate(Origin::signed(last_validator), ValidatorPrefs::default()), + Error::::TooManyValidators + ); }) } From 7473eca53485d305a96d00ccd4c4572fcc4b86ab Mon Sep 17 00:00:00 2001 From: Georges Dib Date: Sat, 25 Sep 2021 21:42:15 +0100 Subject: [PATCH 24/80] Fixing docs --- frame/staking/src/lib.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index b6539065c6684..86985bf32a708 100644 --- a/frame/staking/src/lib.rs +++ b/frame/staking/src/lib.rs @@ -158,7 +158,7 @@ //! //! ``` //! use frame_support::pallet_prelude::*; -//! use frame_system::ensure_signed; +//! use frame_system::{ensure_signed, pallet_prelude::OriginFor}; //! use pallet_staking::{self as staking}; //! //! #[frame_support::pallet] @@ -170,15 +170,15 @@ //! pub struct Pallet(_); //! //! #[pallet::config] -//! pub trait Config: staking::Config {} +//! pub trait Config: frame_system::Config + staking::Config {} //! //! #[pallet::call] //! impl Pallet { //! /// Reward a validator. -//! #[weight = 0] -//! pub fn reward_myself(origin) -> dispatch::DispatchResult { +//! #[pallet::weight(0)] +//! pub fn reward_myself(origin: OriginFor) -> DispatchResult { //! let reported = ensure_signed(origin)?; -//! >::reward_by_ids(vec![(reported, 10)]); +//! >::reward_by_ids(vec![(reported, 10)]); //! Ok(()) //! } //! } From 55d9d9381a79ebaa25184b1aad3fcfc5d736ab5a Mon Sep 17 00:00:00 2001 From: Georges Dib Date: Sat, 25 Sep 2021 22:11:20 +0100 Subject: [PATCH 25/80] Fixing other pallets' tests --- frame/babe/src/mock.rs | 17 ++++++++++++-- frame/babe/src/tests.rs | 12 ++++++---- .../election-provider-multi-phase/src/mock.rs | 4 ++-- frame/election-provider-support/src/lib.rs | 1 + .../election-provider-support/src/onchain.rs | 1 + frame/grandpa/src/mock.rs | 17 ++++++++++++-- frame/grandpa/src/tests.rs | 16 +++++++++----- frame/offences/benchmarking/src/mock.rs | 22 +++++++++++++++---- frame/session/benchmarking/src/mock.rs | 18 +++++++++++++-- 9 files changed, 86 insertions(+), 22 deletions(-) diff --git a/frame/babe/src/mock.rs b/frame/babe/src/mock.rs index a05072bc3319e..4ad1c73a2e78e 100644 --- a/frame/babe/src/mock.rs +++ b/frame/babe/src/mock.rs @@ -127,7 +127,7 @@ impl pallet_session::Config for Test { } impl pallet_session::historical::Config for Test { - type FullIdentification = pallet_staking::Exposure; + type FullIdentification = pallet_staking::Exposure; type FullIdentificationOf = pallet_staking::ExposureOf; } @@ -189,6 +189,13 @@ parameter_types! { pub const MaxNominatorRewardedPerValidator: u32 = 64; pub const ElectionLookahead: u64 = 0; pub const StakingUnsignedPriority: u64 = u64::MAX / 2; + pub const MaxNominations: u32 = 16; + pub const MaxUnappliedSlashes: u32 = 1_000; + pub const MaxNbOfInvulnerables: u32 = 10; + pub const MaxErasForRewards: u32 = 10_000; + pub const MaxNbOfReporters: u32 = 1_000; + pub const MaxPriorSlashingSpans: u32 = 1_000; + pub const MaxNbOfValidators: u32 = 4_000; } impl onchain::Config for Test { @@ -197,7 +204,6 @@ impl onchain::Config for Test { } impl pallet_staking::Config for Test { - const MAX_NOMINATIONS: u32 = 16; type RewardRemainder = (); type CurrencyToVote = frame_support::traits::SaturatingCurrencyToVote; type Event = Event; @@ -212,6 +218,13 @@ impl pallet_staking::Config for Test { type UnixTime = pallet_timestamp::Pallet; type EraPayout = pallet_staking::ConvertCurve; type MaxNominatorRewardedPerValidator = MaxNominatorRewardedPerValidator; + type MaxNominations = MaxNominations; + type MaxUnappliedSlashes = MaxUnappliedSlashes; + type MaxNbOfInvulnerables = MaxNbOfInvulnerables; + type MaxErasForRewards = MaxErasForRewards; + type MaxNbOfReporters = MaxNbOfReporters; + type MaxPriorSlashingSpans = MaxPriorSlashingSpans; + type MaxNbOfValidators = MaxNbOfValidators; type NextNewSession = Session; type ElectionProvider = onchain::OnChainSequentialPhragmen; type GenesisElectionProvider = Self::ElectionProvider; diff --git a/frame/babe/src/tests.rs b/frame/babe/src/tests.rs index 34d861d5d97f7..1d1b9c2bcbc83 100644 --- a/frame/babe/src/tests.rs +++ b/frame/babe/src/tests.rs @@ -415,7 +415,11 @@ fn report_equivocation_current_session_works() { assert_eq!( Staking::eras_stakers(1, validator), - pallet_staking::Exposure { total: 10_000, own: 10_000, others: vec![] }, + pallet_staking::Exposure { + total: 10_000, + own: 10_000, + others: WeakBoundedVec::default() + }, ); } @@ -456,7 +460,7 @@ fn report_equivocation_current_session_works() { assert_eq!(Staking::slashable_balance_of(&offending_validator_id), 0); assert_eq!( Staking::eras_stakers(2, offending_validator_id), - pallet_staking::Exposure { total: 0, own: 0, others: vec![] }, + pallet_staking::Exposure { total: 0, own: 0, others: WeakBoundedVec::default() }, ); // check that the balances of all other validators are left intact. @@ -469,7 +473,7 @@ fn report_equivocation_current_session_works() { assert_eq!(Staking::slashable_balance_of(validator), 10_000); assert_eq!( Staking::eras_stakers(2, validator), - pallet_staking::Exposure { total: 10_000, own: 10_000, others: vec![] }, + pallet_staking::Exposure { total: 10_000, own: 10_000, others: WeakBoundedVec::default() }, ); } }) @@ -528,7 +532,7 @@ fn report_equivocation_old_session_works() { assert_eq!(Staking::slashable_balance_of(&offending_validator_id), 0); assert_eq!( Staking::eras_stakers(3, offending_validator_id), - pallet_staking::Exposure { total: 0, own: 0, others: vec![] }, + pallet_staking::Exposure { total: 0, own: 0, others: WeakBoundedVec::default() }, ); }) } diff --git a/frame/election-provider-multi-phase/src/mock.rs b/frame/election-provider-multi-phase/src/mock.rs index a05dc12c37ac0..d18fa4a9a52bb 100644 --- a/frame/election-provider-multi-phase/src/mock.rs +++ b/frame/election-provider-multi-phase/src/mock.rs @@ -21,7 +21,7 @@ use frame_election_provider_support::{ data_provider, onchain, ElectionDataProvider, SequentialPhragmen, }; pub use frame_support::{assert_noop, assert_ok}; -use frame_support::{parameter_types, traits::Hooks, weights::Weight}; +use frame_support::{pallet_prelude::ConstU32, parameter_types, traits::Hooks, weights::Weight}; use multi_phase::unsigned::{IndexAssignmentOf, Voter}; use parking_lot::RwLock; use sp_core::{ @@ -421,7 +421,7 @@ pub struct ExtBuilder {} pub struct StakingMock; impl ElectionDataProvider for StakingMock { - type MaximumVotesPerVoter = ConstU32<::LIMIT as u32>; + type MaximumVotesPerVoter = ConstU32<{ ::LIMIT as u32 }>; fn targets(maybe_max_len: Option) -> data_provider::Result> { let targets = Targets::get(); diff --git a/frame/election-provider-support/src/lib.rs b/frame/election-provider-support/src/lib.rs index 9954deb036f84..98ba9a6d7b2f9 100644 --- a/frame/election-provider-support/src/lib.rs +++ b/frame/election-provider-support/src/lib.rs @@ -80,6 +80,7 @@ //! ```rust //! # use frame_election_provider_support::{*, data_provider}; //! # use sp_npos_elections::{Support, Assignment}; +//! # use frame_support::pallet_prelude::ConstU32; //! //! type AccountId = u64; //! type Balance = u64; diff --git a/frame/election-provider-support/src/onchain.rs b/frame/election-provider-support/src/onchain.rs index babc1b2c81c5e..c5fd8253740c8 100644 --- a/frame/election-provider-support/src/onchain.rs +++ b/frame/election-provider-support/src/onchain.rs @@ -101,6 +101,7 @@ impl ElectionProvider for OnChainSequen #[cfg(test)] mod tests { use super::*; + use crate::ConstU32; use sp_npos_elections::Support; use sp_runtime::Perbill; diff --git a/frame/grandpa/src/mock.rs b/frame/grandpa/src/mock.rs index 4e5e44ce36e7a..1ff1ace747ee3 100644 --- a/frame/grandpa/src/mock.rs +++ b/frame/grandpa/src/mock.rs @@ -129,7 +129,7 @@ impl pallet_session::Config for Test { } impl pallet_session::historical::Config for Test { - type FullIdentification = pallet_staking::Exposure; + type FullIdentification = pallet_staking::Exposure; type FullIdentificationOf = pallet_staking::ExposureOf; } @@ -191,6 +191,13 @@ parameter_types! { pub const MaxNominatorRewardedPerValidator: u32 = 64; pub const ElectionLookahead: u64 = 0; pub const StakingUnsignedPriority: u64 = u64::MAX / 2; + pub const MaxNominations: u32 = 16; + pub const MaxUnappliedSlashes: u32 = 1_000; + pub const MaxNbOfInvulnerables: u32 = 10; + pub const MaxErasForRewards: u32 = 10_000; + pub const MaxNbOfReporters: u32 = 1_000; + pub const MaxPriorSlashingSpans: u32 = 1_000; + pub const MaxNbOfValidators: u32 = 4_000; } impl onchain::Config for Test { @@ -199,7 +206,6 @@ impl onchain::Config for Test { } impl pallet_staking::Config for Test { - const MAX_NOMINATIONS: u32 = 16; type RewardRemainder = (); type CurrencyToVote = frame_support::traits::SaturatingCurrencyToVote; type Event = Event; @@ -214,6 +220,13 @@ impl pallet_staking::Config for Test { type UnixTime = pallet_timestamp::Pallet; type EraPayout = pallet_staking::ConvertCurve; type MaxNominatorRewardedPerValidator = MaxNominatorRewardedPerValidator; + type MaxNominations = MaxNominations; + type MaxUnappliedSlashes = MaxUnappliedSlashes; + type MaxNbOfInvulnerables = MaxNbOfInvulnerables; + type MaxErasForRewards = MaxErasForRewards; + type MaxNbOfReporters = MaxNbOfReporters; + type MaxPriorSlashingSpans = MaxPriorSlashingSpans; + type MaxNbOfValidators = MaxNbOfValidators; type NextNewSession = Session; type ElectionProvider = onchain::OnChainSequentialPhragmen; type GenesisElectionProvider = Self::ElectionProvider; diff --git a/frame/grandpa/src/tests.rs b/frame/grandpa/src/tests.rs index 98f54f966fadc..90eded6e0a48e 100644 --- a/frame/grandpa/src/tests.rs +++ b/frame/grandpa/src/tests.rs @@ -329,7 +329,11 @@ fn report_equivocation_current_set_works() { assert_eq!( Staking::eras_stakers(1, validator), - pallet_staking::Exposure { total: 10_000, own: 10_000, others: vec![] }, + pallet_staking::Exposure { + total: 10_000, + own: 10_000, + others: WeakBoundedVec::default() + }, ); } @@ -367,7 +371,7 @@ fn report_equivocation_current_set_works() { assert_eq!(Staking::slashable_balance_of(&equivocation_validator_id), 0); assert_eq!( Staking::eras_stakers(2, equivocation_validator_id), - pallet_staking::Exposure { total: 0, own: 0, others: vec![] }, + pallet_staking::Exposure { total: 0, own: 0, others: WeakBoundedVec::default() }, ); // check that the balances of all other validators are left intact. @@ -381,7 +385,7 @@ fn report_equivocation_current_set_works() { assert_eq!( Staking::eras_stakers(2, validator), - pallet_staking::Exposure { total: 10_000, own: 10_000, others: vec![] }, + pallet_staking::Exposure { total: 10_000, own: 10_000, others: WeakBoundedVec::default() }, ); } }); @@ -413,7 +417,7 @@ fn report_equivocation_old_set_works() { assert_eq!( Staking::eras_stakers(2, validator), - pallet_staking::Exposure { total: 10_000, own: 10_000, others: vec![] }, + pallet_staking::Exposure { total: 10_000, own: 10_000, others: WeakBoundedVec::default() }, ); } @@ -446,7 +450,7 @@ fn report_equivocation_old_set_works() { assert_eq!( Staking::eras_stakers(3, equivocation_validator_id), - pallet_staking::Exposure { total: 0, own: 0, others: vec![] }, + pallet_staking::Exposure { total: 0, own: 0, others: WeakBoundedVec::default() }, ); // check that the balances of all other validators are left intact. @@ -460,7 +464,7 @@ fn report_equivocation_old_set_works() { assert_eq!( Staking::eras_stakers(3, validator), - pallet_staking::Exposure { total: 10_000, own: 10_000, others: vec![] }, + pallet_staking::Exposure { total: 10_000, own: 10_000, others: WeakBoundedVec::default() }, ); } }); diff --git a/frame/offences/benchmarking/src/mock.rs b/frame/offences/benchmarking/src/mock.rs index 6973e25371d4f..4214a46ed6b17 100644 --- a/frame/offences/benchmarking/src/mock.rs +++ b/frame/offences/benchmarking/src/mock.rs @@ -89,7 +89,8 @@ impl pallet_timestamp::Config for Test { type WeightInfo = (); } impl pallet_session::historical::Config for Test { - type FullIdentification = pallet_staking::Exposure; + type FullIdentification = + pallet_staking::Exposure; type FullIdentificationOf = pallet_staking::ExposureOf; } @@ -147,8 +148,15 @@ parameter_types! { pub const RewardCurve: &'static sp_runtime::curve::PiecewiseLinear<'static> = &I_NPOS; pub const MaxNominatorRewardedPerValidator: u32 = 64; pub const MaxKeys: u32 = 10_000; - pub const MaxPeerInHeartbeats: u32 = 10_000; - pub const MaxPeerDataEncodingSize: u32 = 1_000; + pub const MaxPeerInHeartbeats: u32 = 10_000; + pub const MaxPeerDataEncodingSize: u32 = 1_000; + pub const MaxNominations: u32 = 16; + pub const MaxUnappliedSlashes: u32 = 1_000; + pub const MaxNbOfInvulnerables: u32 = 10; + pub const MaxErasForRewards: u32 = 10_000; + pub const MaxNbOfReporters: u32 = 1_000; + pub const MaxPriorSlashingSpans: u32 = 1_000; + pub const MaxNbOfValidators: u32 = 4_000; } pub type Extrinsic = sp_runtime::testing::TestXt; @@ -159,7 +167,6 @@ impl onchain::Config for Test { } impl pallet_staking::Config for Test { - const MAX_NOMINATIONS: u32 = 16; type Currency = Balances; type UnixTime = pallet_timestamp::Pallet; type CurrencyToVote = frame_support::traits::SaturatingCurrencyToVote; @@ -175,6 +182,13 @@ impl pallet_staking::Config for Test { type EraPayout = pallet_staking::ConvertCurve; type NextNewSession = Session; type MaxNominatorRewardedPerValidator = MaxNominatorRewardedPerValidator; + type MaxNominations = MaxNominations; + type MaxUnappliedSlashes = MaxUnappliedSlashes; + type MaxNbOfInvulnerables = MaxNbOfInvulnerables; + type MaxErasForRewards = MaxErasForRewards; + type MaxNbOfReporters = MaxNbOfReporters; + type MaxPriorSlashingSpans = MaxPriorSlashingSpans; + type MaxNbOfValidators = MaxNbOfValidators; type ElectionProvider = onchain::OnChainSequentialPhragmen; type GenesisElectionProvider = Self::ElectionProvider; type SortedListProvider = pallet_staking::UseNominatorsMap; diff --git a/frame/session/benchmarking/src/mock.rs b/frame/session/benchmarking/src/mock.rs index 4d3a1a2d8689d..17fc9a9de3368 100644 --- a/frame/session/benchmarking/src/mock.rs +++ b/frame/session/benchmarking/src/mock.rs @@ -94,7 +94,8 @@ impl pallet_timestamp::Config for Test { type WeightInfo = (); } impl pallet_session::historical::Config for Test { - type FullIdentification = pallet_staking::Exposure; + type FullIdentification = + pallet_staking::Exposure; type FullIdentificationOf = pallet_staking::ExposureOf; } @@ -146,6 +147,13 @@ parameter_types! { pub const RewardCurve: &'static sp_runtime::curve::PiecewiseLinear<'static> = &I_NPOS; pub const MaxNominatorRewardedPerValidator: u32 = 64; pub const UnsignedPriority: u64 = 1 << 20; + pub const MaxNominations: u32 = 16; + pub const MaxUnappliedSlashes: u32 = 1_000; + pub const MaxNbOfInvulnerables: u32 = 10; + pub const MaxErasForRewards: u32 = 10_000; + pub const MaxNbOfReporters: u32 = 1_000; + pub const MaxPriorSlashingSpans: u32 = 1_000; + pub const MaxNbOfValidators: u32 = 4_000; } pub type Extrinsic = sp_runtime::testing::TestXt; @@ -164,7 +172,6 @@ impl onchain::Config for Test { } impl pallet_staking::Config for Test { - const MAX_NOMINATIONS: u32 = 16; type Currency = Balances; type UnixTime = pallet_timestamp::Pallet; type CurrencyToVote = frame_support::traits::SaturatingCurrencyToVote; @@ -180,6 +187,13 @@ impl pallet_staking::Config for Test { type EraPayout = pallet_staking::ConvertCurve; type NextNewSession = Session; type MaxNominatorRewardedPerValidator = MaxNominatorRewardedPerValidator; + type MaxNominations = MaxNominations; + type MaxUnappliedSlashes = MaxUnappliedSlashes; + type MaxNbOfInvulnerables = MaxNbOfInvulnerables; + type MaxErasForRewards = MaxErasForRewards; + type MaxNbOfReporters = MaxNbOfReporters; + type MaxPriorSlashingSpans = MaxPriorSlashingSpans; + type MaxNbOfValidators = MaxNbOfValidators; type ElectionProvider = onchain::OnChainSequentialPhragmen; type GenesisElectionProvider = Self::ElectionProvider; type SortedListProvider = pallet_staking::UseNominatorsMap; From 37d5d35f10468fc19dcbe047ac22a9b0339382d3 Mon Sep 17 00:00:00 2001 From: Georges Dib Date: Sat, 25 Sep 2021 22:21:02 +0100 Subject: [PATCH 26/80] Fixing README --- frame/staking/README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/frame/staking/README.md b/frame/staking/README.md index 02cbe0cac86c2..d1220c0cde9d8 100644 --- a/frame/staking/README.md +++ b/frame/staking/README.md @@ -134,7 +134,7 @@ The Staking module contains many public storage items and (im)mutable functions. ```rust use frame_support::pallet_prelude::*; -use frame_system::ensure_signed; +use frame_system::{ensure_signed, pallet_prelude::OriginFor}; use pallet_staking::{self as staking}; #[frame_support::pallet] @@ -146,15 +146,15 @@ pub mod pallet { pub struct Pallet(_); #[pallet::config] - pub trait Config: staking::Config {} + pub trait Config: frame_system::Config + staking::Config {} #[pallet::call] impl Pallet { /// Reward a validator. - #[weight = 0] - pub fn reward_myself(origin) -> dispatch::DispatchResult { + #[pallet::weight(0)] + pub fn reward_myself(origin: OriginFor) -> DispatchResult { let reported = ensure_signed(origin)?; - >::reward_by_ids(vec![(reported, 10)]); + >::reward_by_ids(vec![(reported, 10)]); Ok(()) } } From 2dce1f10496ed3b165348780da685602ed646485 Mon Sep 17 00:00:00 2001 From: Georges Dib Date: Sat, 25 Sep 2021 22:34:35 +0100 Subject: [PATCH 27/80] Fixing test benchmarks --- frame/election-provider-multi-phase/src/benchmarking.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/frame/election-provider-multi-phase/src/benchmarking.rs b/frame/election-provider-multi-phase/src/benchmarking.rs index c05428c621c92..1b26dce11ba9a 100644 --- a/frame/election-provider-multi-phase/src/benchmarking.rs +++ b/frame/election-provider-multi-phase/src/benchmarking.rs @@ -156,7 +156,7 @@ fn set_up_data_provider(v: u32, t: u32) { info, "setting up with voters = {} [degree = {}], targets = {}", v, - T::DataProvider::MaximumVotesPerVoter::get(), + >::MaximumVotesPerVoter::get(), t ); @@ -169,8 +169,10 @@ fn set_up_data_provider(v: u32, t: u32) { }) .collect::>(); // we should always have enough voters to fill. - assert!(targets.len() > T::DataProvider::MaximumVotesPerVoter::get() as usize); - targets.truncate(T::DataProvider::MaximumVotesPerVoter::get() as usize); + let max_votes = + >::MaximumVotesPerVoter::get() as usize; + assert!(targets.len() > max_votes); + targets.truncate(max_votes); // fill voters. (0..v).for_each(|i| { From 68fc710221f74a86ba8f5d8e5219f6f0707a5b2f Mon Sep 17 00:00:00 2001 From: Georges Dib Date: Sat, 25 Sep 2021 23:14:17 +0100 Subject: [PATCH 28/80] fixing benchmark tests --- frame/staking/src/benchmarking.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frame/staking/src/benchmarking.rs b/frame/staking/src/benchmarking.rs index 5766429aba072..9bfa447b03150 100644 --- a/frame/staking/src/benchmarking.rs +++ b/frame/staking/src/benchmarking.rs @@ -41,7 +41,7 @@ use sp_runtime::traits::{Bounded, One}; const SEED: u32 = 0; const MAX_SPANS: u32 = 100; -const MAX_VALIDATORS: u32 = 1000; +const MAX_VALIDATORS: u32 = 100; const MAX_NOMINATORS: u32 = 1000; const MAX_SLASHES: u32 = 1000; From abe2d616114f177caa772f5ce42d7b3b0bed5bc6 Mon Sep 17 00:00:00 2001 From: Georges Dib Date: Sun, 26 Sep 2021 12:13:12 +0100 Subject: [PATCH 29/80] Changing naming from `Nb` to `Count` nomenclature --- bin/node/runtime/src/lib.rs | 12 ++++++------ frame/babe/src/mock.rs | 12 ++++++------ frame/grandpa/src/mock.rs | 12 ++++++------ frame/offences/benchmarking/src/mock.rs | 12 ++++++------ frame/session/benchmarking/src/mock.rs | 12 ++++++------ frame/staking/src/benchmarking.rs | 10 +++++----- frame/staking/src/mock.rs | 12 ++++++------ frame/staking/src/pallet/impls.rs | 2 +- frame/staking/src/pallet/mod.rs | 20 ++++++++++---------- frame/staking/src/slashing.rs | 4 ++-- frame/staking/src/tests.rs | 18 +++++++++--------- 11 files changed, 63 insertions(+), 63 deletions(-) diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index aaeac31ae5c57..c3d6d38cdc78f 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -500,11 +500,11 @@ parameter_types! { pub OffchainRepeat: BlockNumber = 5; pub const MaxNominations: u32 = MAX_NOMINATIONS; pub const MaxUnappliedSlashes: u32 = 1_000; - pub const MaxNbOfInvulnerables: u32 = 10; + pub const MaxInvulnerablesCount: u32 = 10; pub const MaxErasForRewards: u32 = 10_000; - pub const MaxNbOfReporters: u32 = 1_000; + pub const MaxReportersCount: u32 = 1_000; pub const MaxPriorSlashingSpans: u32 = 1_000; - pub const MaxNbOfValidators: u32 = 4_000; + pub const MaxValidatorsCount: u32 = 4_000; } use frame_election_provider_support::onchain; @@ -542,11 +542,11 @@ impl pallet_staking::Config for Runtime { type WeightInfo = pallet_staking::weights::SubstrateWeight; type MaxNominations = MaxNominations; type MaxUnappliedSlashes = MaxUnappliedSlashes; - type MaxNbOfInvulnerables = MaxNbOfInvulnerables; + type MaxInvulnerablesCount = MaxInvulnerablesCount; type MaxErasForRewards = MaxErasForRewards; - type MaxNbOfReporters = MaxNbOfReporters; + type MaxReportersCount = MaxReportersCount; type MaxPriorSlashingSpans = MaxPriorSlashingSpans; - type MaxNbOfValidators = MaxNbOfValidators; + type MaxValidatorsCount = MaxValidatorsCount; } parameter_types! { diff --git a/frame/babe/src/mock.rs b/frame/babe/src/mock.rs index 4ad1c73a2e78e..755fa3730d12d 100644 --- a/frame/babe/src/mock.rs +++ b/frame/babe/src/mock.rs @@ -191,11 +191,11 @@ parameter_types! { pub const StakingUnsignedPriority: u64 = u64::MAX / 2; pub const MaxNominations: u32 = 16; pub const MaxUnappliedSlashes: u32 = 1_000; - pub const MaxNbOfInvulnerables: u32 = 10; + pub const MaxInvulnerablesCount: u32 = 10; pub const MaxErasForRewards: u32 = 10_000; - pub const MaxNbOfReporters: u32 = 1_000; + pub const MaxReportersCount: u32 = 1_000; pub const MaxPriorSlashingSpans: u32 = 1_000; - pub const MaxNbOfValidators: u32 = 4_000; + pub const MaxValidatorsCount: u32 = 4_000; } impl onchain::Config for Test { @@ -220,11 +220,11 @@ impl pallet_staking::Config for Test { type MaxNominatorRewardedPerValidator = MaxNominatorRewardedPerValidator; type MaxNominations = MaxNominations; type MaxUnappliedSlashes = MaxUnappliedSlashes; - type MaxNbOfInvulnerables = MaxNbOfInvulnerables; + type MaxInvulnerablesCount = MaxInvulnerablesCount; type MaxErasForRewards = MaxErasForRewards; - type MaxNbOfReporters = MaxNbOfReporters; + type MaxReportersCount = MaxReportersCount; type MaxPriorSlashingSpans = MaxPriorSlashingSpans; - type MaxNbOfValidators = MaxNbOfValidators; + type MaxValidatorsCount = MaxValidatorsCount; type NextNewSession = Session; type ElectionProvider = onchain::OnChainSequentialPhragmen; type GenesisElectionProvider = Self::ElectionProvider; diff --git a/frame/grandpa/src/mock.rs b/frame/grandpa/src/mock.rs index 1ff1ace747ee3..7d6117084123c 100644 --- a/frame/grandpa/src/mock.rs +++ b/frame/grandpa/src/mock.rs @@ -193,11 +193,11 @@ parameter_types! { pub const StakingUnsignedPriority: u64 = u64::MAX / 2; pub const MaxNominations: u32 = 16; pub const MaxUnappliedSlashes: u32 = 1_000; - pub const MaxNbOfInvulnerables: u32 = 10; + pub const MaxInvulnerablesCount: u32 = 10; pub const MaxErasForRewards: u32 = 10_000; - pub const MaxNbOfReporters: u32 = 1_000; + pub const MaxReportersCount: u32 = 1_000; pub const MaxPriorSlashingSpans: u32 = 1_000; - pub const MaxNbOfValidators: u32 = 4_000; + pub const MaxValidatorsCount: u32 = 4_000; } impl onchain::Config for Test { @@ -222,11 +222,11 @@ impl pallet_staking::Config for Test { type MaxNominatorRewardedPerValidator = MaxNominatorRewardedPerValidator; type MaxNominations = MaxNominations; type MaxUnappliedSlashes = MaxUnappliedSlashes; - type MaxNbOfInvulnerables = MaxNbOfInvulnerables; + type MaxInvulnerablesCount = MaxInvulnerablesCount; type MaxErasForRewards = MaxErasForRewards; - type MaxNbOfReporters = MaxNbOfReporters; + type MaxReportersCount = MaxReportersCount; type MaxPriorSlashingSpans = MaxPriorSlashingSpans; - type MaxNbOfValidators = MaxNbOfValidators; + type MaxValidatorsCount = MaxValidatorsCount; type NextNewSession = Session; type ElectionProvider = onchain::OnChainSequentialPhragmen; type GenesisElectionProvider = Self::ElectionProvider; diff --git a/frame/offences/benchmarking/src/mock.rs b/frame/offences/benchmarking/src/mock.rs index 4214a46ed6b17..ce38892e83587 100644 --- a/frame/offences/benchmarking/src/mock.rs +++ b/frame/offences/benchmarking/src/mock.rs @@ -152,11 +152,11 @@ parameter_types! { pub const MaxPeerDataEncodingSize: u32 = 1_000; pub const MaxNominations: u32 = 16; pub const MaxUnappliedSlashes: u32 = 1_000; - pub const MaxNbOfInvulnerables: u32 = 10; + pub const MaxInvulnerablesCount: u32 = 10; pub const MaxErasForRewards: u32 = 10_000; - pub const MaxNbOfReporters: u32 = 1_000; + pub const MaxReportersCount: u32 = 1_000; pub const MaxPriorSlashingSpans: u32 = 1_000; - pub const MaxNbOfValidators: u32 = 4_000; + pub const MaxValidatorsCount: u32 = 4_000; } pub type Extrinsic = sp_runtime::testing::TestXt; @@ -184,11 +184,11 @@ impl pallet_staking::Config for Test { type MaxNominatorRewardedPerValidator = MaxNominatorRewardedPerValidator; type MaxNominations = MaxNominations; type MaxUnappliedSlashes = MaxUnappliedSlashes; - type MaxNbOfInvulnerables = MaxNbOfInvulnerables; + type MaxInvulnerablesCount = MaxInvulnerablesCount; type MaxErasForRewards = MaxErasForRewards; - type MaxNbOfReporters = MaxNbOfReporters; + type MaxReportersCount = MaxReportersCount; type MaxPriorSlashingSpans = MaxPriorSlashingSpans; - type MaxNbOfValidators = MaxNbOfValidators; + type MaxValidatorsCount = MaxValidatorsCount; type ElectionProvider = onchain::OnChainSequentialPhragmen; type GenesisElectionProvider = Self::ElectionProvider; type SortedListProvider = pallet_staking::UseNominatorsMap; diff --git a/frame/session/benchmarking/src/mock.rs b/frame/session/benchmarking/src/mock.rs index 17fc9a9de3368..40320cc9d9fe0 100644 --- a/frame/session/benchmarking/src/mock.rs +++ b/frame/session/benchmarking/src/mock.rs @@ -149,11 +149,11 @@ parameter_types! { pub const UnsignedPriority: u64 = 1 << 20; pub const MaxNominations: u32 = 16; pub const MaxUnappliedSlashes: u32 = 1_000; - pub const MaxNbOfInvulnerables: u32 = 10; + pub const MaxInvulnerablesCount: u32 = 10; pub const MaxErasForRewards: u32 = 10_000; - pub const MaxNbOfReporters: u32 = 1_000; + pub const MaxReportersCount: u32 = 1_000; pub const MaxPriorSlashingSpans: u32 = 1_000; - pub const MaxNbOfValidators: u32 = 4_000; + pub const MaxValidatorsCount: u32 = 4_000; } pub type Extrinsic = sp_runtime::testing::TestXt; @@ -189,11 +189,11 @@ impl pallet_staking::Config for Test { type MaxNominatorRewardedPerValidator = MaxNominatorRewardedPerValidator; type MaxNominations = MaxNominations; type MaxUnappliedSlashes = MaxUnappliedSlashes; - type MaxNbOfInvulnerables = MaxNbOfInvulnerables; + type MaxInvulnerablesCount = MaxInvulnerablesCount; type MaxErasForRewards = MaxErasForRewards; - type MaxNbOfReporters = MaxNbOfReporters; + type MaxReportersCount = MaxReportersCount; type MaxPriorSlashingSpans = MaxPriorSlashingSpans; - type MaxNbOfValidators = MaxNbOfValidators; + type MaxValidatorsCount = MaxValidatorsCount; type ElectionProvider = onchain::OnChainSequentialPhragmen; type GenesisElectionProvider = Self::ElectionProvider; type SortedListProvider = pallet_staking::UseNominatorsMap; diff --git a/frame/staking/src/benchmarking.rs b/frame/staking/src/benchmarking.rs index 9bfa447b03150..f85b6cf15f31e 100644 --- a/frame/staking/src/benchmarking.rs +++ b/frame/staking/src/benchmarking.rs @@ -115,12 +115,12 @@ pub fn create_validator_with_nominators( assert_ne!(CounterForNominators::::get(), 0); // Give Era Points - let individual = BoundedBTreeMap::<_, _, T::MaxNbOfValidators>::try_from( + let individual = BoundedBTreeMap::<_, _, T::MaxValidatorsCount>::try_from( points_individual.into_iter().collect::>(), ) - .map_err(|_| "Something weird, this means T:MaxNbOfValidators is zero")?; + .map_err(|_| "Something weird, this means T:MaxValidatorsCount is zero")?; let reward = - EraRewardPoints:: { total: points_total, individual }; + EraRewardPoints:: { total: points_total, individual }; let current_era = CurrentEra::::get().unwrap(); ErasRewardPoints::::insert(current_era, reward); @@ -539,7 +539,7 @@ benchmarks! { let era = EraIndex::one(); for _ in 0 .. MAX_SLASHES { unapplied_slashes.push(UnappliedSlash::, T::MaxNominatorRewardedPerValidator, - T::MaxNbOfReporters>::default()); + T::MaxReportersCount>::default()); } let unapplied_slashes = WeakBoundedVec::<_, T::MaxUnappliedSlashes>::try_from(unapplied_slashes) .expect("MAX_SLASHES should be <= MaxUnappliedSlashes, runtime benchmarks need adjustment"); @@ -758,7 +758,7 @@ benchmarks! { } // Give Era Points - let individual = BoundedBTreeMap::<_, _, T::MaxNbOfValidators>::try_from( + let individual = BoundedBTreeMap::<_, _, T::MaxValidatorsCount>::try_from( points_individual.into_iter().collect::>(), ) .map_err(|_| "Too many validators, some runtime benchmarks may need adjustment")?; diff --git a/frame/staking/src/mock.rs b/frame/staking/src/mock.rs index 5d665f5fe8825..b41a4e6f0f39e 100644 --- a/frame/staking/src/mock.rs +++ b/frame/staking/src/mock.rs @@ -252,11 +252,11 @@ parameter_types! { pub static BagThresholds: &'static [sp_npos_elections::VoteWeight] = &THRESHOLDS; pub const MaxNominations: u32 = 16; pub const MaxUnappliedSlashes: u32 = 1_000; - pub const MaxNbOfInvulnerables: u32 = 10; + pub const MaxInvulnerablesCount: u32 = 10; pub const MaxErasForRewards: u32 = 10_000; - pub const MaxNbOfReporters: u32 = 1_000; + pub const MaxReportersCount: u32 = 1_000; pub const MaxPriorSlashingSpans: u32 = 1_000; - pub const MaxNbOfValidators: u32 = 100; + pub const MaxValidatorsCount: u32 = 100; } impl pallet_bags_list::Config for Test { @@ -294,11 +294,11 @@ impl crate::pallet::pallet::Config for Test { type SortedListProvider = BagsList; type MaxNominations = MaxNominations; type MaxUnappliedSlashes = MaxUnappliedSlashes; - type MaxNbOfInvulnerables = MaxNbOfInvulnerables; + type MaxInvulnerablesCount = MaxInvulnerablesCount; type MaxErasForRewards = MaxErasForRewards; - type MaxNbOfReporters = MaxNbOfReporters; + type MaxReportersCount = MaxReportersCount; type MaxPriorSlashingSpans = MaxPriorSlashingSpans; - type MaxNbOfValidators = MaxNbOfValidators; + type MaxValidatorsCount = MaxValidatorsCount; } impl frame_system::offchain::SendTransactionTypes for Test diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index dcff4f370371a..6ec626587dacc 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -1260,7 +1260,7 @@ where let rw = upper_bound + nominators_len * upper_bound; add_db_reads_writes(rw, rw); } - unapplied.reporters = WeakBoundedVec::<_, T::MaxNbOfReporters>::force_from( + unapplied.reporters = WeakBoundedVec::<_, T::MaxReportersCount>::force_from( details.reporters.clone(), Some( "Warning: Number of reporters is bigger than expected. \ diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index ff6d13c8f9df0..d78290464c12d 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -155,7 +155,7 @@ pub mod pallet { /// The maximum number of invulnerables, we expect no more than four invulnerables and /// restricted to testnets. #[pallet::constant] - type MaxNbOfInvulnerables: Get; + type MaxInvulnerablesCount: Get; /// Maximum number of eras for which the stakers behind a validator have claimed rewards. #[pallet::constant] @@ -163,11 +163,11 @@ pub mod pallet { /// Maximum number of validators. #[pallet::constant] - type MaxNbOfValidators: Get; + type MaxValidatorsCount: Get; /// Maximum number of reporters for slashing. #[pallet::constant] - type MaxNbOfReporters: Get; + type MaxReportersCount: Get; /// Maximum number of slashing spans that is stored. #[pallet::constant] @@ -223,7 +223,7 @@ pub mod pallet { #[pallet::storage] #[pallet::getter(fn invulnerables)] pub type Invulnerables = - StorageValue<_, BoundedVec, ValueQuery>; + StorageValue<_, BoundedVec, ValueQuery>; /// Map from all locked "stash" accounts to the controller account. #[pallet::storage] @@ -387,7 +387,7 @@ pub mod pallet { _, Twox64Concat, EraIndex, - EraRewardPoints, + EraRewardPoints, ValueQuery, >; @@ -427,7 +427,7 @@ pub mod pallet { T::AccountId, BalanceOf, T::MaxNominatorRewardedPerValidator, - T::MaxNbOfReporters, + T::MaxReportersCount, >, T::MaxUnappliedSlashes, >, @@ -550,7 +550,7 @@ pub mod pallet { MinValidatorBond::::put(self.min_validator_bond); let invulnerables = - BoundedVec::<_, T::MaxNbOfInvulnerables>::try_from(self.invulnerables.clone()) + BoundedVec::<_, T::MaxInvulnerablesCount>::try_from(self.invulnerables.clone()) .expect( "Too many invulnerables passed, a runtime parameters adjustment may be needed", ); @@ -1012,7 +1012,7 @@ pub mod pallet { // calling `chill_other`. Until then, we explicitly block new validators to protect // the runtime. ensure!( - CounterForValidators::::get() < T::MaxNbOfValidators::get(), + CounterForValidators::::get() < T::MaxValidatorsCount::get(), Error::::TooManyValidators ); } @@ -1281,7 +1281,7 @@ pub mod pallet { invulnerables: Vec, ) -> DispatchResult { ensure_root(origin)?; - let invulnerables = BoundedVec::<_, T::MaxNbOfInvulnerables>::try_from(invulnerables) + let invulnerables = BoundedVec::<_, T::MaxInvulnerablesCount>::try_from(invulnerables) .map_err(|_| Error::::TooManyInvulnerables)?; >::put(invulnerables); Ok(()) @@ -1632,7 +1632,7 @@ pub mod pallet { ); MinNominatorBond::::get() } else if Validators::::contains_key(&stash) { - let max_validator_count = T::MaxNbOfValidators::get(); + let max_validator_count = T::MaxValidatorsCount::get(); let current_validator_count = CounterForValidators::::get(); ensure!( threshold * max_validator_count < current_validator_count, diff --git a/frame/staking/src/slashing.rs b/frame/staking/src/slashing.rs index 27b9aa3f2d4af..8bc86f4cef798 100644 --- a/frame/staking/src/slashing.rs +++ b/frame/staking/src/slashing.rs @@ -243,7 +243,7 @@ pub(crate) fn compute_slash( T::AccountId, BalanceOf, T::MaxNominatorRewardedPerValidator, - T::MaxNbOfReporters, + T::MaxReportersCount, >, > { let SlashParams { stash, slash, exposure, slash_era, window_start, now, reward_proportion } = @@ -624,7 +624,7 @@ pub(crate) fn apply_slash( T::AccountId, BalanceOf, T::MaxNominatorRewardedPerValidator, - T::MaxNbOfReporters, + T::MaxReportersCount, >, ) { let mut slashed_imbalance = NegativeImbalanceOf::::zero(); diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index 3336b1c1558da..6c2bcdfdb2d95 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -241,7 +241,7 @@ fn rewards_should_work() { assert_eq!(Balances::total_balance(&100), init_balance_100); assert_eq!(Balances::total_balance(&101), init_balance_101); assert_eq_uvec!(Session::validators(), vec![11, 21]); - let individual = BoundedBTreeMap::<_, _, ::MaxNbOfValidators>::try_from( + let individual = BoundedBTreeMap::<_, _, ::MaxValidatorsCount>::try_from( vec![(11, 100), (21, 50)].into_iter().collect::>(), ) .expect("Test configuration needs amendment"); @@ -2071,10 +2071,10 @@ fn reward_validator_slashing_validator_does_not_overflow() { }; let reward = EraRewardPoints { total: 1, - individual: BoundedBTreeMap::<_, _, ::MaxNbOfValidators>::try_from( + individual: BoundedBTreeMap::<_, _, ::MaxValidatorsCount>::try_from( vec![(11, 1)].into_iter().collect::>(), ) - .expect("MaxNbOfValidators>0"), + .expect("MaxValidatorsCount>0"), }; // Check reward @@ -2138,10 +2138,10 @@ fn reward_from_authorship_event_handler_works() { assert_eq!( ErasRewardPoints::::get(active_era()), EraRewardPoints { - individual: BoundedBTreeMap::<_, _, ::MaxNbOfValidators>::try_from( + individual: BoundedBTreeMap::<_, _, ::MaxValidatorsCount>::try_from( vec![(11, 20 + 2 * 2 + 1), (21, 1)].into_iter().collect::>() ) - .expect("MaxNbOfValidators should be > 1"), + .expect("MaxValidatorsCount should be > 1"), total: 26, }, ); @@ -2161,10 +2161,10 @@ fn add_reward_points_fns_works() { assert_eq!( ErasRewardPoints::::get(active_era()), EraRewardPoints { - individual: BoundedBTreeMap::<_, _, ::MaxNbOfValidators>::try_from( + individual: BoundedBTreeMap::<_, _, ::MaxValidatorsCount>::try_from( vec![(11, 4), (21, 2)].into_iter().collect::>() ) - .expect("MaxNbOfValidators>1"), + .expect("MaxValidatorsCount>1"), total: 6 }, ); @@ -4335,7 +4335,7 @@ fn chill_other_works() { Staking::chill_other(Origin::signed(1337), 1), Error::::CannotChillOther ); - // But validator will succeed because MaxNbOfValidators is always set + // But validator will succeed because MaxValidatorsCount is always set assert_ok!(Staking::chill_other(Origin::signed(1337), 3)); // Add threshold and limits @@ -4407,7 +4407,7 @@ fn capped_stakers_works() { // can create `max - validator_count` validators let mut some_existing_validator = AccountId::default(); - for i in 0..::MaxNbOfValidators::get() - validator_count { + for i in 0..::MaxValidatorsCount::get() - validator_count { let (_, controller) = testing_utils::create_stash_controller::( i + 10_000_000, 100, From a8f9dcc6c252d874f781a09cc8463299f0f1bde0 Mon Sep 17 00:00:00 2001 From: Georges Dib Date: Sun, 26 Sep 2021 12:19:02 +0100 Subject: [PATCH 30/80] Stop globally importing `ConstU32` and annotate its use accordingly --- frame/election-provider-support/src/lib.rs | 8 ++------ frame/election-provider-support/src/onchain.rs | 3 +-- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/frame/election-provider-support/src/lib.rs b/frame/election-provider-support/src/lib.rs index 98ba9a6d7b2f9..d14108de65fe7 100644 --- a/frame/election-provider-support/src/lib.rs +++ b/frame/election-provider-support/src/lib.rs @@ -80,7 +80,6 @@ //! ```rust //! # use frame_election_provider_support::{*, data_provider}; //! # use sp_npos_elections::{Support, Assignment}; -//! # use frame_support::pallet_prelude::ConstU32; //! //! type AccountId = u64; //! type Balance = u64; @@ -100,7 +99,7 @@ //! pub struct Module(std::marker::PhantomData); //! //! impl ElectionDataProvider for Module { -//! type MaximumVotesPerVoter = ConstU32<1>; +//! type MaximumVotesPerVoter = frame_support::pallet_prelude::ConstU32<1>; //! fn desired_targets() -> data_provider::Result { //! Ok(1) //! } @@ -172,9 +171,6 @@ pub use sp_npos_elections::{ VoteWeight, }; -#[cfg(feature = "std")] -use frame_support::pallet_prelude::ConstU32; - /// Types that are used by the data provider trait. pub mod data_provider { /// Alias for the result type of the election data provider. @@ -253,7 +249,7 @@ pub trait ElectionDataProvider { #[cfg(feature = "std")] impl ElectionDataProvider for () { - type MaximumVotesPerVoter = ConstU32<0>; + type MaximumVotesPerVoter = frame_support::pallet_prelude::ConstU32<0>; fn targets(_maybe_max_len: Option) -> data_provider::Result> { Ok(Default::default()) } diff --git a/frame/election-provider-support/src/onchain.rs b/frame/election-provider-support/src/onchain.rs index c5fd8253740c8..3bbb3a4afab11 100644 --- a/frame/election-provider-support/src/onchain.rs +++ b/frame/election-provider-support/src/onchain.rs @@ -101,7 +101,6 @@ impl ElectionProvider for OnChainSequen #[cfg(test)] mod tests { use super::*; - use crate::ConstU32; use sp_npos_elections::Support; use sp_runtime::Perbill; @@ -161,7 +160,7 @@ mod tests { pub struct DataProvider; impl ElectionDataProvider for DataProvider { - type MaximumVotesPerVoter = ConstU32<2>; + type MaximumVotesPerVoter = frame_support::pallet_prelude::ConstU32<2>; fn voters( _: Option, ) -> data_provider::Result)>> { From f8b5e80955c4b22738e46ce6b17321e9b436033b Mon Sep 17 00:00:00 2001 From: Georges Dib Date: Sun, 26 Sep 2021 12:23:01 +0100 Subject: [PATCH 31/80] No need for a full description, only scope is needed --- frame/staking/src/pallet/impls.rs | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index 6ec626587dacc..eaf6c86861699 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -554,10 +554,7 @@ impl Pallet { let others = WeakBoundedVec::<_, T::MaxNominatorRewardedPerValidator>::force_from( others, - Some( - "Warning: The number of nominators is bigger than expected. \ - A runtime configuration adjustment may be needed.", - ), + Some("exposure.others"), ); let exposure = Exposure { own, others, total }; @@ -1262,10 +1259,7 @@ where } unapplied.reporters = WeakBoundedVec::<_, T::MaxReportersCount>::force_from( details.reporters.clone(), - Some( - "Warning: Number of reporters is bigger than expected. \ - A runtime parameter adjustment may be needed.", - ), + Some("unapplied.reporters"), ); if slash_defer_duration == 0 { // Apply right away. From 87613b81c58c0d9401d07dac5699c54d3640e08b Mon Sep 17 00:00:00 2001 From: Georges Dib Date: Sun, 26 Sep 2021 12:24:42 +0100 Subject: [PATCH 32/80] Only scope is needed in message --- frame/staking/src/pallet/mod.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index d78290464c12d..51fecb8ae4d55 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -802,10 +802,7 @@ pub mod pallet { let claimed_rewards = WeakBoundedVec::<_, T::MaxErasForRewards>::force_from( (last_reward_era..current_era).collect(), - Some( - "Warning: The size of the claimed rewards is bigger than expected. \ - A runtime configuration adjustment may be needed.", - ), + Some("StakingLedger.claimed_rewards"), ); let item = StakingLedger { stash, From 12301454fce31aad68aee1900697ea8d877e1eca Mon Sep 17 00:00:00 2001 From: Georges Dib Date: Sun, 26 Sep 2021 12:28:13 +0100 Subject: [PATCH 33/80] Better documentation punctuation Shorter scope message --- frame/staking/src/pallet/impls.rs | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index eaf6c86861699..9a9a09784500d 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -937,8 +937,8 @@ impl ElectionDataProvider> for Pallet /// # Panic /// - /// Panics if `targets` size is bigger than T::MaxNominations. - /// Or if it cannot convert `weight` into a `BalanceOf` + /// Panics if `targets` size is bigger than T::MaxNominations, or if it cannot convert `weight` + /// into a `BalanceOf`. #[cfg(feature = "runtime-benchmarks")] fn add_voter(voter: T::AccountId, weight: VoteWeight, targets: Vec) { use sp_std::convert::TryFrom; @@ -995,8 +995,8 @@ impl ElectionDataProvider> for Pallet /// # Panic /// - /// Panics if `voters` 3rd element is larger than T::MaxNominations. - /// Or if the 2nd element cannot be converted into a `BalanceOf` + /// Panics if `voters` 3rd element is larger than T::MaxNominations, or if the 2nd element + /// cannot be converted into a `BalanceOf`. #[cfg(feature = "runtime-benchmarks")] fn put_snapshot( voters: Vec<(T::AccountId, VoteWeight, Vec)>, @@ -1275,13 +1275,7 @@ where } else { // Defer to end of some `slash_defer_duration` from now. ::UnappliedSlashes::mutate(active_era, move |for_later| { - for_later.force_push( - unapplied, - Some( - "Warning: More unapplied stashes than expected. \ - A runtime parameter adjustment may be needed.", - ), - ) + for_later.force_push(unapplied, Some("UnappliedStashes.unapplied")) }); add_db_reads_writes(1, 1); } From b83cda748135861db737fde398e94e7bd2d645a7 Mon Sep 17 00:00:00 2001 From: Georges Dib Date: Sun, 26 Sep 2021 12:31:27 +0100 Subject: [PATCH 34/80] Removing few `[pallet::constant]` --- frame/staking/src/pallet/mod.rs | 7 ------- 1 file changed, 7 deletions(-) diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index 51fecb8ae4d55..93acb947ec729 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -96,7 +96,6 @@ pub mod pallet { >; /// Maximum number of nominations per nominator. - #[pallet::constant] type MaxNominations: Get; /// Tokens have been minted and are unused for validator-reward. @@ -149,28 +148,22 @@ pub mod pallet { type MaxNominatorRewardedPerValidator: Get; /// The maximum number of unapplied slashes to be stored in `UnappliedSlashes` - #[pallet::constant] type MaxUnappliedSlashes: Get; /// The maximum number of invulnerables, we expect no more than four invulnerables and /// restricted to testnets. - #[pallet::constant] type MaxInvulnerablesCount: Get; /// Maximum number of eras for which the stakers behind a validator have claimed rewards. - #[pallet::constant] type MaxErasForRewards: Get; /// Maximum number of validators. - #[pallet::constant] type MaxValidatorsCount: Get; /// Maximum number of reporters for slashing. - #[pallet::constant] type MaxReportersCount: Get; /// Maximum number of slashing spans that is stored. - #[pallet::constant] type MaxPriorSlashingSpans: Get; /// Something that can provide a sorted list of voters in a somewhat sorted way. The From a097ab6555d988188cf5205a9c1480d327beeb65 Mon Sep 17 00:00:00 2001 From: Georges Dib Date: Sun, 26 Sep 2021 12:44:23 +0100 Subject: [PATCH 35/80] Making MAX_UNLOCKING_CHUNKS become a runtime parameter `MaxUnlockingChunks` --- bin/node/runtime/src/lib.rs | 2 ++ frame/staking/README.md | 2 +- frame/staking/src/benchmarking.rs | 8 ++++---- frame/staking/src/lib.rs | 2 +- frame/staking/src/pallet/impls.rs | 4 ++-- frame/staking/src/pallet/mod.rs | 22 +++++++++++----------- frame/staking/src/tests.rs | 2 +- 7 files changed, 22 insertions(+), 20 deletions(-) diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index c3d6d38cdc78f..d84a1c5888b24 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -505,6 +505,7 @@ parameter_types! { pub const MaxReportersCount: u32 = 1_000; pub const MaxPriorSlashingSpans: u32 = 1_000; pub const MaxValidatorsCount: u32 = 4_000; + pub const MaxUnlockingChunks: u32 = 32; } use frame_election_provider_support::onchain; @@ -547,6 +548,7 @@ impl pallet_staking::Config for Runtime { type MaxReportersCount = MaxReportersCount; type MaxPriorSlashingSpans = MaxPriorSlashingSpans; type MaxValidatorsCount = MaxValidatorsCount; + type MaxUnlockingChunks = MaxUnlockingChunks; } parameter_types! { diff --git a/frame/staking/README.md b/frame/staking/README.md index d1220c0cde9d8..dcf9e327d5598 100644 --- a/frame/staking/README.md +++ b/frame/staking/README.md @@ -230,7 +230,7 @@ call can be used to actually withdraw the funds. Note that there is a limitation to the number of fund-chunks that can be scheduled to be unlocked in the future via [`unbond`](https://docs.rs/pallet-staking/latest/pallet_staking/enum.Call.html#variant.unbond). In case this maximum -(`MAX_UNLOCKING_CHUNKS`) is reached, the bonded account _must_ first wait until a successful +(`MaxUnlockingChunks`) is reached, the bonded account _must_ first wait until a successful call to `withdraw_unbonded` to remove some of the chunks. ### Election Algorithm diff --git a/frame/staking/src/benchmarking.rs b/frame/staking/src/benchmarking.rs index f85b6cf15f31e..7931f18ed15ab 100644 --- a/frame/staking/src/benchmarking.rs +++ b/frame/staking/src/benchmarking.rs @@ -621,7 +621,7 @@ benchmarks! { } rebond { - let l in 1 .. MAX_UNLOCKING_CHUNKS as u32; + let l in 1 .. ::MaxUnlockingChunks::get() as u32; // clean up any existing state. clear_validators_and_nominators::(); @@ -656,7 +656,7 @@ benchmarks! { for _ in 0 .. l { staking_ledger.unlocking.try_push(unlock_chunk.clone()) - .expect("Size is smaller than MAX_UNLOCKING_CHUNKS, qed"); + .expect("Size is smaller than MaxUnlockingChunks, qed"); } Ledger::::insert(controller.clone(), staking_ledger.clone()); let original_bonded: BalanceOf = staking_ledger.active; @@ -782,7 +782,7 @@ benchmarks! { #[extra] do_slash { - let l in 1 .. MAX_UNLOCKING_CHUNKS as u32; + let l in 1 .. ::MaxUnlockingChunks::get() as u32; let (stash, controller) = create_stash_controller::(0, 100, Default::default())?; let mut staking_ledger = Ledger::::get(controller.clone()).unwrap(); let unlock_chunk = UnlockChunk::> { @@ -791,7 +791,7 @@ benchmarks! { }; for _ in 0 .. l { staking_ledger.unlocking.try_push(unlock_chunk.clone()) - .expect("Size is smaller than MAX_UNLOCKING_CHUNKS, qed"); + .expect("Size is smaller than MaxUnlockingChunks, qed"); } Ledger::::insert(controller, staking_ledger); let slash_amount = T::Currency::minimum_balance() * 10u32.into(); diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index 86985bf32a708..58ef2f5db2f51 100644 --- a/frame/staking/src/lib.rs +++ b/frame/staking/src/lib.rs @@ -255,7 +255,7 @@ //! //! Note that there is a limitation to the number of fund-chunks that can be scheduled to be //! unlocked in the future via [`unbond`](Call::unbond). In case this maximum -//! (`MAX_UNLOCKING_CHUNKS`) is reached, the bonded account _must_ first wait until a successful +//! (`MaxUnlockingChunks`) is reached, the bonded account _must_ first wait until a successful //! call to `withdraw_unbonded` to remove some of the chunks. //! //! ### Election Algorithm diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index 9a9a09784500d..a36b2713880ac 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -45,7 +45,7 @@ use sp_std::{collections::btree_map::BTreeMap, prelude::*}; use crate::{ log, slashing, weights::WeightInfo, ActiveEraInfo, BalanceOf, EraIndex, EraPayout, Exposure, ExposureOf, Forcing, IndividualExposure, Nominations, PositiveImbalanceOf, RewardDestination, - SessionInterface, StakingLedger, ValidatorPrefs, MAX_UNLOCKING_CHUNKS, + SessionInterface, StakingLedger, ValidatorPrefs, }; use super::{pallet::*, STAKING_ID}; @@ -210,7 +210,7 @@ impl Pallet { ledger: &StakingLedger< T::AccountId, BalanceOf, - ConstU32, + T::MaxUnlockingChunks, T::MaxErasForRewards, >, ) { diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index 93acb947ec729..c7f9aa46d9284 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -50,7 +50,6 @@ use crate::{ ValidatorPrefs, }; -pub const MAX_UNLOCKING_CHUNKS: u32 = 32; const STAKING_ID: LockIdentifier = *b"staking "; #[frame_support::pallet] @@ -166,6 +165,12 @@ pub mod pallet { /// Maximum number of slashing spans that is stored. type MaxPriorSlashingSpans: Get; + /// Note that there is a limitation to the number of fund-chunks that can be scheduled to be + /// unlocked in the future via [`unbond`](Call::unbond). In case this maximum + /// (`MaxUnlockingChunks`) is reached, the bonded account _must_ first wait until a + /// successful call to `withdraw_unbonded` to remove some of the chunks. + type MaxUnlockingChunks: Get; + /// Something that can provide a sorted list of voters in a somewhat sorted way. The /// original use case for this was designed with [`pallet_bags_list::Pallet`] in mind. If /// the bags-list is not desired, [`impls::UseNominatorsMap`] is likely the desired option. @@ -238,12 +243,7 @@ pub mod pallet { _, Blake2_128Concat, T::AccountId, - StakingLedger< - T::AccountId, - BalanceOf, - ConstU32, - T::MaxErasForRewards, - >, + StakingLedger, T::MaxUnlockingChunks, T::MaxErasForRewards>, >; /// Where the reward payment should be made. Keyed by stash. @@ -801,7 +801,7 @@ pub mod pallet { stash, total: value, active: value, - unlocking: BoundedVec::<_, ConstU32>::default(), + unlocking: BoundedVec::<_, T::MaxUnlockingChunks>::default(), claimed_rewards, }; Self::update_ledger(&controller, &item); @@ -866,7 +866,7 @@ pub mod pallet { /// Once the unlock period is done, you can call `withdraw_unbonded` to actually move /// the funds out of management ready for transfer. /// - /// No more than a limited number of unlocking chunks (see `MAX_UNLOCKING_CHUNKS`) + /// No more than a limited number of unlocking chunks (see `MaxUnlockingChunks`) /// can co-exists at the same time. In that case, [`Call::withdraw_unbonded`] need /// to be called first to remove some of the chunks (if possible). /// @@ -1400,10 +1400,10 @@ pub mod pallet { /// /// # /// - Time complexity: O(L), where L is unlocking chunks - /// - Bounded by `MAX_UNLOCKING_CHUNKS`. + /// - Bounded by `MaxUnlockingChunks`. /// - Storage changes: Can't increase storage, only decrease it. /// # - #[pallet::weight(T::WeightInfo::rebond(MAX_UNLOCKING_CHUNKS))] + #[pallet::weight(T::WeightInfo::rebond(T::MaxUnlockingChunks::get()))] pub fn rebond( origin: OriginFor, #[pallet::compact] value: BalanceOf, diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index 6c2bcdfdb2d95..77409fb5fc5df 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -1289,7 +1289,7 @@ fn bond_extra_and_withdraw_unbonded_works() { fn too_many_unbond_calls_should_not_work() { ExtBuilder::default().build_and_execute(|| { // locked at era 0 until 3 - for _ in 0..MAX_UNLOCKING_CHUNKS - 1 { + for _ in 0..::MaxUnlockingChunks::get() - 1 { assert_ok!(Staking::unbond(Origin::signed(10), 1)); } From b8e8559907d9c52780e3a1aee5f71bb0b859931e Mon Sep 17 00:00:00 2001 From: Georges Dib Date: Sun, 26 Sep 2021 13:01:28 +0100 Subject: [PATCH 36/80] Adding punctuation to documentation. Scope message does not need to be explicit. --- frame/staking/src/lib.rs | 14 +++++++------- frame/staking/src/pallet/mod.rs | 6 +++--- frame/staking/src/slashing.rs | 11 ++--------- frame/support/src/storage/bounded_btree_map.rs | 2 +- frame/support/src/storage/bounded_vec.rs | 2 +- 5 files changed, 14 insertions(+), 21 deletions(-) diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index 58ef2f5db2f51..cb623809000c7 100644 --- a/frame/staking/src/lib.rs +++ b/frame/staking/src/lib.rs @@ -372,7 +372,7 @@ pub struct ActiveEraInfo { /// Reward points of an era. Used to split era total payout between validators. /// /// This points will be used to reward validators and their respective nominators. -/// `Limit` bounds the number of points earned by a given validator +/// `Limit` bounds the number of points earned by a given validator. #[derive( PartialEqNoBound, Encode, Decode, DefaultNoBound, RuntimeDebugNoBound, TypeInfo, MaxEncodedLen, )] @@ -453,8 +453,8 @@ pub struct UnlockChunk { } /// The ledger of a (bonded) stash. -/// `UnlockingLimit` is the size limit of the `WeakBoundedVec` representing `unlocking` -/// `RewardsLimit` is the size limit of the `WeakBoundedVec` representing `claimed_rewards` +/// `UnlockingLimit` is the size limit of the `WeakBoundedVec` representing `unlocking`. +/// `RewardsLimit` is the size limit of the `WeakBoundedVec` representing `claimed_rewards`. #[derive( PartialEqNoBound, EqNoBound, @@ -605,7 +605,7 @@ where } /// A record of the nominations made by a specific account. -/// `Limit` bounds the number of `targets` +/// `Limit` bounds the number of `targets`. #[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, TypeInfo, MaxEncodedLen)] #[scale_info(skip_type_params(Limit))] #[codec(mel_bound(Limit: Get))] @@ -640,7 +640,7 @@ pub struct IndividualExposure { } /// A snapshot of the stake backing a single validator in the system. -/// `Limit` is the size limit of `others` bounded by `MaxNominatorRewardedPerValidator` +/// `Limit` is the size limit of `others` bounded by `MaxNominatorRewardedPerValidator`. #[derive( PartialEqNoBound, EqNoBound, @@ -701,8 +701,8 @@ where /// A pending slash record. The value of the slash has been computed but not applied yet, /// rather deferred for several eras. -/// `SlashedLimit` bounds the number of slashed accounts -/// `ReportersLimit` bounds the number of reporters +/// `SlashedLimit` bounds the number of slashed accounts. +/// `ReportersLimit` bounds the number of reporters. #[derive(Encode, Decode, RuntimeDebug, TypeInfo, MaxEncodedLen)] #[codec(mel_bound(SlashedLimit: Get, ReportersLimit: Get))] #[scale_info(skip_type_params(SlashedLimit, ReportersLimit))] diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index c7f9aa46d9284..5b41355ab6487 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -146,7 +146,7 @@ pub mod pallet { #[pallet::constant] type MaxNominatorRewardedPerValidator: Get; - /// The maximum number of unapplied slashes to be stored in `UnappliedSlashes` + /// The maximum number of unapplied slashes to be stored in `UnappliedSlashes`. type MaxUnappliedSlashes: Get; /// The maximum number of invulnerables, we expect no more than four invulnerables and @@ -677,9 +677,9 @@ pub mod pallet { /// There are too many validators in the system. Governance needs to adjust the staking /// settings to keep things safe for the runtime. TooManyValidators, - /// Too many invulnerables are passed, a runtime configuration adjustment may be needed + /// Too many invulnerables are passed, a runtime configuration adjustment may be needed. TooManyInvulnerables, - /// Too many Rewards Eras are passed, a runtime configuration adjustment may be needed + /// Too many Rewards Eras are passed, a runtime configuration adjustment may be needed. TooManyRewardsEras, } diff --git a/frame/staking/src/slashing.rs b/frame/staking/src/slashing.rs index 8bc86f4cef798..ebb65d71228aa 100644 --- a/frame/staking/src/slashing.rs +++ b/frame/staking/src/slashing.rs @@ -92,7 +92,7 @@ impl SlashingSpan { } /// An encoding of all of a nominator's slashing spans. -/// `Limit` bounds the size of the prior slashing spans vector +/// `Limit` bounds the size of the prior slashing spans vector. #[derive(Encode, Decode, RuntimeDebug, TypeInfo, MaxEncodedLen)] #[scale_info(skip_type_params(Limit))] #[codec(mel_bound(Limit: Get))] @@ -134,14 +134,7 @@ impl> SlashingSpans { } let last_length = next_start - self.last_start; - self.prior.force_insert( - 0, - last_length, - Some( - "Warning: Size of the the prior slashing spans bigger than expected. \ - A runtime adjustment may be needed.", - ), - ); + self.prior.force_insert(0, last_length, Some("SlashingSpans.prior")); self.last_start = next_start; self.span_index += 1; true diff --git a/frame/support/src/storage/bounded_btree_map.rs b/frame/support/src/storage/bounded_btree_map.rs index e0ae13066cc5d..2e49e5178f988 100644 --- a/frame/support/src/storage/bounded_btree_map.rs +++ b/frame/support/src/storage/bounded_btree_map.rs @@ -155,7 +155,7 @@ where self.0.remove_entry(key) } - /// Exactly the same semantics as [`BTreeMap::entry`] + /// Exactly the same semantics as [`BTreeMap::entry`]. /// Gets the given key's corresponding entry in the map for in-place manipulation. pub fn entry(&mut self, key: K) -> Entry<'_, K, V> where diff --git a/frame/support/src/storage/bounded_vec.rs b/frame/support/src/storage/bounded_vec.rs index 694b9498ab6a7..c3650c6c1c1a9 100644 --- a/frame/support/src/storage/bounded_vec.rs +++ b/frame/support/src/storage/bounded_vec.rs @@ -135,7 +135,7 @@ impl BoundedVec { self.0.last_mut() } - /// Exactly the same semantics as [`Vec::iter_mut`] + /// Exactly the same semantics as [`Vec::iter_mut`]. pub fn iter_mut(&mut self) -> IterMut<'_, T> { self.0.iter_mut() } From 98526da396d6aa634e257fa276552191063a9551 Mon Sep 17 00:00:00 2001 From: Georges Dib Date: Sun, 26 Sep 2021 13:18:56 +0100 Subject: [PATCH 37/80] Fixing tests after changes to `MaxUnlockingChunks` --- frame/babe/src/mock.rs | 2 + frame/grandpa/src/mock.rs | 2 + frame/offences/benchmarking/src/mock.rs | 2 + frame/session/benchmarking/src/mock.rs | 2 + frame/staking/src/mock.rs | 2 + frame/staking/src/tests.rs | 128 +++++++++++------------- 6 files changed, 70 insertions(+), 68 deletions(-) diff --git a/frame/babe/src/mock.rs b/frame/babe/src/mock.rs index 755fa3730d12d..30155e98ce371 100644 --- a/frame/babe/src/mock.rs +++ b/frame/babe/src/mock.rs @@ -196,6 +196,7 @@ parameter_types! { pub const MaxReportersCount: u32 = 1_000; pub const MaxPriorSlashingSpans: u32 = 1_000; pub const MaxValidatorsCount: u32 = 4_000; + pub const MaxUnlockingChunks: u32 = 32; } impl onchain::Config for Test { @@ -225,6 +226,7 @@ impl pallet_staking::Config for Test { type MaxReportersCount = MaxReportersCount; type MaxPriorSlashingSpans = MaxPriorSlashingSpans; type MaxValidatorsCount = MaxValidatorsCount; + type MaxUnlockingChunks = MaxUnlockingChunks; type NextNewSession = Session; type ElectionProvider = onchain::OnChainSequentialPhragmen; type GenesisElectionProvider = Self::ElectionProvider; diff --git a/frame/grandpa/src/mock.rs b/frame/grandpa/src/mock.rs index 7d6117084123c..29430bba38a96 100644 --- a/frame/grandpa/src/mock.rs +++ b/frame/grandpa/src/mock.rs @@ -198,6 +198,7 @@ parameter_types! { pub const MaxReportersCount: u32 = 1_000; pub const MaxPriorSlashingSpans: u32 = 1_000; pub const MaxValidatorsCount: u32 = 4_000; + pub const MaxUnlockingChunks: u32 = 32; } impl onchain::Config for Test { @@ -227,6 +228,7 @@ impl pallet_staking::Config for Test { type MaxReportersCount = MaxReportersCount; type MaxPriorSlashingSpans = MaxPriorSlashingSpans; type MaxValidatorsCount = MaxValidatorsCount; + type MaxUnlockingChunks = MaxUnlockingChunks; type NextNewSession = Session; type ElectionProvider = onchain::OnChainSequentialPhragmen; type GenesisElectionProvider = Self::ElectionProvider; diff --git a/frame/offences/benchmarking/src/mock.rs b/frame/offences/benchmarking/src/mock.rs index ce38892e83587..625db0b60db7f 100644 --- a/frame/offences/benchmarking/src/mock.rs +++ b/frame/offences/benchmarking/src/mock.rs @@ -157,6 +157,7 @@ parameter_types! { pub const MaxReportersCount: u32 = 1_000; pub const MaxPriorSlashingSpans: u32 = 1_000; pub const MaxValidatorsCount: u32 = 4_000; + pub const MaxUnlockingChunks: u32 = 32; } pub type Extrinsic = sp_runtime::testing::TestXt; @@ -189,6 +190,7 @@ impl pallet_staking::Config for Test { type MaxReportersCount = MaxReportersCount; type MaxPriorSlashingSpans = MaxPriorSlashingSpans; type MaxValidatorsCount = MaxValidatorsCount; + type MaxUnlockingChunks = MaxUnlockingChunks; type ElectionProvider = onchain::OnChainSequentialPhragmen; type GenesisElectionProvider = Self::ElectionProvider; type SortedListProvider = pallet_staking::UseNominatorsMap; diff --git a/frame/session/benchmarking/src/mock.rs b/frame/session/benchmarking/src/mock.rs index 40320cc9d9fe0..9628c59e42784 100644 --- a/frame/session/benchmarking/src/mock.rs +++ b/frame/session/benchmarking/src/mock.rs @@ -154,6 +154,7 @@ parameter_types! { pub const MaxReportersCount: u32 = 1_000; pub const MaxPriorSlashingSpans: u32 = 1_000; pub const MaxValidatorsCount: u32 = 4_000; + pub const MaxUnlockingChunks: u32 = 32; } pub type Extrinsic = sp_runtime::testing::TestXt; @@ -194,6 +195,7 @@ impl pallet_staking::Config for Test { type MaxReportersCount = MaxReportersCount; type MaxPriorSlashingSpans = MaxPriorSlashingSpans; type MaxValidatorsCount = MaxValidatorsCount; + type MaxUnlockingChunks = MaxUnlockingChunks; type ElectionProvider = onchain::OnChainSequentialPhragmen; type GenesisElectionProvider = Self::ElectionProvider; type SortedListProvider = pallet_staking::UseNominatorsMap; diff --git a/frame/staking/src/mock.rs b/frame/staking/src/mock.rs index b41a4e6f0f39e..69c347bb46e52 100644 --- a/frame/staking/src/mock.rs +++ b/frame/staking/src/mock.rs @@ -257,6 +257,7 @@ parameter_types! { pub const MaxReportersCount: u32 = 1_000; pub const MaxPriorSlashingSpans: u32 = 1_000; pub const MaxValidatorsCount: u32 = 100; + pub const MaxUnlockingChunks: u32 = 32; } impl pallet_bags_list::Config for Test { @@ -299,6 +300,7 @@ impl crate::pallet::pallet::Config for Test { type MaxReportersCount = MaxReportersCount; type MaxPriorSlashingSpans = MaxPriorSlashingSpans; type MaxValidatorsCount = MaxValidatorsCount; + type MaxUnlockingChunks = MaxUnlockingChunks; } impl frame_system::offchain::SendTransactionTypes for Test diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index 77409fb5fc5df..0492f38496f31 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -1221,11 +1221,10 @@ fn bond_extra_and_withdraw_unbonded_works() { stash: 11, total: 1000 + 100, active: 100, - unlocking: BoundedVec::<_, ConstU32<32>>::try_from(vec![UnlockChunk { - value: 1000, - era: 2 + 3 - }]) - .expect("32>1"), + unlocking: BoundedVec::<_, ::MaxUnlockingChunks>::try_from(vec![ + UnlockChunk { value: 1000, era: 2 + 3 } + ]) + .expect("MaxUnlockingChunks>1"), claimed_rewards: WeakBoundedVec::default(), }), ); @@ -1238,11 +1237,10 @@ fn bond_extra_and_withdraw_unbonded_works() { stash: 11, total: 1000 + 100, active: 100, - unlocking: BoundedVec::<_, ConstU32<32>>::try_from(vec![UnlockChunk { - value: 1000, - era: 2 + 3 - }]) - .expect("32>1"), + unlocking: BoundedVec::<_, ::MaxUnlockingChunks>::try_from(vec![ + UnlockChunk { value: 1000, era: 2 + 3 } + ]) + .expect("MaxUnlockingChunks>1"), claimed_rewards: WeakBoundedVec::default(), }), ); @@ -1258,11 +1256,10 @@ fn bond_extra_and_withdraw_unbonded_works() { stash: 11, total: 1000 + 100, active: 100, - unlocking: BoundedVec::<_, ConstU32<32>>::try_from(vec![UnlockChunk { - value: 1000, - era: 2 + 3 - }]) - .expect("32>1"), + unlocking: BoundedVec::<_, ::MaxUnlockingChunks>::try_from(vec![ + UnlockChunk { value: 1000, era: 2 + 3 } + ]) + .expect("MaxUnlockingChunks>1"), claimed_rewards: WeakBoundedVec::default(), }), ); @@ -1355,11 +1352,10 @@ fn rebond_works() { stash: 11, total: 1000, active: 100, - unlocking: BoundedVec::<_, ConstU32<32>>::try_from(vec![UnlockChunk { - value: 900, - era: 2 + 3 - }]) - .expect("32>1"), + unlocking: BoundedVec::<_, ::MaxUnlockingChunks>::try_from(vec![ + UnlockChunk { value: 900, era: 2 + 3 } + ]) + .expect("MaxUnlockingChunks>1"), claimed_rewards: WeakBoundedVec::default(), }) ); @@ -1385,11 +1381,10 @@ fn rebond_works() { stash: 11, total: 1000, active: 100, - unlocking: BoundedVec::<_, ConstU32<32>>::try_from(vec![UnlockChunk { - value: 900, - era: 5 - }]) - .expect("32>1"), + unlocking: BoundedVec::<_, ::MaxUnlockingChunks>::try_from(vec![ + UnlockChunk { value: 900, era: 5 } + ]) + .expect("MaxUnlockingChunks>1"), claimed_rewards: WeakBoundedVec::default(), }) ); @@ -1402,11 +1397,10 @@ fn rebond_works() { stash: 11, total: 1000, active: 600, - unlocking: BoundedVec::<_, ConstU32<32>>::try_from(vec![UnlockChunk { - value: 400, - era: 5 - }]) - .expect("32>1"), + unlocking: BoundedVec::<_, ::MaxUnlockingChunks>::try_from(vec![ + UnlockChunk { value: 400, era: 5 } + ]) + .expect("MaxUnlockingChunks>1"), claimed_rewards: WeakBoundedVec::default(), }) ); @@ -1434,12 +1428,12 @@ fn rebond_works() { stash: 11, total: 1000, active: 100, - unlocking: BoundedVec::<_, ConstU32<32>>::try_from(vec![ + unlocking: BoundedVec::<_, ::MaxUnlockingChunks>::try_from(vec![ UnlockChunk { value: 300, era: 5 }, UnlockChunk { value: 300, era: 5 }, UnlockChunk { value: 300, era: 5 }, ]) - .expect("32>3"), + .expect("MaxUnlockingChunks>3"), claimed_rewards: WeakBoundedVec::default(), }) ); @@ -1452,11 +1446,11 @@ fn rebond_works() { stash: 11, total: 1000, active: 600, - unlocking: BoundedVec::<_, ConstU32<32>>::try_from(vec![ + unlocking: BoundedVec::<_, ::MaxUnlockingChunks>::try_from(vec![ UnlockChunk { value: 300, era: 5 }, UnlockChunk { value: 100, era: 5 }, ]) - .expect("32>2"), + .expect("MaxUnlockingChunks>2"), claimed_rewards: WeakBoundedVec::default(), }) ); @@ -1498,11 +1492,10 @@ fn rebond_is_fifo() { stash: 11, total: 1000, active: 600, - unlocking: BoundedVec::<_, ConstU32<32>>::try_from(vec![UnlockChunk { - value: 400, - era: 2 + 3 - },]) - .expect("32>1"), + unlocking: BoundedVec::<_, ::MaxUnlockingChunks>::try_from(vec![ + UnlockChunk { value: 400, era: 2 + 3 }, + ]) + .expect("MaxUnlockingChunks>1"), claimed_rewards: WeakBoundedVec::default(), }) ); @@ -1517,11 +1510,11 @@ fn rebond_is_fifo() { stash: 11, total: 1000, active: 300, - unlocking: BoundedVec::<_, ConstU32<32>>::try_from(vec![ + unlocking: BoundedVec::<_, ::MaxUnlockingChunks>::try_from(vec![ UnlockChunk { value: 400, era: 2 + 3 }, UnlockChunk { value: 300, era: 3 + 3 }, ]) - .expect("32>2"), + .expect("MaxUnlockingChunks>2"), claimed_rewards: WeakBoundedVec::default(), }) ); @@ -1536,12 +1529,12 @@ fn rebond_is_fifo() { stash: 11, total: 1000, active: 100, - unlocking: BoundedVec::<_, ConstU32<32>>::try_from(vec![ + unlocking: BoundedVec::<_, ::MaxUnlockingChunks>::try_from(vec![ UnlockChunk { value: 400, era: 2 + 3 }, UnlockChunk { value: 300, era: 3 + 3 }, UnlockChunk { value: 200, era: 4 + 3 }, ]) - .expect("32>3"), + .expect("MaxUnlockingChunks>3"), claimed_rewards: WeakBoundedVec::default(), }) ); @@ -1554,11 +1547,11 @@ fn rebond_is_fifo() { stash: 11, total: 1000, active: 500, - unlocking: BoundedVec::<_, ConstU32<32>>::try_from(vec![ + unlocking: BoundedVec::<_, ::MaxUnlockingChunks>::try_from(vec![ UnlockChunk { value: 400, era: 2 + 3 }, UnlockChunk { value: 100, era: 3 + 3 }, ]) - .expect("32>2"), + .expect("MaxUnlockingChunks>2"), claimed_rewards: WeakBoundedVec::default(), }) ); @@ -1840,11 +1833,10 @@ fn bond_with_no_staked_value() { stash: 1, active: 0, total: 5, - unlocking: BoundedVec::<_, ConstU32<32>>::try_from(vec![UnlockChunk { - value: 5, - era: 3 - }]) - .expect("32>1"), + unlocking: BoundedVec::<_, ::MaxUnlockingChunks>::try_from( + vec![UnlockChunk { value: 5, era: 3 }] + ) + .expect("MaxUnlockingChunks>1"), claimed_rewards: WeakBoundedVec::default(), }) ); @@ -2138,10 +2130,11 @@ fn reward_from_authorship_event_handler_works() { assert_eq!( ErasRewardPoints::::get(active_era()), EraRewardPoints { - individual: BoundedBTreeMap::<_, _, ::MaxValidatorsCount>::try_from( - vec![(11, 20 + 2 * 2 + 1), (21, 1)].into_iter().collect::>() - ) - .expect("MaxValidatorsCount should be > 1"), + individual: + BoundedBTreeMap::<_, _, ::MaxValidatorsCount>::try_from( + vec![(11, 20 + 2 * 2 + 1), (21, 1)].into_iter().collect::>() + ) + .expect("MaxValidatorsCount should be > 1"), total: 26, }, ); @@ -2161,10 +2154,11 @@ fn add_reward_points_fns_works() { assert_eq!( ErasRewardPoints::::get(active_era()), EraRewardPoints { - individual: BoundedBTreeMap::<_, _, ::MaxValidatorsCount>::try_from( - vec![(11, 4), (21, 2)].into_iter().collect::>() - ) - .expect("MaxValidatorsCount>1"), + individual: + BoundedBTreeMap::<_, _, ::MaxValidatorsCount>::try_from( + vec![(11, 4), (21, 2)].into_iter().collect::>() + ) + .expect("MaxValidatorsCount>1"), total: 6 }, ); @@ -3790,11 +3784,10 @@ fn cannot_rebond_to_lower_than_ed() { stash: 21, total: 10 * 1000, active: 0, - unlocking: BoundedVec::<_, ConstU32<32>>::try_from(vec![UnlockChunk { - value: 10 * 1000, - era: 3 - }]) - .expect("32>1"), + unlocking: BoundedVec::<_, ::MaxUnlockingChunks>::try_from( + vec![UnlockChunk { value: 10 * 1000, era: 3 }] + ) + .expect("MaxUnlockingChunks>1"), claimed_rewards: WeakBoundedVec::default(), } ); @@ -3831,11 +3824,10 @@ fn cannot_bond_extra_to_lower_than_ed() { stash: 21, total: 10 * 1000, active: 0, - unlocking: BoundedVec::<_, ConstU32<32>>::try_from(vec![UnlockChunk { - value: 10 * 1000, - era: 3 - }]) - .expect("32>1"), + unlocking: BoundedVec::<_, ::MaxUnlockingChunks>::try_from( + vec![UnlockChunk { value: 10 * 1000, era: 3 }] + ) + .expect("MaxUnlockingChunks>1"), claimed_rewards: WeakBoundedVec::default(), } ); From cc6729bfdf1e9518744084afb1b73c29c3678a52 Mon Sep 17 00:00:00 2001 From: Georges Dib Date: Sun, 26 Sep 2021 17:03:47 +0100 Subject: [PATCH 38/80] Test fixes --- frame/babe/src/tests.rs | 2 +- frame/grandpa/src/tests.rs | 18 +++++++++++++++--- frame/support/src/storage/bounded_vec.rs | 4 +--- 3 files changed, 17 insertions(+), 7 deletions(-) diff --git a/frame/babe/src/tests.rs b/frame/babe/src/tests.rs index 1d1b9c2bcbc83..436b685eae2a2 100644 --- a/frame/babe/src/tests.rs +++ b/frame/babe/src/tests.rs @@ -533,7 +533,7 @@ fn report_equivocation_old_session_works() { assert_eq!( Staking::eras_stakers(3, offending_validator_id), pallet_staking::Exposure { total: 0, own: 0, others: WeakBoundedVec::default() }, - ); + );Ï }) } diff --git a/frame/grandpa/src/tests.rs b/frame/grandpa/src/tests.rs index 90eded6e0a48e..bfcf752423535 100644 --- a/frame/grandpa/src/tests.rs +++ b/frame/grandpa/src/tests.rs @@ -385,7 +385,11 @@ fn report_equivocation_current_set_works() { assert_eq!( Staking::eras_stakers(2, validator), - pallet_staking::Exposure { total: 10_000, own: 10_000, others: WeakBoundedVec::default() }, + pallet_staking::Exposure { + total: 10_000, + own: 10_000, + others: WeakBoundedVec::default() + }, ); } }); @@ -417,7 +421,11 @@ fn report_equivocation_old_set_works() { assert_eq!( Staking::eras_stakers(2, validator), - pallet_staking::Exposure { total: 10_000, own: 10_000, others: WeakBoundedVec::default() }, + pallet_staking::Exposure { + total: 10_000, + own: 10_000, + others: WeakBoundedVec::default() + }, ); } @@ -464,7 +472,11 @@ fn report_equivocation_old_set_works() { assert_eq!( Staking::eras_stakers(3, validator), - pallet_staking::Exposure { total: 10_000, own: 10_000, others: WeakBoundedVec::default() }, + pallet_staking::Exposure { + total: 10_000, + own: 10_000, + others: WeakBoundedVec::default() + }, ); } }); diff --git a/frame/support/src/storage/bounded_vec.rs b/frame/support/src/storage/bounded_vec.rs index c3650c6c1c1a9..a2b0506932892 100644 --- a/frame/support/src/storage/bounded_vec.rs +++ b/frame/support/src/storage/bounded_vec.rs @@ -28,9 +28,7 @@ use core::{ ops::{Deref, Index, IndexMut}, slice::{IterMut, SliceIndex}, }; -use sp_std::{ - convert::TryFrom, marker::PhantomData, ops::RangeBounds, prelude::*, vec::Drain, -}; +use sp_std::{convert::TryFrom, marker::PhantomData, ops::RangeBounds, prelude::*, vec::Drain}; /// A bounded vector. /// From 0c8fa9ff552d14ef95c63f79dc01d59394447252 Mon Sep 17 00:00:00 2001 From: Georges Dib Date: Sun, 26 Sep 2021 17:04:30 +0100 Subject: [PATCH 39/80] Test fixes --- frame/staking/src/mock.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frame/staking/src/mock.rs b/frame/staking/src/mock.rs index 69c347bb46e52..e21d3173d99c3 100644 --- a/frame/staking/src/mock.rs +++ b/frame/staking/src/mock.rs @@ -252,7 +252,7 @@ parameter_types! { pub static BagThresholds: &'static [sp_npos_elections::VoteWeight] = &THRESHOLDS; pub const MaxNominations: u32 = 16; pub const MaxUnappliedSlashes: u32 = 1_000; - pub const MaxInvulnerablesCount: u32 = 10; + pub const MaxInvulnerablesCount: u32 = 100; pub const MaxErasForRewards: u32 = 10_000; pub const MaxReportersCount: u32 = 1_000; pub const MaxPriorSlashingSpans: u32 = 1_000; From a024de5c069749b54ee899063669737aa728b919 Mon Sep 17 00:00:00 2001 From: Georges Dib Date: Sun, 26 Sep 2021 18:33:15 +0100 Subject: [PATCH 40/80] Adding `MaxIndividualExposures` replacing `MaxNominatorRewardedPerValidator` at some places --- bin/node/runtime/src/lib.rs | 5 +- frame/offences/benchmarking/src/lib.rs | 5 +- frame/staking/src/benchmarking.rs | 2 +- frame/staking/src/lib.rs | 12 ++-- frame/staking/src/mock.rs | 4 +- frame/staking/src/pallet/impls.rs | 56 +++++++++---------- frame/staking/src/pallet/mod.rs | 7 ++- frame/staking/src/slashing.rs | 20 +++---- frame/staking/src/tests.rs | 27 ++++----- frame/support/src/storage/weak_bounded_vec.rs | 8 --- 10 files changed, 67 insertions(+), 79 deletions(-) diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index d84a1c5888b24..af0220200349b 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -475,8 +475,7 @@ impl pallet_session::Config for Runtime { } impl pallet_session::historical::Config for Runtime { - type FullIdentification = - pallet_staking::Exposure; + type FullIdentification = pallet_staking::Exposure; type FullIdentificationOf = pallet_staking::ExposureOf; } @@ -498,6 +497,7 @@ parameter_types! { pub const RewardCurve: &'static PiecewiseLinear<'static> = &REWARD_CURVE; pub const MaxNominatorRewardedPerValidator: u32 = 256; pub OffchainRepeat: BlockNumber = 5; + pub const MaxIndividualExposures: u32 = 256; pub const MaxNominations: u32 = MAX_NOMINATIONS; pub const MaxUnappliedSlashes: u32 = 1_000; pub const MaxInvulnerablesCount: u32 = 10; @@ -541,6 +541,7 @@ impl pallet_staking::Config for Runtime { // Note that the aforementioned does not scale to a very large number of nominators. type SortedListProvider = BagsList; type WeightInfo = pallet_staking::weights::SubstrateWeight; + type MaxIndividualExposures = MaxIndividualExposures; type MaxNominations = MaxNominations; type MaxUnappliedSlashes = MaxUnappliedSlashes; type MaxInvulnerablesCount = MaxInvulnerablesCount; diff --git a/frame/offences/benchmarking/src/lib.rs b/frame/offences/benchmarking/src/lib.rs index 5d860b0a4729d..df933345e0695 100644 --- a/frame/offences/benchmarking/src/lib.rs +++ b/frame/offences/benchmarking/src/lib.rs @@ -150,9 +150,8 @@ fn create_offender(n: u32, nominators: u32) -> Result, &' nominator_stashes.push(nominator_stash.clone()); } - let others = - WeakBoundedVec::<_, T::MaxNominatorRewardedPerValidator>::try_from(individual_exposures) - .expect("nominators too big, runtime benchmarks may need adjustment"); + let others = WeakBoundedVec::<_, T::MaxIndividualExposures>::try_from(individual_exposures) + .map_err(|_| "nominators too big, runtime benchmarks may need adjustment")?; let exposure = Exposure { total: amount.clone() * n.into(), own: amount, others }; let current_era = 0u32; Staking::::add_era_stakers(current_era.into(), stash.clone().into(), exposure); diff --git a/frame/staking/src/benchmarking.rs b/frame/staking/src/benchmarking.rs index 7931f18ed15ab..acf7c2beebd67 100644 --- a/frame/staking/src/benchmarking.rs +++ b/frame/staking/src/benchmarking.rs @@ -538,7 +538,7 @@ benchmarks! { let mut unapplied_slashes = Vec::new(); let era = EraIndex::one(); for _ in 0 .. MAX_SLASHES { - unapplied_slashes.push(UnappliedSlash::, T::MaxNominatorRewardedPerValidator, + unapplied_slashes.push(UnappliedSlash::, T::MaxIndividualExposures, T::MaxReportersCount>::default()); } let unapplied_slashes = WeakBoundedVec::<_, T::MaxUnappliedSlashes>::try_from(unapplied_slashes) diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index cb623809000c7..d50e044c18e58 100644 --- a/frame/staking/src/lib.rs +++ b/frame/staking/src/lib.rs @@ -640,7 +640,7 @@ pub struct IndividualExposure { } /// A snapshot of the stake backing a single validator in the system. -/// `Limit` is the size limit of `others` bounded by `MaxNominatorRewardedPerValidator`. +/// `Limit` is the size limit of `others`. #[derive( PartialEqNoBound, EqNoBound, @@ -767,7 +767,7 @@ where FullIdentification = Exposure< ::AccountId, BalanceOf, - T::MaxNominatorRewardedPerValidator, + T::MaxIndividualExposures, >, FullIdentificationOf = ExposureOf, >, @@ -898,14 +898,12 @@ impl Convert> for StashOf { pub struct ExposureOf(sp_std::marker::PhantomData); impl - Convert< - T::AccountId, - Option, T::MaxNominatorRewardedPerValidator>>, - > for ExposureOf + Convert, T::MaxIndividualExposures>>> + for ExposureOf { fn convert( validator: T::AccountId, - ) -> Option, T::MaxNominatorRewardedPerValidator>> { + ) -> Option, T::MaxIndividualExposures>> { >::active_era() .map(|active_era| >::eras_stakers(active_era.index, &validator)) } diff --git a/frame/staking/src/mock.rs b/frame/staking/src/mock.rs index e21d3173d99c3..645496ef2af3f 100644 --- a/frame/staking/src/mock.rs +++ b/frame/staking/src/mock.rs @@ -196,7 +196,7 @@ impl pallet_session::Config for Test { } impl pallet_session::historical::Config for Test { - type FullIdentification = crate::Exposure; + type FullIdentification = crate::Exposure; type FullIdentificationOf = crate::ExposureOf; } impl pallet_authorship::Config for Test { @@ -228,6 +228,7 @@ parameter_types! { pub const BondingDuration: EraIndex = 3; pub const RewardCurve: &'static PiecewiseLinear<'static> = &I_NPOS; pub const MaxNominatorRewardedPerValidator: u32 = 64; + pub const MaxIndividualExposures: u32 = 64; } thread_local! { @@ -288,6 +289,7 @@ impl crate::pallet::pallet::Config for Test { type EraPayout = ConvertCurve; type NextNewSession = Session; type MaxNominatorRewardedPerValidator = MaxNominatorRewardedPerValidator; + type MaxIndividualExposures = MaxIndividualExposures; type ElectionProvider = onchain::OnChainSequentialPhragmen; type GenesisElectionProvider = Self::ElectionProvider; type WeightInfo = (); diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index a36b2713880ac..27bc2ad511faf 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -40,7 +40,7 @@ use sp_staking::{ offence::{OffenceDetails, OnOffenceHandler}, SessionIndex, }; -use sp_std::{collections::btree_map::BTreeMap, prelude::*}; +use sp_std::{collections::btree_map::BTreeMap, convert::TryFrom, prelude::*}; use crate::{ log, slashing, weights::WeightInfo, ActiveEraInfo, BalanceOf, EraIndex, EraPayout, Exposure, @@ -398,7 +398,7 @@ impl Pallet { start_session_index: SessionIndex, exposures: Vec<( T::AccountId, - Exposure, T::MaxNominatorRewardedPerValidator>, + Exposure, T::MaxIndividualExposures>, )>, ) -> Vec { // Increment or set current era. @@ -477,7 +477,7 @@ impl Pallet { pub fn store_stakers_info( exposures: Vec<( T::AccountId, - Exposure, T::MaxNominatorRewardedPerValidator>, + Exposure, T::MaxIndividualExposures>, )>, new_planned_era: EraIndex, ) -> Vec { @@ -489,12 +489,21 @@ impl Pallet { total_stake = total_stake.saturating_add(exposure.total); >::insert(new_planned_era, &stash, &exposure); - let mut exposure_clipped = exposure; + let mut others = exposure.others.to_vec(); let clipped_max_len = T::MaxNominatorRewardedPerValidator::get() as usize; - if exposure_clipped.others.len() > clipped_max_len { - exposure_clipped.others.sort_by(|a, b| a.value.cmp(&b.value).reverse()); - exposure_clipped.others.truncate(clipped_max_len); + if others.len() > clipped_max_len { + others.sort_by(|a, b| a.value.cmp(&b.value).reverse()); + others.truncate(clipped_max_len); } + + let others = WeakBoundedVec::<_, T::MaxNominatorRewardedPerValidator>::try_from(others) + .expect("Vec was clipped, so this has to work, qed"); + let exposure_clipped = + Exposure::, T::MaxNominatorRewardedPerValidator> { + total: exposure.total, + own: exposure.own, + others, + }; >::insert(&new_planned_era, &stash, exposure_clipped); }); @@ -523,10 +532,7 @@ impl Pallet { /// [`Exposure`]. fn collect_exposures( supports: Supports, - ) -> Vec<( - T::AccountId, - Exposure, T::MaxNominatorRewardedPerValidator>, - )> { + ) -> Vec<(T::AccountId, Exposure, T::MaxIndividualExposures>)> { let total_issuance = T::Currency::total_issuance(); let to_currency = |e: frame_election_provider_support::ExtendedBalance| { T::CurrencyToVote::to_currency(e, total_issuance) @@ -552,7 +558,7 @@ impl Pallet { total = total.saturating_add(stake); }); - let others = WeakBoundedVec::<_, T::MaxNominatorRewardedPerValidator>::force_from( + let others = WeakBoundedVec::<_, T::MaxIndividualExposures>::force_from( others, Some("exposure.others"), ); @@ -560,7 +566,7 @@ impl Pallet { let exposure = Exposure { own, others, total }; (validator, exposure) }) - .collect::)>>() + .collect::)>>() } /// Remove all associated data of a stash account from the staking system. @@ -650,7 +656,7 @@ impl Pallet { pub fn add_era_stakers( current_era: EraIndex, controller: T::AccountId, - exposure: Exposure, T::MaxNominatorRewardedPerValidator>, + exposure: Exposure, T::MaxIndividualExposures>, ) { >::insert(¤t_era, &controller, &exposure); } @@ -941,7 +947,6 @@ impl ElectionDataProvider> for Pallet /// into a `BalanceOf`. #[cfg(feature = "runtime-benchmarks")] fn add_voter(voter: T::AccountId, weight: VoteWeight, targets: Vec) { - use sp_std::convert::TryFrom; let stake = >::try_from(weight).unwrap_or_else(|_| { panic!("cannot convert a VoteWeight into BalanceOf, benchmark needs reconfiguring.") }); @@ -1003,7 +1008,6 @@ impl ElectionDataProvider> for Pallet targets: Vec, target_stake: Option, ) { - use sp_std::convert::TryFrom; targets.into_iter().for_each(|v| { let stake: BalanceOf = target_stake .and_then(|w| >::try_from(w).ok()) @@ -1076,17 +1080,13 @@ impl pallet_session::SessionManager for Pallet { impl historical::SessionManager< T::AccountId, - Exposure, T::MaxNominatorRewardedPerValidator>, + Exposure, T::MaxIndividualExposures>, > for Pallet { fn new_session( new_index: SessionIndex, - ) -> Option< - Vec<( - T::AccountId, - Exposure, T::MaxNominatorRewardedPerValidator>, - )>, - > { + ) -> Option, T::MaxIndividualExposures>)>> + { >::new_session(new_index).map(|validators| { let current_era = Self::current_era() // Must be some as a new era has been created. @@ -1103,12 +1103,8 @@ impl } fn new_session_genesis( new_index: SessionIndex, - ) -> Option< - Vec<( - T::AccountId, - Exposure, T::MaxNominatorRewardedPerValidator>, - )>, - > { + ) -> Option, T::MaxIndividualExposures>)>> + { >::new_session_genesis(new_index).map( |validators| { let current_era = Self::current_era() @@ -1159,7 +1155,7 @@ where FullIdentification = Exposure< ::AccountId, BalanceOf, - T::MaxNominatorRewardedPerValidator, + T::MaxIndividualExposures, >, FullIdentificationOf = ExposureOf, >, diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index 5b41355ab6487..b0804fb73c87c 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -146,6 +146,9 @@ pub mod pallet { #[pallet::constant] type MaxNominatorRewardedPerValidator: Get; + /// The maximum number of exposure of a certain validator at a given era. + type MaxIndividualExposures: Get; + /// The maximum number of unapplied slashes to be stored in `UnappliedSlashes`. type MaxUnappliedSlashes: Get; @@ -320,7 +323,7 @@ pub mod pallet { EraIndex, Twox64Concat, T::AccountId, - Exposure, T::MaxNominatorRewardedPerValidator>, + Exposure, T::MaxIndividualExposures>, ValueQuery, >; @@ -419,7 +422,7 @@ pub mod pallet { UnappliedSlash< T::AccountId, BalanceOf, - T::MaxNominatorRewardedPerValidator, + T::MaxIndividualExposures, T::MaxReportersCount, >, T::MaxUnappliedSlashes, diff --git a/frame/staking/src/slashing.rs b/frame/staking/src/slashing.rs index ebb65d71228aa..59b58e11eed00 100644 --- a/frame/staking/src/slashing.rs +++ b/frame/staking/src/slashing.rs @@ -210,8 +210,7 @@ pub(crate) struct SlashParams<'a, T: 'a + Config> { /// The proportion of the slash. pub(crate) slash: Perbill, /// The exposure of the stash and all nominators. - pub(crate) exposure: - &'a Exposure, T::MaxNominatorRewardedPerValidator>, + pub(crate) exposure: &'a Exposure, T::MaxIndividualExposures>, /// The era where the offence occurred. pub(crate) slash_era: EraIndex, /// The first era in the current bonding period. @@ -232,12 +231,7 @@ pub(crate) struct SlashParams<'a, T: 'a + Config> { pub(crate) fn compute_slash( params: SlashParams, ) -> Option< - UnappliedSlash< - T::AccountId, - BalanceOf, - T::MaxNominatorRewardedPerValidator, - T::MaxReportersCount, - >, + UnappliedSlash, T::MaxIndividualExposures, T::MaxReportersCount>, > { let SlashParams { stash, slash, exposure, slash_era, window_start, now, reward_proportion } = params.clone(); @@ -348,7 +342,7 @@ fn slash_nominators( prior_slash_p: Perbill, nominators_slashed: &mut WeakBoundedVec< (T::AccountId, BalanceOf), - T::MaxNominatorRewardedPerValidator, + T::MaxIndividualExposures, >, ) -> BalanceOf { let SlashParams { stash: _, slash, exposure, slash_era, window_start, now, reward_proportion } = @@ -401,8 +395,10 @@ fn slash_nominators( slashed_nominators.push((stash.clone(), nom_slashed)); } - *nominators_slashed = WeakBoundedVec::<_, T::MaxNominatorRewardedPerValidator>::try_from(slashed_nominators) - .expect("slashed_nominators has a size of exposure.others which is MaxNominatorRewardedPerValidator"); + *nominators_slashed = WeakBoundedVec::<_, T::MaxIndividualExposures>::try_from( + slashed_nominators, + ) + .expect("slashed_nominators has a size of exposure.others which is MaxIndividualExposures"); reward_payout } @@ -616,7 +612,7 @@ pub(crate) fn apply_slash( unapplied_slash: UnappliedSlash< T::AccountId, BalanceOf, - T::MaxNominatorRewardedPerValidator, + T::MaxIndividualExposures, T::MaxReportersCount, >, ) { diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index 0492f38496f31..a4eb76e4a9d0a 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -149,7 +149,7 @@ fn basic_setup_works() { Exposure { total: 1125, own: 1000, - others: WeakBoundedVec::<_, ::MaxNominatorRewardedPerValidator>::try_from( + others: WeakBoundedVec::<_, ::MaxIndividualExposures>::try_from( vec![IndividualExposure { who: 101, value: 125 }] ) .expect("Please adjust testing parameters"), @@ -160,8 +160,8 @@ fn basic_setup_works() { Exposure { total: 1375, own: 1000, - others: WeakBoundedVec::<_, ::MaxNominatorRewardedPerValidator>::try_from( - vec![IndividualExposure { who: 101, value: 375}] + others: WeakBoundedVec::<_, ::MaxIndividualExposures>::try_from( + vec![IndividualExposure { who: 101, value: 375 }] ) .expect("Please adjust testing parameters"), }, @@ -544,7 +544,7 @@ fn nominating_and_rewards_should_work() { assert_eq!(Balances::total_balance(&20), initial_balance_20 + total_payout_0 / 2); initial_balance_20 = Balances::total_balance(&20); - let mut others = WeakBoundedVec::<_, MaxNominatorRewardedPerValidator>::try_from(vec![ + let mut others = WeakBoundedVec::<_, MaxIndividualExposures>::try_from(vec![ IndividualExposure { who: 1, value: 400 }, IndividualExposure { who: 3, value: 400 }, ]) @@ -556,7 +556,7 @@ fn nominating_and_rewards_should_work() { Exposure { total: 1000 + 800, own: 1000, others }, ); - others = WeakBoundedVec::<_, MaxNominatorRewardedPerValidator>::try_from(vec![ + others = WeakBoundedVec::<_, MaxIndividualExposures>::try_from(vec![ IndividualExposure { who: 1, value: 600 }, IndividualExposure { who: 3, value: 600 }, ]) @@ -2055,12 +2055,11 @@ fn reward_validator_slashing_validator_does_not_overflow() { // Set staker let _ = Balances::make_free_balance_be(&11, stake); - let exposure = - Exposure::::MaxNominatorRewardedPerValidator> { - total: stake, - own: stake, - others: WeakBoundedVec::default(), - }; + let exposure = Exposure::::MaxIndividualExposures> { + total: stake, + own: stake, + others: WeakBoundedVec::default(), + }; let reward = EraRewardPoints { total: 1, individual: BoundedBTreeMap::<_, _, ::MaxValidatorsCount>::try_from( @@ -2091,8 +2090,10 @@ fn reward_validator_slashing_validator_does_not_overflow() { Exposure { total: stake, own: 1, - others: WeakBoundedVec::<_, ::MaxNominatorRewardedPerValidator>::try_from( - vec![IndividualExposure { who: 2, value: stake - 1 }]).expect("MaxNominatorRewardedPerValidator>0"), + others: WeakBoundedVec::<_, ::MaxIndividualExposures>::try_from( + vec![IndividualExposure { who: 2, value: stake - 1 }], + ) + .expect("MaxIndividualExposures>0"), }, ); diff --git a/frame/support/src/storage/weak_bounded_vec.rs b/frame/support/src/storage/weak_bounded_vec.rs index f3f73606c3e13..7463d6e1c5742 100644 --- a/frame/support/src/storage/weak_bounded_vec.rs +++ b/frame/support/src/storage/weak_bounded_vec.rs @@ -84,14 +84,6 @@ impl WeakBoundedVec { self.0.drain(range) } - /// Exactly the same semantics as [`Vec::sort_by`]. - pub fn sort_by(&mut self, compare: F) - where - F: FnMut(&T, &T) -> Ordering, - { - self.0.sort_by(compare); - } - /// Exactly the same semantics as [`Vec::truncate`]. /// /// # Panics From de68fd2d61344e9317db005a1b9113d3e0a38e0d Mon Sep 17 00:00:00 2001 From: Georges Dib Date: Sun, 26 Sep 2021 18:44:49 +0100 Subject: [PATCH 41/80] Fixing tests after adding `MaxIndividualExposures` --- frame/babe/src/mock.rs | 4 +++- frame/babe/src/tests.rs | 8 ++++++-- frame/grandpa/src/mock.rs | 4 +++- frame/offences/benchmarking/src/mock.rs | 5 +++-- frame/session/benchmarking/src/mock.rs | 5 +++-- frame/staking/src/tests.rs | 9 ++++++++- 6 files changed, 26 insertions(+), 9 deletions(-) diff --git a/frame/babe/src/mock.rs b/frame/babe/src/mock.rs index 30155e98ce371..0619635d03608 100644 --- a/frame/babe/src/mock.rs +++ b/frame/babe/src/mock.rs @@ -127,7 +127,7 @@ impl pallet_session::Config for Test { } impl pallet_session::historical::Config for Test { - type FullIdentification = pallet_staking::Exposure; + type FullIdentification = pallet_staking::Exposure; type FullIdentificationOf = pallet_staking::ExposureOf; } @@ -187,6 +187,7 @@ parameter_types! { pub const AttestationPeriod: u64 = 100; pub const RewardCurve: &'static PiecewiseLinear<'static> = &REWARD_CURVE; pub const MaxNominatorRewardedPerValidator: u32 = 64; + pub const MaxIndividualExposures: u32 = 64; pub const ElectionLookahead: u64 = 0; pub const StakingUnsignedPriority: u64 = u64::MAX / 2; pub const MaxNominations: u32 = 16; @@ -219,6 +220,7 @@ impl pallet_staking::Config for Test { type UnixTime = pallet_timestamp::Pallet; type EraPayout = pallet_staking::ConvertCurve; type MaxNominatorRewardedPerValidator = MaxNominatorRewardedPerValidator; + type MaxIndividualExposures = MaxIndividualExposures; type MaxNominations = MaxNominations; type MaxUnappliedSlashes = MaxUnappliedSlashes; type MaxInvulnerablesCount = MaxInvulnerablesCount; diff --git a/frame/babe/src/tests.rs b/frame/babe/src/tests.rs index 436b685eae2a2..daf99152d306a 100644 --- a/frame/babe/src/tests.rs +++ b/frame/babe/src/tests.rs @@ -473,7 +473,11 @@ fn report_equivocation_current_session_works() { assert_eq!(Staking::slashable_balance_of(validator), 10_000); assert_eq!( Staking::eras_stakers(2, validator), - pallet_staking::Exposure { total: 10_000, own: 10_000, others: WeakBoundedVec::default() }, + pallet_staking::Exposure { + total: 10_000, + own: 10_000, + others: WeakBoundedVec::default() + }, ); } }) @@ -533,7 +537,7 @@ fn report_equivocation_old_session_works() { assert_eq!( Staking::eras_stakers(3, offending_validator_id), pallet_staking::Exposure { total: 0, own: 0, others: WeakBoundedVec::default() }, - );Ï + ); }) } diff --git a/frame/grandpa/src/mock.rs b/frame/grandpa/src/mock.rs index 29430bba38a96..1f416ff0ae650 100644 --- a/frame/grandpa/src/mock.rs +++ b/frame/grandpa/src/mock.rs @@ -129,7 +129,7 @@ impl pallet_session::Config for Test { } impl pallet_session::historical::Config for Test { - type FullIdentification = pallet_staking::Exposure; + type FullIdentification = pallet_staking::Exposure; type FullIdentificationOf = pallet_staking::ExposureOf; } @@ -189,6 +189,7 @@ parameter_types! { pub const AttestationPeriod: u64 = 100; pub const RewardCurve: &'static PiecewiseLinear<'static> = &REWARD_CURVE; pub const MaxNominatorRewardedPerValidator: u32 = 64; + pub const MaxIndividualExposures: u32 = 64; pub const ElectionLookahead: u64 = 0; pub const StakingUnsignedPriority: u64 = u64::MAX / 2; pub const MaxNominations: u32 = 16; @@ -221,6 +222,7 @@ impl pallet_staking::Config for Test { type UnixTime = pallet_timestamp::Pallet; type EraPayout = pallet_staking::ConvertCurve; type MaxNominatorRewardedPerValidator = MaxNominatorRewardedPerValidator; + type MaxIndividualExposures = MaxIndividualExposures; type MaxNominations = MaxNominations; type MaxUnappliedSlashes = MaxUnappliedSlashes; type MaxInvulnerablesCount = MaxInvulnerablesCount; diff --git a/frame/offences/benchmarking/src/mock.rs b/frame/offences/benchmarking/src/mock.rs index 625db0b60db7f..21b2c198e98af 100644 --- a/frame/offences/benchmarking/src/mock.rs +++ b/frame/offences/benchmarking/src/mock.rs @@ -89,8 +89,7 @@ impl pallet_timestamp::Config for Test { type WeightInfo = (); } impl pallet_session::historical::Config for Test { - type FullIdentification = - pallet_staking::Exposure; + type FullIdentification = pallet_staking::Exposure; type FullIdentificationOf = pallet_staking::ExposureOf; } @@ -147,6 +146,7 @@ pallet_staking_reward_curve::build! { parameter_types! { pub const RewardCurve: &'static sp_runtime::curve::PiecewiseLinear<'static> = &I_NPOS; pub const MaxNominatorRewardedPerValidator: u32 = 64; + pub const MaxIndividualExposures: u32 = 64; pub const MaxKeys: u32 = 10_000; pub const MaxPeerInHeartbeats: u32 = 10_000; pub const MaxPeerDataEncodingSize: u32 = 1_000; @@ -183,6 +183,7 @@ impl pallet_staking::Config for Test { type EraPayout = pallet_staking::ConvertCurve; type NextNewSession = Session; type MaxNominatorRewardedPerValidator = MaxNominatorRewardedPerValidator; + type MaxIndividualExposures = MaxIndividualExposures; type MaxNominations = MaxNominations; type MaxUnappliedSlashes = MaxUnappliedSlashes; type MaxInvulnerablesCount = MaxInvulnerablesCount; diff --git a/frame/session/benchmarking/src/mock.rs b/frame/session/benchmarking/src/mock.rs index 9628c59e42784..b6eb0a422c8b6 100644 --- a/frame/session/benchmarking/src/mock.rs +++ b/frame/session/benchmarking/src/mock.rs @@ -94,8 +94,7 @@ impl pallet_timestamp::Config for Test { type WeightInfo = (); } impl pallet_session::historical::Config for Test { - type FullIdentification = - pallet_staking::Exposure; + type FullIdentification = pallet_staking::Exposure; type FullIdentificationOf = pallet_staking::ExposureOf; } @@ -146,6 +145,7 @@ pallet_staking_reward_curve::build! { parameter_types! { pub const RewardCurve: &'static sp_runtime::curve::PiecewiseLinear<'static> = &I_NPOS; pub const MaxNominatorRewardedPerValidator: u32 = 64; + pub const MaxIndividualExposures: u32 = 64; pub const UnsignedPriority: u64 = 1 << 20; pub const MaxNominations: u32 = 16; pub const MaxUnappliedSlashes: u32 = 1_000; @@ -188,6 +188,7 @@ impl pallet_staking::Config for Test { type EraPayout = pallet_staking::ConvertCurve; type NextNewSession = Session; type MaxNominatorRewardedPerValidator = MaxNominatorRewardedPerValidator; + type MaxIndividualExposures = MaxIndividualExposures; type MaxNominations = MaxNominations; type MaxUnappliedSlashes = MaxUnappliedSlashes; type MaxInvulnerablesCount = MaxInvulnerablesCount; diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index a4eb76e4a9d0a..1a271fab3ac8b 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -2071,7 +2071,14 @@ fn reward_validator_slashing_validator_does_not_overflow() { // Check reward ErasRewardPoints::::insert(0, reward); ErasStakers::::insert(0, 11, &exposure); - ErasStakersClipped::::insert(0, 11, exposure); + + let exposure_clipped = + Exposure::::MaxNominatorRewardedPerValidator> { + total: stake, + own: stake, + others: WeakBoundedVec::default(), + }; + ErasStakersClipped::::insert(0, 11, exposure_clipped); ErasValidatorReward::::insert(0, stake); assert_ok!(Staking::payout_stakers(Origin::signed(1337), 11, 0)); assert_eq!(Balances::total_balance(&11), stake * 2); From 531f43a07bcc679f8d738a1e200a8fc685340e97 Mon Sep 17 00:00:00 2001 From: Georges Dib Date: Sun, 26 Sep 2021 21:45:44 +0100 Subject: [PATCH 42/80] Removing trailing whitespace --- frame/election-provider-multi-phase/src/benchmarking.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frame/election-provider-multi-phase/src/benchmarking.rs b/frame/election-provider-multi-phase/src/benchmarking.rs index 1b26dce11ba9a..6061838539484 100644 --- a/frame/election-provider-multi-phase/src/benchmarking.rs +++ b/frame/election-provider-multi-phase/src/benchmarking.rs @@ -169,7 +169,7 @@ fn set_up_data_provider(v: u32, t: u32) { }) .collect::>(); // we should always have enough voters to fill. - let max_votes = + let max_votes = >::MaximumVotesPerVoter::get() as usize; assert!(targets.len() > max_votes); targets.truncate(max_votes); From 84d2b13e1de856e1360b1f55c19385fb40c6411a Mon Sep 17 00:00:00 2001 From: Georges Dib Date: Sun, 26 Sep 2021 22:07:14 +0100 Subject: [PATCH 43/80] Fixing tests post merge --- frame/staking/src/tests.rs | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index 988142e9e22d4..d86c197545068 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -1580,8 +1580,11 @@ fn rebond_emits_right_value_in_event() { stash: 11, total: 1000, active: 100, - unlocking: vec![UnlockChunk { value: 900, era: 1 + 3 }], - claimed_rewards: vec![], + unlocking: BoundedVec::<_, ::MaxUnlockingChunks>::try_from(vec![ + UnlockChunk { value: 900, era: 1 + 3 } + ]) + .expect("MaxUnlockingChunks>1"), + claimed_rewards: WeakBoundedVec::default(), }) ); @@ -1593,8 +1596,11 @@ fn rebond_emits_right_value_in_event() { stash: 11, total: 1000, active: 200, - unlocking: vec![UnlockChunk { value: 800, era: 1 + 3 }], - claimed_rewards: vec![], + unlocking: BoundedVec::<_, ::MaxUnlockingChunks>::try_from( + vec![UnlockChunk { value: 800, era: 1 + 3 }] + ) + .expect("MaxUnlockingChunks>1"), + claimed_rewards: WeakBoundedVec::default(), }) ); // Event emitted should be correct @@ -1608,8 +1614,8 @@ fn rebond_emits_right_value_in_event() { stash: 11, total: 1000, active: 1000, - unlocking: vec![], - claimed_rewards: vec![], + unlocking: BoundedVec::default(), + claimed_rewards: WeakBoundedVec::default(), }) ); // Event emitted should be correct, only 800 From a2f7055a488ddeaf72db3090dcc761efb975b26a Mon Sep 17 00:00:00 2001 From: Georges Dib Date: Sun, 26 Sep 2021 23:01:09 +0100 Subject: [PATCH 44/80] fmt --- frame/staking/src/tests.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index d86c197545068..6a37ae67d1536 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -1596,9 +1596,9 @@ fn rebond_emits_right_value_in_event() { stash: 11, total: 1000, active: 200, - unlocking: BoundedVec::<_, ::MaxUnlockingChunks>::try_from( - vec![UnlockChunk { value: 800, era: 1 + 3 }] - ) + unlocking: BoundedVec::<_, ::MaxUnlockingChunks>::try_from(vec![ + UnlockChunk { value: 800, era: 1 + 3 } + ]) .expect("MaxUnlockingChunks>1"), claimed_rewards: WeakBoundedVec::default(), }) From 5705c2522484ff681efff42a2c0749b603c10690 Mon Sep 17 00:00:00 2001 From: Georges Dib Date: Mon, 27 Sep 2021 22:38:25 +0100 Subject: [PATCH 45/80] Renaming `MaxNominatorRewardedPerValidator` to `MaxRewardableIndividualExposures` --- bin/node/runtime/src/lib.rs | 4 ++-- frame/babe/src/mock.rs | 4 ++-- frame/grandpa/src/mock.rs | 4 ++-- frame/offences/benchmarking/src/mock.rs | 4 ++-- frame/session/benchmarking/src/mock.rs | 4 ++-- frame/staking/README.md | 2 +- frame/staking/fuzzer/src/mock.rs | 4 ++-- frame/staking/src/benchmarking.rs | 12 ++++++------ frame/staking/src/lib.rs | 2 +- frame/staking/src/mock.rs | 4 ++-- frame/staking/src/pallet/impls.rs | 8 ++++---- frame/staking/src/pallet/mod.rs | 14 +++++++------- frame/staking/src/tests.rs | 8 ++++---- 13 files changed, 37 insertions(+), 37 deletions(-) diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index af0220200349b..2297dabae2cae 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -495,7 +495,7 @@ parameter_types! { pub const BondingDuration: pallet_staking::EraIndex = 24 * 28; pub const SlashDeferDuration: pallet_staking::EraIndex = 24 * 7; // 1/4 the bonding duration. pub const RewardCurve: &'static PiecewiseLinear<'static> = &REWARD_CURVE; - pub const MaxNominatorRewardedPerValidator: u32 = 256; + pub const MaxRewardableIndividualExposures: u32 = 256; pub OffchainRepeat: BlockNumber = 5; pub const MaxIndividualExposures: u32 = 256; pub const MaxNominations: u32 = MAX_NOMINATIONS; @@ -534,7 +534,7 @@ impl pallet_staking::Config for Runtime { type SessionInterface = Self; type EraPayout = pallet_staking::ConvertCurve; type NextNewSession = Session; - type MaxNominatorRewardedPerValidator = MaxNominatorRewardedPerValidator; + type MaxRewardableIndividualExposures = MaxRewardableIndividualExposures; type ElectionProvider = ElectionProviderMultiPhase; type GenesisElectionProvider = onchain::OnChainSequentialPhragmen; // Alternatively, use pallet_staking::UseNominatorsMap to just use the nominators map. diff --git a/frame/babe/src/mock.rs b/frame/babe/src/mock.rs index 4dd0176b56196..cfd217a424ce6 100644 --- a/frame/babe/src/mock.rs +++ b/frame/babe/src/mock.rs @@ -186,7 +186,7 @@ parameter_types! { pub const SlashDeferDuration: EraIndex = 0; pub const AttestationPeriod: u64 = 100; pub const RewardCurve: &'static PiecewiseLinear<'static> = &REWARD_CURVE; - pub const MaxNominatorRewardedPerValidator: u32 = 64; + pub const MaxRewardableIndividualExposures: u32 = 64; pub const MaxIndividualExposures: u32 = 64; pub const ElectionLookahead: u64 = 0; pub const StakingUnsignedPriority: u64 = u64::MAX / 2; @@ -219,7 +219,7 @@ impl pallet_staking::Config for Test { type SessionInterface = Self; type UnixTime = pallet_timestamp::Pallet; type EraPayout = pallet_staking::ConvertCurve; - type MaxNominatorRewardedPerValidator = MaxNominatorRewardedPerValidator; + type MaxRewardableIndividualExposures = MaxRewardableIndividualExposures; type MaxIndividualExposures = MaxIndividualExposures; type MaxNominations = MaxNominations; type MaxUnappliedSlashes = MaxUnappliedSlashes; diff --git a/frame/grandpa/src/mock.rs b/frame/grandpa/src/mock.rs index 1f416ff0ae650..05be1ace97be0 100644 --- a/frame/grandpa/src/mock.rs +++ b/frame/grandpa/src/mock.rs @@ -188,7 +188,7 @@ parameter_types! { pub const SlashDeferDuration: EraIndex = 0; pub const AttestationPeriod: u64 = 100; pub const RewardCurve: &'static PiecewiseLinear<'static> = &REWARD_CURVE; - pub const MaxNominatorRewardedPerValidator: u32 = 64; + pub const MaxRewardableIndividualExposures: u32 = 64; pub const MaxIndividualExposures: u32 = 64; pub const ElectionLookahead: u64 = 0; pub const StakingUnsignedPriority: u64 = u64::MAX / 2; @@ -221,7 +221,7 @@ impl pallet_staking::Config for Test { type SessionInterface = Self; type UnixTime = pallet_timestamp::Pallet; type EraPayout = pallet_staking::ConvertCurve; - type MaxNominatorRewardedPerValidator = MaxNominatorRewardedPerValidator; + type MaxRewardableIndividualExposures = MaxRewardableIndividualExposures; type MaxIndividualExposures = MaxIndividualExposures; type MaxNominations = MaxNominations; type MaxUnappliedSlashes = MaxUnappliedSlashes; diff --git a/frame/offences/benchmarking/src/mock.rs b/frame/offences/benchmarking/src/mock.rs index 21b2c198e98af..207032eb33d13 100644 --- a/frame/offences/benchmarking/src/mock.rs +++ b/frame/offences/benchmarking/src/mock.rs @@ -145,7 +145,7 @@ pallet_staking_reward_curve::build! { } parameter_types! { pub const RewardCurve: &'static sp_runtime::curve::PiecewiseLinear<'static> = &I_NPOS; - pub const MaxNominatorRewardedPerValidator: u32 = 64; + pub const MaxRewardableIndividualExposures: u32 = 64; pub const MaxIndividualExposures: u32 = 64; pub const MaxKeys: u32 = 10_000; pub const MaxPeerInHeartbeats: u32 = 10_000; @@ -182,7 +182,7 @@ impl pallet_staking::Config for Test { type SessionInterface = Self; type EraPayout = pallet_staking::ConvertCurve; type NextNewSession = Session; - type MaxNominatorRewardedPerValidator = MaxNominatorRewardedPerValidator; + type MaxRewardableIndividualExposures = MaxRewardableIndividualExposures; type MaxIndividualExposures = MaxIndividualExposures; type MaxNominations = MaxNominations; type MaxUnappliedSlashes = MaxUnappliedSlashes; diff --git a/frame/session/benchmarking/src/mock.rs b/frame/session/benchmarking/src/mock.rs index b6eb0a422c8b6..a002eff5deeb0 100644 --- a/frame/session/benchmarking/src/mock.rs +++ b/frame/session/benchmarking/src/mock.rs @@ -144,7 +144,7 @@ pallet_staking_reward_curve::build! { } parameter_types! { pub const RewardCurve: &'static sp_runtime::curve::PiecewiseLinear<'static> = &I_NPOS; - pub const MaxNominatorRewardedPerValidator: u32 = 64; + pub const MaxRewardableIndividualExposures: u32 = 64; pub const MaxIndividualExposures: u32 = 64; pub const UnsignedPriority: u64 = 1 << 20; pub const MaxNominations: u32 = 16; @@ -187,7 +187,7 @@ impl pallet_staking::Config for Test { type SessionInterface = Self; type EraPayout = pallet_staking::ConvertCurve; type NextNewSession = Session; - type MaxNominatorRewardedPerValidator = MaxNominatorRewardedPerValidator; + type MaxRewardableIndividualExposures = MaxRewardableIndividualExposures; type MaxIndividualExposures = MaxIndividualExposures; type MaxNominations = MaxNominations; type MaxUnappliedSlashes = MaxUnappliedSlashes; diff --git a/frame/staking/README.md b/frame/staking/README.md index dcf9e327d5598..a1a0051a1c951 100644 --- a/frame/staking/README.md +++ b/frame/staking/README.md @@ -90,7 +90,7 @@ valid behavior_ while _punishing any misbehavior or lack of availability_. Rewards must be claimed for each era before it gets too old by `$HISTORY_DEPTH` using the `payout_stakers` call. Any account can call `payout_stakers`, which pays the reward to the -validator as well as its nominators. Only the [`Config::MaxNominatorRewardedPerValidator`] +validator as well as its nominators. Only the [`Config::MaxRewardableIndividualExposures`] biggest stakers can claim their reward. This is to limit the i/o cost to mutate storage for each nominator's account. diff --git a/frame/staking/fuzzer/src/mock.rs b/frame/staking/fuzzer/src/mock.rs index 921e0d3b48d7d..5156ed9ba91c3 100644 --- a/frame/staking/fuzzer/src/mock.rs +++ b/frame/staking/fuzzer/src/mock.rs @@ -146,7 +146,7 @@ pallet_staking_reward_curve::build! { } parameter_types! { pub const RewardCurve: &'static sp_runtime::curve::PiecewiseLinear<'static> = &I_NPOS; - pub const MaxNominatorRewardedPerValidator: u32 = 64; + pub const MaxRewardableIndividualExposures: u32 = 64; pub const MaxIterations: u32 = 20; } @@ -194,7 +194,7 @@ impl pallet_staking::Config for Test { type Call = Call; type MaxIterations = MaxIterations; type MinSolutionScoreBump = (); - type MaxNominatorRewardedPerValidator = MaxNominatorRewardedPerValidator; + type MaxRewardableIndividualExposures = MaxRewardableIndividualExposures; type UnsignedPriority = (); type OffchainSolutionWeightLimit = (); type WeightInfo = (); diff --git a/frame/staking/src/benchmarking.rs b/frame/staking/src/benchmarking.rs index acf7c2beebd67..1ff138e921cbc 100644 --- a/frame/staking/src/benchmarking.rs +++ b/frame/staking/src/benchmarking.rs @@ -552,10 +552,10 @@ benchmarks! { } payout_stakers_dead_controller { - let n in 1 .. T::MaxNominatorRewardedPerValidator::get() as u32; + let n in 1 .. T::MaxRewardableIndividualExposures::get() as u32; let (validator, nominators) = create_validator_with_nominators::( n, - T::MaxNominatorRewardedPerValidator::get() as u32, + T::MaxRewardableIndividualExposures::get() as u32, true, RewardDestination::Controller, )?; @@ -585,10 +585,10 @@ benchmarks! { } payout_stakers_alive_staked { - let n in 1 .. T::MaxNominatorRewardedPerValidator::get() as u32; + let n in 1 .. T::MaxRewardableIndividualExposures::get() as u32; let (validator, nominators) = create_validator_with_nominators::( n, - T::MaxNominatorRewardedPerValidator::get() as u32, + T::MaxRewardableIndividualExposures::get() as u32, false, RewardDestination::Staked, )?; @@ -929,7 +929,7 @@ mod tests { let (validator_stash, nominators) = create_validator_with_nominators::( n, - ::MaxNominatorRewardedPerValidator::get() as u32, + ::MaxRewardableIndividualExposures::get() as u32, false, RewardDestination::Staked, ) @@ -954,7 +954,7 @@ mod tests { let (validator_stash, _nominators) = create_validator_with_nominators::( n, - ::MaxNominatorRewardedPerValidator::get() as u32, + ::MaxRewardableIndividualExposures::get() as u32, false, RewardDestination::Staked, ) diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index f454098c7ea38..6bccd08343296 100644 --- a/frame/staking/src/lib.rs +++ b/frame/staking/src/lib.rs @@ -114,7 +114,7 @@ //! //! Rewards must be claimed for each era before it gets too old by `$HISTORY_DEPTH` using the //! `payout_stakers` call. Any account can call `payout_stakers`, which pays the reward to the -//! validator as well as its nominators. Only the [`Config::MaxNominatorRewardedPerValidator`] +//! validator as well as its nominators. Only the [`Config::MaxRewardableIndividualExposures`] //! biggest stakers can claim their reward. This is to limit the i/o cost to mutate storage for each //! nominator's account. //! diff --git a/frame/staking/src/mock.rs b/frame/staking/src/mock.rs index 645496ef2af3f..cafbe55134264 100644 --- a/frame/staking/src/mock.rs +++ b/frame/staking/src/mock.rs @@ -227,7 +227,7 @@ pallet_staking_reward_curve::build! { parameter_types! { pub const BondingDuration: EraIndex = 3; pub const RewardCurve: &'static PiecewiseLinear<'static> = &I_NPOS; - pub const MaxNominatorRewardedPerValidator: u32 = 64; + pub const MaxRewardableIndividualExposures: u32 = 64; pub const MaxIndividualExposures: u32 = 64; } @@ -288,7 +288,7 @@ impl crate::pallet::pallet::Config for Test { type SessionInterface = Self; type EraPayout = ConvertCurve; type NextNewSession = Session; - type MaxNominatorRewardedPerValidator = MaxNominatorRewardedPerValidator; + type MaxRewardableIndividualExposures = MaxRewardableIndividualExposures; type MaxIndividualExposures = MaxIndividualExposures; type ElectionProvider = onchain::OnChainSequentialPhragmen; type GenesisElectionProvider = Self::ElectionProvider; diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index 27bc2ad511faf..e9fdd26b8311f 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -198,7 +198,7 @@ impl Pallet { } } - debug_assert!(nominator_payout_count <= T::MaxNominatorRewardedPerValidator::get()); + debug_assert!(nominator_payout_count <= T::MaxRewardableIndividualExposures::get()); Ok(Some(T::WeightInfo::payout_stakers_alive_staked(nominator_payout_count)).into()) } @@ -490,16 +490,16 @@ impl Pallet { >::insert(new_planned_era, &stash, &exposure); let mut others = exposure.others.to_vec(); - let clipped_max_len = T::MaxNominatorRewardedPerValidator::get() as usize; + let clipped_max_len = T::MaxRewardableIndividualExposures::get() as usize; if others.len() > clipped_max_len { others.sort_by(|a, b| a.value.cmp(&b.value).reverse()); others.truncate(clipped_max_len); } - let others = WeakBoundedVec::<_, T::MaxNominatorRewardedPerValidator>::try_from(others) + let others = WeakBoundedVec::<_, T::MaxRewardableIndividualExposures>::try_from(others) .expect("Vec was clipped, so this has to work, qed"); let exposure_clipped = - Exposure::, T::MaxNominatorRewardedPerValidator> { + Exposure::, T::MaxRewardableIndividualExposures> { total: exposure.total, own: exposure.own, others, diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index 93445e30026dd..400c2b50d7085 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -141,10 +141,10 @@ pub mod pallet { /// The maximum number of nominators rewarded for each validator. /// - /// For each validator only the `$MaxNominatorRewardedPerValidator` biggest stakers can + /// For each validator only the `$MaxRewardableIndividualExposures` biggest stakers can /// claim their reward. This used to limit the i/o cost for the nominator payout. #[pallet::constant] - type MaxNominatorRewardedPerValidator: Get; + type MaxRewardableIndividualExposures: Get; /// The maximum number of exposure of a certain validator at a given era. type MaxIndividualExposures: Get; @@ -330,7 +330,7 @@ pub mod pallet { /// Clipped Exposure of validator at era. /// /// This is similar to [`ErasStakers`] but number of nominators exposed is reduced to the - /// `T::MaxNominatorRewardedPerValidator` biggest stakers. + /// `T::MaxRewardableIndividualExposures` biggest stakers. /// (Note: the field `total` and `own` of the exposure remains unchanged). /// This is used to limit the i/o cost for the nominator payout. /// @@ -346,7 +346,7 @@ pub mod pallet { EraIndex, Twox64Concat, T::AccountId, - Exposure, T::MaxNominatorRewardedPerValidator>, + Exposure, T::MaxRewardableIndividualExposures>, ValueQuery, >; @@ -1367,14 +1367,14 @@ pub mod pallet { /// Pay out all the stakers behind a single validator for a single era. /// /// - `validator_stash` is the stash account of the validator. Their nominators, up to - /// `T::MaxNominatorRewardedPerValidator`, will also receive their rewards. + /// `T::MaxRewardableIndividualExposures`, will also receive their rewards. /// - `era` may be any era between `[current_era - history_depth; current_era]`. /// /// The origin of this call must be _Signed_. Any account can call this function, even if /// it is not one of the stakers. /// /// # - /// - Time complexity: at most O(MaxNominatorRewardedPerValidator). + /// - Time complexity: at most O(MaxRewardableIndividualExposures). /// - Contains a limited number of reads and writes. /// ----------- /// N is the Number of payouts for the validator (including the validator) @@ -1386,7 +1386,7 @@ pub mod pallet { /// Paying even a dead controller is cheaper weight-wise. We don't do any refunds here. /// # #[pallet::weight(T::WeightInfo::payout_stakers_alive_staked( - T::MaxNominatorRewardedPerValidator::get() + T::MaxRewardableIndividualExposures::get() ))] pub fn payout_stakers( origin: OriginFor, diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index 6a37ae67d1536..b2190f17876fa 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -2138,7 +2138,7 @@ fn reward_validator_slashing_validator_does_not_overflow() { ErasStakers::::insert(0, 11, &exposure); let exposure_clipped = - Exposure::::MaxNominatorRewardedPerValidator> { + Exposure::::MaxRewardableIndividualExposures> { total: stake, own: stake, others: WeakBoundedVec::default(), @@ -3232,7 +3232,7 @@ fn six_session_delay() { #[test] fn test_max_nominator_rewarded_per_validator_and_cant_steal_someone_else_reward() { ExtBuilder::default().build_and_execute(|| { - for i in 0..=::MaxNominatorRewardedPerValidator::get() { + for i in 0..=::MaxRewardableIndividualExposures::get() { let stash = 10_000 + i as AccountId; let controller = 20_000 + i as AccountId; let balance = 10_000 + i as Balance; @@ -3255,7 +3255,7 @@ fn test_max_nominator_rewarded_per_validator_and_cant_steal_someone_else_reward( mock::make_all_reward_payment(1); // Assert only nominators from 1 to Max are rewarded - for i in 0..=::MaxNominatorRewardedPerValidator::get() { + for i in 0..=::MaxRewardableIndividualExposures::get() { let stash = 10_000 + i as AccountId; let balance = 10_000 + i as Balance; if stash == 10_000 { @@ -3475,7 +3475,7 @@ fn payout_stakers_handles_weight_refund() { // Note: this test relies on the assumption that `payout_stakers_alive_staked` is solely used by // `payout_stakers` to calculate the weight of each payout op. ExtBuilder::default().has_stakers(false).build_and_execute(|| { - let max_nom_rewarded = ::MaxNominatorRewardedPerValidator::get(); + let max_nom_rewarded = ::MaxRewardableIndividualExposures::get(); // Make sure the configured value is meaningful for our use. assert!(max_nom_rewarded >= 4); let half_max_nom_rewarded = max_nom_rewarded / 2; From 2577c7dbb3391237e53eb1c36c2ea4261099cb5e Mon Sep 17 00:00:00 2001 From: Georges Dib Date: Sat, 2 Oct 2021 15:07:15 +0100 Subject: [PATCH 46/80] Implementing `OrdNoBound` derive trait --- frame/offences/benchmarking/src/lib.rs | 2 +- frame/staking/src/lib.rs | 39 ++-------- frame/support/procedural/src/lib.rs | 7 ++ frame/support/procedural/src/ord_no_bound.rs | 82 ++++++++++++++++++++ frame/support/src/lib.rs | 18 +++++ 5 files changed, 113 insertions(+), 35 deletions(-) create mode 100644 frame/support/procedural/src/ord_no_bound.rs diff --git a/frame/offences/benchmarking/src/lib.rs b/frame/offences/benchmarking/src/lib.rs index 8db20a4f3ec2f..aeb6028338e9c 100644 --- a/frame/offences/benchmarking/src/lib.rs +++ b/frame/offences/benchmarking/src/lib.rs @@ -23,7 +23,7 @@ mod mock; use sp_std::{convert::TryFrom, prelude::*, vec}; -use frame_benchmarking::{account, benchmarks, impl_benchmark_test_suite}; +use frame_benchmarking::{account, benchmarks}; use frame_support::{ traits::{Currency, Get, ValidatorSet, ValidatorSetWithIdentification}, WeakBoundedVec, diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index b9d807bed0b79..712c3318ce857 100644 --- a/frame/staking/src/lib.rs +++ b/frame/staking/src/lib.rs @@ -305,8 +305,8 @@ use frame_support::{ storage::bounded_btree_map::BoundedBTreeMap, traits::{Currency, Get}, weights::Weight, - BoundedVec, CloneNoBound, DefaultNoBound, EqNoBound, PartialEqNoBound, RuntimeDebugNoBound, - WeakBoundedVec, + BoundedVec, CloneNoBound, DefaultNoBound, EqNoBound, OrdNoBound, PartialEqNoBound, + RuntimeDebugNoBound, WeakBoundedVec, }; use scale_info::TypeInfo; use sp_runtime::{ @@ -319,7 +319,6 @@ use sp_staking::{ SessionIndex, }; use sp_std::{ - cmp::Ordering, convert::{From, TryFrom}, fmt, prelude::*, @@ -647,6 +646,7 @@ pub struct IndividualExposure { #[derive( PartialEqNoBound, EqNoBound, + OrdNoBound, Encode, Decode, CloneNoBound, @@ -659,8 +659,8 @@ pub struct IndividualExposure { #[codec(mel_bound(Limit: Get, Balance: HasCompact))] pub struct Exposure where - AccountId: MaxEncodedLen + Eq + Default + Clone + fmt::Debug, - Balance: HasCompact + MaxEncodedLen + Eq + Default + Clone + fmt::Debug, + AccountId: MaxEncodedLen + Eq + Default + Clone + Ord + fmt::Debug, + Balance: HasCompact + MaxEncodedLen + Eq + Default + Clone + Ord + fmt::Debug, Limit: Get, { /// The total balance backing this validator. @@ -673,35 +673,6 @@ where pub others: WeakBoundedVec, Limit>, } -impl PartialOrd for Exposure -where - AccountId: MaxEncodedLen + Eq + Default + Clone + Ord + fmt::Debug, - Balance: HasCompact + MaxEncodedLen + Eq + Default + Clone + Ord + fmt::Debug, - Limit: Get, -{ - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } -} - -impl Ord for Exposure -where - AccountId: MaxEncodedLen + Eq + Default + Clone + Ord + fmt::Debug, - Balance: HasCompact + MaxEncodedLen + Eq + Default + Clone + Ord + fmt::Debug, - Limit: Get, -{ - fn cmp(&self, other: &Self) -> Ordering { - let mut result = Ord::cmp(&self.total, &other.total); - if result == Ordering::Equal { - result = Ord::cmp(&self.own, &other.own); - if result == Ordering::Equal { - return Ord::cmp(&self.others, &other.others) - } - } - return result - } -} - /// A pending slash record. The value of the slash has been computed but not applied yet, /// rather deferred for several eras. /// `SlashedLimit` bounds the number of slashed accounts. diff --git a/frame/support/procedural/src/lib.rs b/frame/support/procedural/src/lib.rs index 6987fc49b9a8c..a7d93b26e20ec 100644 --- a/frame/support/procedural/src/lib.rs +++ b/frame/support/procedural/src/lib.rs @@ -26,6 +26,7 @@ mod debug_no_bound; mod default_no_bound; mod dummy_part_checker; mod key_prefix; +mod ord_no_bound; mod pallet; mod partial_eq_no_bound; mod storage; @@ -435,6 +436,12 @@ pub fn derive_runtime_debug_no_bound(input: TokenStream) -> TokenStream { } } +/// Derive [`Ord`] but do not bound any generic. Docs are at `frame_support::OrdNoBound`. +#[proc_macro_derive(OrdNoBound)] +pub fn derive_ord_no_bound(input: TokenStream) -> TokenStream { + ord_no_bound::derive_ord_no_bound(input) +} + /// Derive [`PartialEq`] but do not bound any generic. Docs are at /// `frame_support::PartialEqNoBound`. #[proc_macro_derive(PartialEqNoBound)] diff --git a/frame/support/procedural/src/ord_no_bound.rs b/frame/support/procedural/src/ord_no_bound.rs new file mode 100644 index 0000000000000..fe1b45a466eb5 --- /dev/null +++ b/frame/support/procedural/src/ord_no_bound.rs @@ -0,0 +1,82 @@ +// This file is part of Substrate. + +// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use syn::spanned::Spanned; + +/// Derive Ord but do not bound any generic. +pub fn derive_ord_no_bound(input: proc_macro::TokenStream) -> proc_macro::TokenStream { + let input: syn::DeriveInput = match syn::parse(input) { + Ok(input) => input, + Err(e) => return e.to_compile_error().into(), + }; + + let name = &input.ident; + let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl(); + + let impl_ = match input.data { + syn::Data::Struct(struct_) => match struct_.fields { + syn::Fields::Named(named) => { + let fields = named.named.iter().map(|i| &i.ident).map(|i| { + quote::quote_spanned!(i.span() => if self.#i != other.#i { + return self.#i.cmp(&other.#i); + }) + }); + + quote::quote!( #( #fields )* ) + }, + syn::Fields::Unnamed(unnamed) => { + let fields = + unnamed.unnamed.iter().enumerate().map(|(i, _)| syn::Index::from(i)).map(|i| { + quote::quote_spanned!(i.span() => if self.#i != other.#i { + return self.#i.cmp(&other.#i); + }) + }); + + quote::quote!( #( #fields )* ) + }, + syn::Fields::Unit => { + quote::quote!() + }, + }, + syn::Data::Enum(_) => { + let msg = "Enum type not supported by `derive(OrdNoBound)`"; + return syn::Error::new(input.span(), msg).to_compile_error().into() + }, + syn::Data::Union(_) => { + let msg = "Union type not supported by `derive(OrdNoBound)`"; + return syn::Error::new(input.span(), msg).to_compile_error().into() + }, + }; + + quote::quote!( + const _: () = { + impl #impl_generics core::cmp::Ord for #name #ty_generics #where_clause { + fn cmp(&self, other: &Self) -> core::cmp::Ordering { + #impl_ + core::cmp::Ordering::Equal + } + } + + impl #impl_generics core::cmp::PartialOrd for #name #ty_generics #where_clause { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } + } + }; + ) + .into() +} diff --git a/frame/support/src/lib.rs b/frame/support/src/lib.rs index f3b00c764bb35..97184e8103a93 100644 --- a/frame/support/src/lib.rs +++ b/frame/support/src/lib.rs @@ -633,6 +633,24 @@ pub use frame_support_procedural::EqNoBound; /// ``` pub use frame_support_procedural::PartialEqNoBound; +/// Derive [`Ord`] but do not bound any generic. +/// +/// This is useful for type generic over runtime: +/// ``` +/// # use frame_support::{EqNoBound, OrdNoBound, PartialEqNoBound}; +/// trait Config { +/// type C: Ord; +/// } +/// +/// // `Foo` implements [`Ord`] because `C` bounds [`Ord`]. +/// // Otherwise compilation will fail with an output telling `c` doesn't implement [`Ord`]. +/// #[derive(PartialEqNoBound, EqNoBound, OrdNoBound)] +/// struct Foo { +/// c: T::C, +/// } +/// ``` +pub use frame_support_procedural::OrdNoBound; + /// Derive [`Debug`] but do not bound any generic. /// /// This is useful for type generic over runtime: From 0e6455a90b51ec511a2d10cc2fcdf986240685d4 Mon Sep 17 00:00:00 2001 From: Georges Dib Date: Sat, 2 Oct 2021 15:55:04 +0100 Subject: [PATCH 47/80] Adding tests for `OrdNoBound` Fixing other tests outputs --- frame/support/test/tests/derive_no_bound.rs | 15 +++++++++------ .../test/tests/derive_no_bound_ui/clone.stderr | 4 ---- .../test/tests/derive_no_bound_ui/default.stderr | 4 ---- .../test/tests/derive_no_bound_ui/eq.stderr | 5 ----- .../support/test/tests/derive_no_bound_ui/ord.rs | 12 ++++++++++++ .../test/tests/derive_no_bound_ui/ord.stderr | 9 +++++++++ 6 files changed, 30 insertions(+), 19 deletions(-) create mode 100644 frame/support/test/tests/derive_no_bound_ui/ord.rs create mode 100644 frame/support/test/tests/derive_no_bound_ui/ord.stderr diff --git a/frame/support/test/tests/derive_no_bound.rs b/frame/support/test/tests/derive_no_bound.rs index 1827844664fa7..78f58f3603335 100644 --- a/frame/support/test/tests/derive_no_bound.rs +++ b/frame/support/test/tests/derive_no_bound.rs @@ -15,11 +15,12 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Tests for DebugNoBound, CloneNoBound, EqNoBound, PartialEqNoBound, DefaultNoBound, and -//! RuntimeDebugNoBound +//! Tests for DebugNoBound, CloneNoBound, EqNoBound, PartialEqNoBound, DefaultNoBound, OrdNoBound +//! and RuntimeDebugNoBound. use frame_support::{ - CloneNoBound, DebugNoBound, DefaultNoBound, EqNoBound, PartialEqNoBound, RuntimeDebugNoBound, + CloneNoBound, DebugNoBound, DefaultNoBound, EqNoBound, OrdNoBound, PartialEqNoBound, + RuntimeDebugNoBound, }; #[derive(RuntimeDebugNoBound)] @@ -32,7 +33,7 @@ fn runtime_debug_no_bound_display_correctly() { } trait Config { - type C: std::fmt::Debug + Clone + Eq + PartialEq + Default; + type C: std::fmt::Debug + Clone + Eq + PartialEq + Default + Ord; } struct Runtime; @@ -42,7 +43,7 @@ impl Config for Runtime { type C = u32; } -#[derive(DebugNoBound, CloneNoBound, EqNoBound, PartialEqNoBound, DefaultNoBound)] +#[derive(DebugNoBound, CloneNoBound, EqNoBound, PartialEqNoBound, DefaultNoBound, OrdNoBound)] struct StructNamed { a: u32, b: u64, @@ -83,9 +84,10 @@ fn test_struct_named() { }; assert!(b != a_1); + assert!(b > a_1); } -#[derive(DebugNoBound, CloneNoBound, EqNoBound, PartialEqNoBound, DefaultNoBound)] +#[derive(DebugNoBound, CloneNoBound, EqNoBound, PartialEqNoBound, DefaultNoBound, OrdNoBound)] struct StructUnnamed(u32, u64, T::C, core::marker::PhantomData<(U, V)>); #[test] @@ -108,6 +110,7 @@ fn test_struct_unnamed() { let b = StructUnnamed::(1, 2, 4, Default::default()); assert!(b != a_1); + assert!(b > a_1); } #[derive(DebugNoBound, CloneNoBound, EqNoBound, PartialEqNoBound, DefaultNoBound)] diff --git a/frame/support/test/tests/derive_no_bound_ui/clone.stderr b/frame/support/test/tests/derive_no_bound_ui/clone.stderr index 050b576c8b9ed..0301824d59eff 100644 --- a/frame/support/test/tests/derive_no_bound_ui/clone.stderr +++ b/frame/support/test/tests/derive_no_bound_ui/clone.stderr @@ -5,7 +5,3 @@ error[E0277]: the trait bound `::C: Clone` is not satisfied | ^ the trait `Clone` is not implemented for `::C` | note: required by `clone` - --> $DIR/clone.rs:121:5 - | -121 | fn clone(&self) -> Self; - | ^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/frame/support/test/tests/derive_no_bound_ui/default.stderr b/frame/support/test/tests/derive_no_bound_ui/default.stderr index 7608f877a3b56..cfa9194ee7f8f 100644 --- a/frame/support/test/tests/derive_no_bound_ui/default.stderr +++ b/frame/support/test/tests/derive_no_bound_ui/default.stderr @@ -5,7 +5,3 @@ error[E0277]: the trait bound `::C: std::default::Default` is not s | ^ the trait `std::default::Default` is not implemented for `::C` | note: required by `std::default::Default::default` - --> $DIR/default.rs:116:5 - | -116 | fn default() -> Self; - | ^^^^^^^^^^^^^^^^^^^^^ diff --git a/frame/support/test/tests/derive_no_bound_ui/eq.stderr b/frame/support/test/tests/derive_no_bound_ui/eq.stderr index fce13d6f17f06..bbd907adecb33 100644 --- a/frame/support/test/tests/derive_no_bound_ui/eq.stderr +++ b/frame/support/test/tests/derive_no_bound_ui/eq.stderr @@ -4,9 +4,4 @@ error[E0277]: can't compare `Foo` with `Foo` 6 | struct Foo { | ^^^ no implementation for `Foo == Foo` | - ::: $RUST/core/src/cmp.rs - | - | pub trait Eq: PartialEq { - | --------------- required by this bound in `std::cmp::Eq` - | = help: the trait `PartialEq` is not implemented for `Foo` diff --git a/frame/support/test/tests/derive_no_bound_ui/ord.rs b/frame/support/test/tests/derive_no_bound_ui/ord.rs new file mode 100644 index 0000000000000..d8b484d82ffdc --- /dev/null +++ b/frame/support/test/tests/derive_no_bound_ui/ord.rs @@ -0,0 +1,12 @@ +use frame_support::{EqNoBound, OrdNoBound, PartialEqNoBound}; + +trait Config { + type C: Eq; +} + +#[derive(PartialEqNoBound, EqNoBound, OrdNoBound)] +struct Foo { + c: T::C, +} + +fn main() {} \ No newline at end of file diff --git a/frame/support/test/tests/derive_no_bound_ui/ord.stderr b/frame/support/test/tests/derive_no_bound_ui/ord.stderr new file mode 100644 index 0000000000000..e62c5b988d8d6 --- /dev/null +++ b/frame/support/test/tests/derive_no_bound_ui/ord.stderr @@ -0,0 +1,9 @@ +error[E0599]: the method `cmp` exists for associated type `::C`, but its trait bounds were not satisfied + --> $DIR/ord.rs:9:2 + | +9 | c: T::C, + | ^ method cannot be called on `::C` due to unsatisfied trait bounds + | + = note: the following trait bounds were not satisfied: + `::C: Iterator` + which is required by `&mut ::C: Iterator` From a6296273e00ea4499b3eed7742f2707576f8f3d9 Mon Sep 17 00:00:00 2001 From: Georges Dib Date: Sat, 2 Oct 2021 16:17:54 +0100 Subject: [PATCH 48/80] Fixing tests, I must be running a different compiler version locally --- frame/support/test/tests/derive_no_bound_ui/clone.stderr | 4 ++++ frame/support/test/tests/derive_no_bound_ui/default.stderr | 4 ++++ frame/support/test/tests/derive_no_bound_ui/eq.stderr | 5 +++++ 3 files changed, 13 insertions(+) diff --git a/frame/support/test/tests/derive_no_bound_ui/clone.stderr b/frame/support/test/tests/derive_no_bound_ui/clone.stderr index 0301824d59eff..050b576c8b9ed 100644 --- a/frame/support/test/tests/derive_no_bound_ui/clone.stderr +++ b/frame/support/test/tests/derive_no_bound_ui/clone.stderr @@ -5,3 +5,7 @@ error[E0277]: the trait bound `::C: Clone` is not satisfied | ^ the trait `Clone` is not implemented for `::C` | note: required by `clone` + --> $DIR/clone.rs:121:5 + | +121 | fn clone(&self) -> Self; + | ^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/frame/support/test/tests/derive_no_bound_ui/default.stderr b/frame/support/test/tests/derive_no_bound_ui/default.stderr index cfa9194ee7f8f..7608f877a3b56 100644 --- a/frame/support/test/tests/derive_no_bound_ui/default.stderr +++ b/frame/support/test/tests/derive_no_bound_ui/default.stderr @@ -5,3 +5,7 @@ error[E0277]: the trait bound `::C: std::default::Default` is not s | ^ the trait `std::default::Default` is not implemented for `::C` | note: required by `std::default::Default::default` + --> $DIR/default.rs:116:5 + | +116 | fn default() -> Self; + | ^^^^^^^^^^^^^^^^^^^^^ diff --git a/frame/support/test/tests/derive_no_bound_ui/eq.stderr b/frame/support/test/tests/derive_no_bound_ui/eq.stderr index bbd907adecb33..fce13d6f17f06 100644 --- a/frame/support/test/tests/derive_no_bound_ui/eq.stderr +++ b/frame/support/test/tests/derive_no_bound_ui/eq.stderr @@ -4,4 +4,9 @@ error[E0277]: can't compare `Foo` with `Foo` 6 | struct Foo { | ^^^ no implementation for `Foo == Foo` | + ::: $RUST/core/src/cmp.rs + | + | pub trait Eq: PartialEq { + | --------------- required by this bound in `std::cmp::Eq` + | = help: the trait `PartialEq` is not implemented for `Foo` From 1fc1a32fda3e64c5e2375351d53410b5e1c6a00e Mon Sep 17 00:00:00 2001 From: Georges Dib Date: Tue, 12 Oct 2021 20:32:20 +0100 Subject: [PATCH 49/80] Implementing bounding --- bin/node/runtime/src/lib.rs | 1 - .../src/benchmarking.rs | 8 +- .../src/helpers.rs | 27 ++++-- .../election-provider-multi-phase/src/lib.rs | 81 ++++++++++++---- .../src/unsigned.rs | 7 +- frame/election-provider-support/src/lib.rs | 96 ++++++++++++++----- .../election-provider-support/src/onchain.rs | 27 +++++- frame/staking/src/pallet/impls.rs | 31 +++--- frame/staking/src/pallet/mod.rs | 2 + 9 files changed, 207 insertions(+), 73 deletions(-) diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 0bb46bb8f2bd0..9d919c7f9e357 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -605,7 +605,6 @@ impl pallet_election_provider_multi_phase::BenchmarkingConfig for BenchmarkConfi const DESIRED_TARGETS: [u32; 2] = [200, 400]; const SNAPSHOT_MAXIMUM_VOTERS: u32 = 1000; const MINER_MAXIMUM_VOTERS: u32 = 1000; - const MAXIMUM_TARGETS: u32 = 300; } /// Maximum number of iterations for balancing that will be executed in the embedded OCW diff --git a/frame/election-provider-multi-phase/src/benchmarking.rs b/frame/election-provider-multi-phase/src/benchmarking.rs index d202764ac0c57..17dc5c3a4bf64 100644 --- a/frame/election-provider-multi-phase/src/benchmarking.rs +++ b/frame/election-provider-multi-phase/src/benchmarking.rs @@ -150,7 +150,9 @@ fn solution_with_size( Ok(RawSolution { solution, score, round }) } -fn set_up_data_provider(v: u32, t: u32) { +fn set_up_data_provider(v: u32) { + // number of targets in snapshot. Fixed to maximum. + let t = T::MaxTargets::get(); T::DataProvider::clear(); log!( info, @@ -394,8 +396,6 @@ frame_benchmarking::benchmarks! { mine_solution_offchain_memory { // number of votes in snapshot. Fixed to maximum. let v = T::BenchmarkingConfig::MINER_MAXIMUM_VOTERS; - // number of targets in snapshot. Fixed to maximum. - let t = T::BenchmarkingConfig::MAXIMUM_TARGETS; set_up_data_provider::(v, t); let now = frame_system::Pallet::::block_number(); @@ -416,8 +416,6 @@ frame_benchmarking::benchmarks! { create_snapshot_memory { // number of votes in snapshot. Fixed to maximum. let v = T::BenchmarkingConfig::SNAPSHOT_MAXIMUM_VOTERS; - // number of targets in snapshot. Fixed to maximum. - let t = T::BenchmarkingConfig::MAXIMUM_TARGETS; set_up_data_provider::(v, t); assert!(>::snapshot().is_none()); diff --git a/frame/election-provider-multi-phase/src/helpers.rs b/frame/election-provider-multi-phase/src/helpers.rs index 72b1b23f27f3c..a57e47f5d4a48 100644 --- a/frame/election-provider-multi-phase/src/helpers.rs +++ b/frame/election-provider-multi-phase/src/helpers.rs @@ -18,6 +18,8 @@ //! Some helper functions/macros for this crate. use super::{Config, SolutionTargetIndexOf, SolutionVoterIndexOf, VoteWeight}; +use frame_election_provider_support::ElectionDataProvider; +use frame_support::{storage::bounded_btree_map::BoundedBTreeMap, BoundedVec}; use sp_std::{collections::btree_map::BTreeMap, convert::TryInto, prelude::*}; #[macro_export] @@ -30,15 +32,22 @@ macro_rules! log { }; } +type MaximumVotesPerVoter = >::MaximumVotesPerVoter; + /// Generate a btree-map cache of the voters and their indices. /// /// This can be used to efficiently build index getter closures. pub fn generate_voter_cache( - snapshot: &Vec<(T::AccountId, VoteWeight, Vec)>, -) -> BTreeMap { - let mut cache: BTreeMap = BTreeMap::new(); + snapshot: &Vec<(T::AccountId, VoteWeight, BoundedVec>)>, +) -> BoundedBTreeMap> { + let mut cache: BoundedBTreeMap> = + BoundedBTreeMap::new(); snapshot.iter().enumerate().for_each(|(i, (x, _, _))| { - let _existed = cache.insert(x.clone(), i); + let _existed = cache.try_insert(x.clone(), i).expect("Size is MaximumVotesPerVoter"); // if a duplicate exists, we only consider the last one. Defensive only, should never // happen. debug_assert!(_existed.is_none()); @@ -148,7 +157,7 @@ pub fn target_index_fn_linear( /// Create a function that can map a voter index ([`SolutionVoterIndexOf`]) to the actual voter /// account using a linearly indexible snapshot. pub fn voter_at_fn( - snapshot: &Vec<(T::AccountId, VoteWeight, Vec)>, + snapshot: &Vec<(T::AccountId, VoteWeight, BoundedVec>)>, ) -> impl Fn(SolutionVoterIndexOf) -> Option + '_ { move |i| { as TryInto>::try_into(i) @@ -192,8 +201,12 @@ pub fn stake_of_fn_linear( /// The cache need must be derived from the same snapshot. Zero is returned if a voter is /// non-existent. pub fn stake_of_fn<'a, T: Config>( - snapshot: &'a Vec<(T::AccountId, VoteWeight, Vec)>, - cache: &'a BTreeMap, + snapshot: &'a Vec<( + T::AccountId, + VoteWeight, + BoundedVec>, + )>, + cache: &'a BoundedBTreeMap>, ) -> impl Fn(&T::AccountId) -> VoteWeight + 'a { move |who| { if let Some(index) = cache.get(who) { diff --git a/frame/election-provider-multi-phase/src/lib.rs b/frame/election-provider-multi-phase/src/lib.rs index b46763a179871..705675095b919 100644 --- a/frame/election-provider-multi-phase/src/lib.rs +++ b/frame/election-provider-multi-phase/src/lib.rs @@ -215,6 +215,7 @@ use frame_support::{ ensure, traits::{Currency, Get, OnUnbalanced, ReservableCurrency}, weights::{DispatchClass, Weight}, + BoundedVec, RuntimeDebugNoBound, }; use frame_system::{ensure_none, offchain::SendTransactionTypes}; use scale_info::TypeInfo; @@ -268,6 +269,7 @@ pub type SolutionAccuracyOf = as NposSolution>::Accuracy; pub type FallbackErrorOf = <::Fallback as ElectionProvider< ::AccountId, ::BlockNumber, + ::MaxTargets, >>::Error; /// Configuration for the benchmarks of the pallet. @@ -284,8 +286,6 @@ pub trait BenchmarkingConfig { const SNAPSHOT_MAXIMUM_VOTERS: u32; /// Maximum number of voters expected. This is used only for memory-benchmarking of miner. const MINER_MAXIMUM_VOTERS: u32; - /// Maximum number of targets expected. This is used only for memory-benchmarking. - const MAXIMUM_TARGETS: u32; } impl BenchmarkingConfig for () { @@ -295,13 +295,12 @@ impl BenchmarkingConfig for () { const DESIRED_TARGETS: [u32; 2] = [400, 800]; const SNAPSHOT_MAXIMUM_VOTERS: u32 = 10_000; const MINER_MAXIMUM_VOTERS: u32 = 10_000; - const MAXIMUM_TARGETS: u32 = 2_000; } /// A fallback implementation that transitions the pallet to the emergency phase. pub struct NoFallback(sp_std::marker::PhantomData); -impl ElectionProvider for NoFallback { +impl ElectionProvider for NoFallback { type DataProvider = T::DataProvider; type Error = &'static str; @@ -437,12 +436,15 @@ pub struct ReadySolution { /// [`ElectionDataProvider`] and are kept around until the round is finished. /// /// These are stored together because they are often accessed together. -#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, Default, TypeInfo)] -pub struct RoundSnapshot { +/// `MaxVotes` bounds the number of voters per voter +/// `MaxTargets` bounds the number of targets +#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebugNoBound, Default, TypeInfo)] +#[scale_info(skip_type_params(MaxVotes, MaxTargets))] +pub struct RoundSnapshot, MaxTargets: Get> { /// All of the voters. - pub voters: Vec<(A, VoteWeight, Vec)>, + pub voters: Vec<(A, VoteWeight, BoundedVec)>, /// All of the targets. - pub targets: Vec, + pub targets: BoundedVec, } /// Encodes the length of a solution or a snapshot. @@ -635,6 +637,9 @@ pub mod pallet { /// Handler for the rewards. type RewardHandler: OnUnbalanced>; + /// Maximum number of targets for the data provider. + type MaxTargets: Get; + /// Maximum length (bytes) that the mined solution should consume. /// /// The miner will ensure that the total length of the unsigned solution will not exceed @@ -643,7 +648,11 @@ pub mod pallet { type MinerMaxLength: Get; /// Something that will provide the election data. - type DataProvider: ElectionDataProvider; + type DataProvider: ElectionDataProvider< + Self::AccountId, + Self::BlockNumber, + Self::MaxTargets, + >; /// The solution type. type Solution: codec::Codec @@ -660,6 +669,7 @@ pub mod pallet { type Fallback: ElectionProvider< Self::AccountId, Self::BlockNumber, + Self::MaxTargets, DataProvider = Self::DataProvider, >; @@ -807,7 +817,11 @@ pub mod pallet { // NOTE that this pallet does not really need to enforce this in runtime. The // solution cannot represent any voters more than `LIMIT` anyhow. assert_eq!( - >::MaximumVotesPerVoter::get(), + >::MaximumVotesPerVoter::get(), as NposSolution>::LIMIT as u32, ); } @@ -1124,7 +1138,18 @@ pub mod pallet { /// This is created at the beginning of the signed phase and cleared upon calling `elect`. #[pallet::storage] #[pallet::getter(fn snapshot)] - pub type Snapshot = StorageValue<_, RoundSnapshot>; + pub type Snapshot = StorageValue< + _, + RoundSnapshot< + T::AccountId, + >::MaximumVotesPerVoter, + T::MaxTargets, + >, + >; /// Desired number of targets to elect for this round. /// @@ -1249,8 +1274,17 @@ impl Pallet { /// /// Extracted for easier weight calculation. fn create_snapshot_internal( - targets: Vec, - voters: Vec>, + targets: BoundedVec, + voters: Vec< + crate::unsigned::Voter< + T, + >::MaximumVotesPerVoter, + >, + >, desired_targets: u32, ) { let metadata = @@ -1280,8 +1314,23 @@ impl Pallet { /// Parts of [`create_snapshot`] that happen outside of this pallet. /// /// Extracted for easier weight calculation. - fn create_snapshot_external( - ) -> Result<(Vec, Vec>, u32), ElectionError> { + fn create_snapshot_external() -> Result< + ( + BoundedVec, + Vec< + crate::unsigned::Voter< + T, + >::MaximumVotesPerVoter, + >, + >, + u32, + ), + ElectionError, + > { let target_limit = >::max_value().saturated_into::(); // for now we have just a single block snapshot. let voter_limit = T::VoterSnapshotPerBlock::get().saturated_into::(); @@ -1488,7 +1537,7 @@ impl Pallet { } } -impl ElectionProvider for Pallet { +impl ElectionProvider for Pallet { type Error = ElectionError; type DataProvider = T::DataProvider; diff --git a/frame/election-provider-multi-phase/src/unsigned.rs b/frame/election-provider-multi-phase/src/unsigned.rs index 31ad502ac076e..2ff82a8d99bdc 100644 --- a/frame/election-provider-multi-phase/src/unsigned.rs +++ b/frame/election-provider-multi-phase/src/unsigned.rs @@ -24,7 +24,7 @@ use crate::{ }; use codec::Encode; use frame_election_provider_support::{NposSolver, PerThing128}; -use frame_support::{dispatch::DispatchResult, ensure, traits::Get}; +use frame_support::{dispatch::DispatchResult, ensure, traits::Get, BoundedVec}; use frame_system::offchain::SubmitTransaction; use sp_arithmetic::Perbill; use sp_npos_elections::{ @@ -47,10 +47,11 @@ pub(crate) const OFFCHAIN_CACHED_CALL: &[u8] = b"parity/multi-phase-unsigned-ele /// A voter's fundamental data: their ID, their stake, and the list of candidates for whom they /// voted. -pub type Voter = ( +/// `Limit` bounds the vec size +pub type Voter = ( ::AccountId, sp_npos_elections::VoteWeight, - Vec<::AccountId>, + BoundedVec<::AccountId, Limit>, ); /// The relative distribution of a voter's stake among the winning targets. diff --git a/frame/election-provider-support/src/lib.rs b/frame/election-provider-support/src/lib.rs index d14108de65fe7..29d556289816e 100644 --- a/frame/election-provider-support/src/lib.rs +++ b/frame/election-provider-support/src/lib.rs @@ -161,7 +161,7 @@ #![cfg_attr(not(feature = "std"), no_std)] pub mod onchain; -use frame_support::traits::Get; +use frame_support::{traits::Get, BoundedVec}; use sp_std::{fmt::Debug, prelude::*}; /// Re-export some type as they are used in the interface. @@ -178,7 +178,8 @@ pub mod data_provider { } /// Something that can provide the data to an [`ElectionProvider`]. -pub trait ElectionDataProvider { +/// `MaxTarget` represents the maximum number of candidates. +pub trait ElectionDataProvider { /// Maximum number of votes per voter that this data provider is providing. type MaximumVotesPerVoter: Get; @@ -189,7 +190,9 @@ pub trait ElectionDataProvider { /// /// This should be implemented as a self-weighing function. The implementor should register its /// appropriate weight at the end of execution with the system pallet directly. - fn targets(maybe_max_len: Option) -> data_provider::Result>; + fn targets( + maybe_max_len: Option, + ) -> data_provider::Result>; /// All possible voters for the election. /// @@ -202,7 +205,9 @@ pub trait ElectionDataProvider { /// appropriate weight at the end of execution with the system pallet directly. fn voters( maybe_max_len: Option, - ) -> data_provider::Result)>>; + ) -> data_provider::Result< + Vec<(AccountId, VoteWeight, BoundedVec)>, + >; /// The number of targets to elect. /// @@ -222,8 +227,8 @@ pub trait ElectionDataProvider { /// else a noop. #[cfg(any(feature = "runtime-benchmarks", test))] fn put_snapshot( - _voters: Vec<(AccountId, VoteWeight, Vec)>, - _targets: Vec, + _voters: Vec<(AccountId, VoteWeight, BoundedVec)>, + _targets: BoundedVec, _target_stake: Option, ) { } @@ -233,7 +238,12 @@ pub trait ElectionDataProvider { /// /// Same as `put_snapshot`, but can add a single voter one by one. #[cfg(any(feature = "runtime-benchmarks", test))] - fn add_voter(_voter: AccountId, _weight: VoteWeight, _targets: Vec) {} + fn add_voter( + _voter: AccountId, + _weight: VoteWeight, + _targets: BoundedVec, + ) { + } /// Utility function only to be used in benchmarking scenarios, to be implemented optionally, /// else a noop. @@ -248,14 +258,20 @@ pub trait ElectionDataProvider { } #[cfg(feature = "std")] -impl ElectionDataProvider for () { +impl ElectionDataProvider + for () +{ type MaximumVotesPerVoter = frame_support::pallet_prelude::ConstU32<0>; - fn targets(_maybe_max_len: Option) -> data_provider::Result> { + fn targets( + _maybe_max_len: Option, + ) -> data_provider::Result> { Ok(Default::default()) } fn voters( _maybe_max_len: Option, - ) -> data_provider::Result)>> { + ) -> data_provider::Result< + Vec<(AccountId, VoteWeight, BoundedVec)>, + > { Ok(Default::default()) } fn desired_targets() -> data_provider::Result { @@ -271,12 +287,13 @@ impl ElectionDataProvider for () /// This trait only provides an interface to _request_ an election, i.e. /// [`ElectionProvider::elect`]. That data required for the election need to be passed to the /// implemented of this trait through [`ElectionProvider::DataProvider`]. -pub trait ElectionProvider { +/// `MaxTargets` is the maximum number of candidates. +pub trait ElectionProvider { /// The error type that is returned by the provider. type Error: Debug; /// The data provider of the election. - type DataProvider: ElectionDataProvider; + type DataProvider: ElectionDataProvider; /// Elect a new set of winners. /// @@ -288,7 +305,9 @@ pub trait ElectionProvider { } #[cfg(feature = "std")] -impl ElectionProvider for () { +impl ElectionProvider + for () +{ type Error = &'static str; type DataProvider = (); @@ -367,7 +386,9 @@ pub trait VoteWeightProvider { } /// Something that can compute the result to an NPoS solution. -pub trait NposSolver { +/// `MaxTargets` is the maximum number of candidates. +/// `MaximumVotesPerVoter` bounds the voters per voter +pub trait NposSolver, MaximumVotesPerVoter: Get> { /// The account identifier type of this solver. type AccountId: sp_npos_elections::IdentifierT; /// The accuracy of this solver. This will affect the accuracy of the output. @@ -379,8 +400,12 @@ pub trait NposSolver { /// of `targets`. fn solve( to_elect: usize, - targets: Vec, - voters: Vec<(Self::AccountId, VoteWeight, Vec)>, + targets: BoundedVec, + voters: Vec<( + Self::AccountId, + VoteWeight, + BoundedVec, + )>, ) -> Result, Self::Error>; } @@ -393,18 +418,30 @@ pub struct SequentialPhragmen( impl< AccountId: IdentifierT, Accuracy: PerThing128, + MaxTargets: Get, + MaximumVotesPerVoter: Get, Balancing: Get>, - > NposSolver for SequentialPhragmen + > NposSolver + for SequentialPhragmen { type AccountId = AccountId; type Accuracy = Accuracy; type Error = sp_npos_elections::Error; fn solve( winners: usize, - targets: Vec, - voters: Vec<(Self::AccountId, VoteWeight, Vec)>, + targets: BoundedVec, + voters: Vec<( + Self::AccountId, + VoteWeight, + BoundedVec, + )>, ) -> Result, Self::Error> { - sp_npos_elections::seq_phragmen(winners, targets, voters, Balancing::get()) + let mut voters_vec: Vec<(Self::AccountId, VoteWeight, Vec)> = + Vec::with_capacity(voters.len()); + for voter in voters { + voters_vec.push((voter.0, voter.1, voter.2.to_vec())); + } + sp_npos_elections::seq_phragmen(winners, targets.to_vec(), voters_vec, Balancing::get()) } } @@ -417,17 +454,28 @@ pub struct PhragMMS( impl< AccountId: IdentifierT, Accuracy: PerThing128, + MaxTargets: Get, + MaximumVotesPerVoter: Get, Balancing: Get>, - > NposSolver for PhragMMS + > NposSolver for PhragMMS { type AccountId = AccountId; type Accuracy = Accuracy; type Error = sp_npos_elections::Error; fn solve( winners: usize, - targets: Vec, - voters: Vec<(Self::AccountId, VoteWeight, Vec)>, + targets: BoundedVec, + voters: Vec<( + Self::AccountId, + VoteWeight, + BoundedVec, + )>, ) -> Result, Self::Error> { - sp_npos_elections::phragmms(winners, targets, voters, Balancing::get()) + let mut voters_vec: Vec<(Self::AccountId, VoteWeight, Vec)> = + Vec::with_capacity(voters.len()); + for voter in voters { + voters_vec.push((voter.0, voter.1, voter.2.to_vec())); + } + sp_npos_elections::phragmms(winners, targets.to_vec(), voters_vec, Balancing::get()) } } diff --git a/frame/election-provider-support/src/onchain.rs b/frame/election-provider-support/src/onchain.rs index 3bbb3a4afab11..d27c3febacca9 100644 --- a/frame/election-provider-support/src/onchain.rs +++ b/frame/election-provider-support/src/onchain.rs @@ -61,11 +61,17 @@ pub struct OnChainSequentialPhragmen(PhantomData); pub trait Config: frame_system::Config { /// The accuracy used to compute the election: type Accuracy: PerThing128; + /// Maximum number of nominations per nominator. + type MaxNominations: Get; + /// Maximum number of potential targets (usually the number of validators). + type MaxTargets: Get; /// Something that provides the data for election. - type DataProvider: ElectionDataProvider; + type DataProvider: ElectionDataProvider; } -impl ElectionProvider for OnChainSequentialPhragmen { +impl ElectionProvider + for OnChainSequentialPhragmen +{ type Error = Error; type DataProvider = T::DataProvider; @@ -79,12 +85,23 @@ impl ElectionProvider for OnChainSequen .map(|(validator, vote_weight, _)| (validator.clone(), *vote_weight)) .collect(); + let voters = voters + .iter() + .map(|(validator, vote_weight, targets)| { + (validator.clone(), *vote_weight, targets.to_vec()) + }) + .collect(); + let stake_of = |w: &T::AccountId| -> VoteWeight { stake_map.get(w).cloned().unwrap_or_default() }; - let ElectionResult { winners: _, assignments } = - seq_phragmen::<_, T::Accuracy>(desired_targets as usize, targets, voters, None) - .map_err(Error::from)?; + let ElectionResult { winners: _, assignments } = seq_phragmen::<_, T::Accuracy>( + desired_targets as usize, + targets.to_vec(), + voters, + None, + ) + .map_err(Error::from)?; let staked = assignment_ratio_to_staked_normalized(assignments, &stake_of)?; diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index e9fdd26b8311f..a3ad661e90bad 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -682,7 +682,7 @@ impl Pallet { /// auto-chilled, but still count towards the limit imposed by `maybe_max_len`. pub fn get_npos_voters( maybe_max_len: Option, - ) -> Vec<(T::AccountId, VoteWeight, Vec)> { + ) -> Vec<(T::AccountId, VoteWeight, BoundedVec)> { let max_allowed_len = { let nominator_count = CounterForNominators::::get() as usize; let validator_count = CounterForValidators::::get() as usize; @@ -696,8 +696,10 @@ impl Pallet { let mut validators_taken = 0u32; for (validator, _) in >::iter().take(max_allowed_len) { // Append self vote. - let self_vote = - (validator.clone(), Self::weight_of(&validator), vec![validator.clone()]); + let validator_bounded = + BoundedVec::<_, T::MaxNominations>::try_from(vec![validator.clone()]) + .expect("T::MaxNominations>0"); + let self_vote = (validator.clone(), Self::weight_of(&validator), validator_bounded); all_voters.push(self_vote); validators_taken.saturating_inc(); } @@ -730,11 +732,7 @@ impl Pallet { .map_or(true, |spans| submitted_in >= spans.last_nonzero_slash()) }); if !targets.len().is_zero() { - all_voters.push(( - nominator.clone(), - Self::weight_of(&nominator), - targets.to_vec(), - )); + all_voters.push((nominator.clone(), Self::weight_of(&nominator), targets)); nominators_taken.saturating_inc(); } } else { @@ -764,7 +762,7 @@ impl Pallet { /// Get the targets for an upcoming npos election. /// /// This function is self-weighing as [`DispatchClass::Mandatory`]. - pub fn get_npos_targets() -> Vec { + pub fn get_npos_targets() -> BoundedVec { let mut validator_count = 0u32; let targets = Validators::::iter() .map(|(v, _)| { @@ -773,6 +771,9 @@ impl Pallet { }) .collect::>(); + let targets = BoundedVec::<_, T::MaxValidatorsCount>::try_from(targets) + .expect("Size is smaller than MaxValidatorsCount"); + Self::register_weight(T::WeightInfo::get_npos_targets(validator_count)); targets @@ -871,7 +872,9 @@ impl Pallet { } } -impl ElectionDataProvider> for Pallet { +impl ElectionDataProvider, T::MaxValidatorsCount> + for Pallet +{ type MaximumVotesPerVoter = T::MaxNominations; fn desired_targets() -> data_provider::Result { @@ -881,7 +884,9 @@ impl ElectionDataProvider> for Pallet fn voters( maybe_max_len: Option, - ) -> data_provider::Result)>> { + ) -> data_provider::Result< + Vec<(T::AccountId, VoteWeight, BoundedVec)>, + > { debug_assert!(>::iter().count() as u32 == CounterForNominators::::get()); debug_assert!(>::iter().count() as u32 == CounterForValidators::::get()); debug_assert_eq!( @@ -897,7 +902,9 @@ impl ElectionDataProvider> for Pallet Ok(voters) } - fn targets(maybe_max_len: Option) -> data_provider::Result> { + fn targets( + maybe_max_len: Option, + ) -> data_provider::Result> { let target_count = CounterForValidators::::get(); // We can't handle this case yet -- return an error. diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index 400c2b50d7085..2b8cb6223f0d5 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -83,6 +83,7 @@ pub mod pallet { type ElectionProvider: frame_election_provider_support::ElectionProvider< Self::AccountId, Self::BlockNumber, + Self::MaxValidatorsCount, // we only accept an election provider that has staking as data provider. DataProvider = Pallet, >; @@ -91,6 +92,7 @@ pub mod pallet { type GenesisElectionProvider: frame_election_provider_support::ElectionProvider< Self::AccountId, Self::BlockNumber, + Self::MaxValidatorsCount, DataProvider = Pallet, >; From c51b29cf90aec6cecba633783605095db4f80a42 Mon Sep 17 00:00:00 2001 From: Georges Dib Date: Tue, 12 Oct 2021 23:02:57 +0100 Subject: [PATCH 50/80] * Increasing `MaxIndividualExposures` * Renaming `MaxErasForRewards` to `MaxHistoryDepth` * Changed `WeakBoundedVec::default` to `Default::default` * Fixed typo in error message --- bin/node/runtime/src/lib.rs | 6 +- frame/babe/src/mock.rs | 4 +- frame/babe/src/tests.rs | 8 +- frame/grandpa/src/mock.rs | 4 +- frame/grandpa/src/tests.rs | 12 +-- frame/offences/benchmarking/src/mock.rs | 4 +- frame/session/benchmarking/src/mock.rs | 4 +- frame/staking/src/benchmarking.rs | 2 +- frame/staking/src/lib.rs | 4 +- frame/staking/src/mock.rs | 4 +- frame/staking/src/pallet/impls.rs | 18 ++-- frame/staking/src/pallet/mod.rs | 16 +++- frame/staking/src/slashing.rs | 10 +- frame/staking/src/tests.rs | 120 ++++++++++++------------ 14 files changed, 113 insertions(+), 103 deletions(-) diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 0bb46bb8f2bd0..2f2350b6bfed9 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -497,11 +497,11 @@ parameter_types! { pub const RewardCurve: &'static PiecewiseLinear<'static> = &REWARD_CURVE; pub const MaxRewardableIndividualExposures: u32 = 256; pub OffchainRepeat: BlockNumber = 5; - pub const MaxIndividualExposures: u32 = 256; + pub const MaxIndividualExposures: u32 = 10_000; pub const MaxNominations: u32 = MAX_NOMINATIONS; pub const MaxUnappliedSlashes: u32 = 1_000; pub const MaxInvulnerablesCount: u32 = 10; - pub const MaxErasForRewards: u32 = 10_000; + pub const MaxHistoryDepth: u32 = 10_000; pub const MaxReportersCount: u32 = 1_000; pub const MaxPriorSlashingSpans: u32 = 1_000; pub const MaxValidatorsCount: u32 = 4_000; @@ -545,7 +545,7 @@ impl pallet_staking::Config for Runtime { type MaxNominations = MaxNominations; type MaxUnappliedSlashes = MaxUnappliedSlashes; type MaxInvulnerablesCount = MaxInvulnerablesCount; - type MaxErasForRewards = MaxErasForRewards; + type MaxHistoryDepth = MaxHistoryDepth; type MaxReportersCount = MaxReportersCount; type MaxPriorSlashingSpans = MaxPriorSlashingSpans; type MaxValidatorsCount = MaxValidatorsCount; diff --git a/frame/babe/src/mock.rs b/frame/babe/src/mock.rs index cfd217a424ce6..a69baab94c07e 100644 --- a/frame/babe/src/mock.rs +++ b/frame/babe/src/mock.rs @@ -193,7 +193,7 @@ parameter_types! { pub const MaxNominations: u32 = 16; pub const MaxUnappliedSlashes: u32 = 1_000; pub const MaxInvulnerablesCount: u32 = 10; - pub const MaxErasForRewards: u32 = 10_000; + pub const MaxHistoryDepth: u32 = 10_000; pub const MaxReportersCount: u32 = 1_000; pub const MaxPriorSlashingSpans: u32 = 1_000; pub const MaxValidatorsCount: u32 = 4_000; @@ -224,7 +224,7 @@ impl pallet_staking::Config for Test { type MaxNominations = MaxNominations; type MaxUnappliedSlashes = MaxUnappliedSlashes; type MaxInvulnerablesCount = MaxInvulnerablesCount; - type MaxErasForRewards = MaxErasForRewards; + type MaxHistoryDepth = MaxHistoryDepth; type MaxReportersCount = MaxReportersCount; type MaxPriorSlashingSpans = MaxPriorSlashingSpans; type MaxValidatorsCount = MaxValidatorsCount; diff --git a/frame/babe/src/tests.rs b/frame/babe/src/tests.rs index daf99152d306a..53054b94c3df6 100644 --- a/frame/babe/src/tests.rs +++ b/frame/babe/src/tests.rs @@ -418,7 +418,7 @@ fn report_equivocation_current_session_works() { pallet_staking::Exposure { total: 10_000, own: 10_000, - others: WeakBoundedVec::default() + others: Default::default() }, ); } @@ -460,7 +460,7 @@ fn report_equivocation_current_session_works() { assert_eq!(Staking::slashable_balance_of(&offending_validator_id), 0); assert_eq!( Staking::eras_stakers(2, offending_validator_id), - pallet_staking::Exposure { total: 0, own: 0, others: WeakBoundedVec::default() }, + pallet_staking::Exposure { total: 0, own: 0, others: Default::default() }, ); // check that the balances of all other validators are left intact. @@ -476,7 +476,7 @@ fn report_equivocation_current_session_works() { pallet_staking::Exposure { total: 10_000, own: 10_000, - others: WeakBoundedVec::default() + others: Default::default() }, ); } @@ -536,7 +536,7 @@ fn report_equivocation_old_session_works() { assert_eq!(Staking::slashable_balance_of(&offending_validator_id), 0); assert_eq!( Staking::eras_stakers(3, offending_validator_id), - pallet_staking::Exposure { total: 0, own: 0, others: WeakBoundedVec::default() }, + pallet_staking::Exposure { total: 0, own: 0, others: Default::default() }, ); }) } diff --git a/frame/grandpa/src/mock.rs b/frame/grandpa/src/mock.rs index 05be1ace97be0..c3b1f84e21ff9 100644 --- a/frame/grandpa/src/mock.rs +++ b/frame/grandpa/src/mock.rs @@ -195,7 +195,7 @@ parameter_types! { pub const MaxNominations: u32 = 16; pub const MaxUnappliedSlashes: u32 = 1_000; pub const MaxInvulnerablesCount: u32 = 10; - pub const MaxErasForRewards: u32 = 10_000; + pub const MaxHistoryDepth: u32 = 10_000; pub const MaxReportersCount: u32 = 1_000; pub const MaxPriorSlashingSpans: u32 = 1_000; pub const MaxValidatorsCount: u32 = 4_000; @@ -226,7 +226,7 @@ impl pallet_staking::Config for Test { type MaxNominations = MaxNominations; type MaxUnappliedSlashes = MaxUnappliedSlashes; type MaxInvulnerablesCount = MaxInvulnerablesCount; - type MaxErasForRewards = MaxErasForRewards; + type MaxHistoryDepth = MaxHistoryDepth; type MaxReportersCount = MaxReportersCount; type MaxPriorSlashingSpans = MaxPriorSlashingSpans; type MaxValidatorsCount = MaxValidatorsCount; diff --git a/frame/grandpa/src/tests.rs b/frame/grandpa/src/tests.rs index bfcf752423535..1284eb200f261 100644 --- a/frame/grandpa/src/tests.rs +++ b/frame/grandpa/src/tests.rs @@ -332,7 +332,7 @@ fn report_equivocation_current_set_works() { pallet_staking::Exposure { total: 10_000, own: 10_000, - others: WeakBoundedVec::default() + others: Default::default() }, ); } @@ -371,7 +371,7 @@ fn report_equivocation_current_set_works() { assert_eq!(Staking::slashable_balance_of(&equivocation_validator_id), 0); assert_eq!( Staking::eras_stakers(2, equivocation_validator_id), - pallet_staking::Exposure { total: 0, own: 0, others: WeakBoundedVec::default() }, + pallet_staking::Exposure { total: 0, own: 0, others: Default::default() }, ); // check that the balances of all other validators are left intact. @@ -388,7 +388,7 @@ fn report_equivocation_current_set_works() { pallet_staking::Exposure { total: 10_000, own: 10_000, - others: WeakBoundedVec::default() + others: Default::default() }, ); } @@ -424,7 +424,7 @@ fn report_equivocation_old_set_works() { pallet_staking::Exposure { total: 10_000, own: 10_000, - others: WeakBoundedVec::default() + others: Default::default() }, ); } @@ -458,7 +458,7 @@ fn report_equivocation_old_set_works() { assert_eq!( Staking::eras_stakers(3, equivocation_validator_id), - pallet_staking::Exposure { total: 0, own: 0, others: WeakBoundedVec::default() }, + pallet_staking::Exposure { total: 0, own: 0, others: Default::default() }, ); // check that the balances of all other validators are left intact. @@ -475,7 +475,7 @@ fn report_equivocation_old_set_works() { pallet_staking::Exposure { total: 10_000, own: 10_000, - others: WeakBoundedVec::default() + others: Default::default() }, ); } diff --git a/frame/offences/benchmarking/src/mock.rs b/frame/offences/benchmarking/src/mock.rs index 207032eb33d13..e8a64f2e3a91a 100644 --- a/frame/offences/benchmarking/src/mock.rs +++ b/frame/offences/benchmarking/src/mock.rs @@ -153,7 +153,7 @@ parameter_types! { pub const MaxNominations: u32 = 16; pub const MaxUnappliedSlashes: u32 = 1_000; pub const MaxInvulnerablesCount: u32 = 10; - pub const MaxErasForRewards: u32 = 10_000; + pub const MaxHistoryDepth: u32 = 10_000; pub const MaxReportersCount: u32 = 1_000; pub const MaxPriorSlashingSpans: u32 = 1_000; pub const MaxValidatorsCount: u32 = 4_000; @@ -187,7 +187,7 @@ impl pallet_staking::Config for Test { type MaxNominations = MaxNominations; type MaxUnappliedSlashes = MaxUnappliedSlashes; type MaxInvulnerablesCount = MaxInvulnerablesCount; - type MaxErasForRewards = MaxErasForRewards; + type MaxHistoryDepth = MaxHistoryDepth; type MaxReportersCount = MaxReportersCount; type MaxPriorSlashingSpans = MaxPriorSlashingSpans; type MaxValidatorsCount = MaxValidatorsCount; diff --git a/frame/session/benchmarking/src/mock.rs b/frame/session/benchmarking/src/mock.rs index a002eff5deeb0..82cc3022631a0 100644 --- a/frame/session/benchmarking/src/mock.rs +++ b/frame/session/benchmarking/src/mock.rs @@ -150,7 +150,7 @@ parameter_types! { pub const MaxNominations: u32 = 16; pub const MaxUnappliedSlashes: u32 = 1_000; pub const MaxInvulnerablesCount: u32 = 10; - pub const MaxErasForRewards: u32 = 10_000; + pub const MaxHistoryDepth: u32 = 10_000; pub const MaxReportersCount: u32 = 1_000; pub const MaxPriorSlashingSpans: u32 = 1_000; pub const MaxValidatorsCount: u32 = 4_000; @@ -192,7 +192,7 @@ impl pallet_staking::Config for Test { type MaxNominations = MaxNominations; type MaxUnappliedSlashes = MaxUnappliedSlashes; type MaxInvulnerablesCount = MaxInvulnerablesCount; - type MaxErasForRewards = MaxErasForRewards; + type MaxHistoryDepth = MaxHistoryDepth; type MaxReportersCount = MaxReportersCount; type MaxPriorSlashingSpans = MaxPriorSlashingSpans; type MaxValidatorsCount = MaxValidatorsCount; diff --git a/frame/staking/src/benchmarking.rs b/frame/staking/src/benchmarking.rs index 51b0caffbebd2..9369354e4f621 100644 --- a/frame/staking/src/benchmarking.rs +++ b/frame/staking/src/benchmarking.rs @@ -119,7 +119,7 @@ pub fn create_validator_with_nominators( let individual = BoundedBTreeMap::<_, _, T::MaxValidatorsCount>::try_from( points_individual.into_iter().collect::>(), ) - .map_err(|_| "Something weird, this means T:MaxValidatorsCount is zero")?; + .map_err(|_| "Something weird, this means T::MaxValidatorsCount is zero")?; let reward = EraRewardPoints:: { total: points_total, individual }; diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index 712c3318ce857..5e5e4aae1633c 100644 --- a/frame/staking/src/lib.rs +++ b/frame/staking/src/lib.rs @@ -711,8 +711,8 @@ where Self { validator: AccountId::default(), own: Balance::default(), - others: WeakBoundedVec::default(), - reporters: WeakBoundedVec::default(), + others: Default::default(), + reporters: Default::default(), payout: Balance::default(), } } diff --git a/frame/staking/src/mock.rs b/frame/staking/src/mock.rs index 18fa1083365f4..cb8ba17ed8b69 100644 --- a/frame/staking/src/mock.rs +++ b/frame/staking/src/mock.rs @@ -253,7 +253,7 @@ parameter_types! { pub const MaxNominations: u32 = 16; pub const MaxUnappliedSlashes: u32 = 1_000; pub const MaxInvulnerablesCount: u32 = 100; - pub const MaxErasForRewards: u32 = 10_000; + pub const MaxHistoryDepth: u32 = 10_000; pub const MaxReportersCount: u32 = 1_000; pub const MaxPriorSlashingSpans: u32 = 1_000; pub const MaxValidatorsCount: u32 = 100; @@ -297,7 +297,7 @@ impl crate::pallet::pallet::Config for Test { type MaxNominations = MaxNominations; type MaxUnappliedSlashes = MaxUnappliedSlashes; type MaxInvulnerablesCount = MaxInvulnerablesCount; - type MaxErasForRewards = MaxErasForRewards; + type MaxHistoryDepth = MaxHistoryDepth; type MaxReportersCount = MaxReportersCount; type MaxPriorSlashingSpans = MaxPriorSlashingSpans; type MaxValidatorsCount = MaxValidatorsCount; diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index e9fdd26b8311f..4c94e299990bd 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -211,7 +211,7 @@ impl Pallet { T::AccountId, BalanceOf, T::MaxUnlockingChunks, - T::MaxErasForRewards, + T::MaxHistoryDepth, >, ) { T::Currency::set_lock(STAKING_ID, &ledger.stash, ledger.total, WithdrawReasons::all()); @@ -957,8 +957,8 @@ impl ElectionDataProvider> for Pallet stash: voter.clone(), active: stake, total: stake, - unlocking: BoundedVec::default(), - claimed_rewards: WeakBoundedVec::default(), + unlocking: Default::default(), + claimed_rewards: Default::default(), }, ); @@ -977,8 +977,8 @@ impl ElectionDataProvider> for Pallet stash: target.clone(), active: stake, total: stake, - unlocking: BoundedVec::default(), - claimed_rewards: WeakBoundedVec::default(), + unlocking: Default::default(), + claimed_rewards: Default::default(), }, ); Self::do_add_validator( @@ -1019,8 +1019,8 @@ impl ElectionDataProvider> for Pallet stash: v.clone(), active: stake, total: stake, - unlocking: BoundedVec::default(), - claimed_rewards: WeakBoundedVec::default(), + unlocking: Default::default(), + claimed_rewards: Default::default(), }, ); Self::do_add_validator( @@ -1040,8 +1040,8 @@ impl ElectionDataProvider> for Pallet stash: v.clone(), active: stake, total: stake, - unlocking: BoundedVec::default(), - claimed_rewards: WeakBoundedVec::default(), + unlocking: Default::default(), + claimed_rewards: Default::default(), }, ); let targets = BoundedVec::<_, T::MaxNominations>::try_from(t) diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index 400c2b50d7085..f645a0dd690b7 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -157,7 +157,8 @@ pub mod pallet { type MaxInvulnerablesCount: Get; /// Maximum number of eras for which the stakers behind a validator have claimed rewards. - type MaxErasForRewards: Get; + /// This also corresponds to maximum value that `HistoryDepth` can take. + type MaxHistoryDepth: Get; /// Maximum number of validators. type MaxValidatorsCount: Get; @@ -246,7 +247,7 @@ pub mod pallet { _, Blake2_128Concat, T::AccountId, - StakingLedger, T::MaxUnlockingChunks, T::MaxErasForRewards>, + StakingLedger, T::MaxUnlockingChunks, T::MaxHistoryDepth>, >; /// Where the reward payment should be made. Keyed by stash. @@ -535,6 +536,11 @@ pub mod pallet { #[pallet::genesis_build] impl GenesisBuild for GenesisConfig { fn build(&self) { + assert!( + self.history_depth < T::MaxHistoryDepth::get(), + "history_depth too big, a runtime adjustment may be needed." + ); + HistoryDepth::::put(self.history_depth); ValidatorCount::::put(self.validator_count); MinimumValidatorCount::::put(self.minimum_validator_count); @@ -796,7 +802,7 @@ pub mod pallet { let value = value.min(stash_balance); Self::deposit_event(Event::::Bonded(stash.clone(), value)); - let claimed_rewards = WeakBoundedVec::<_, T::MaxErasForRewards>::force_from( + let claimed_rewards = WeakBoundedVec::<_, T::MaxHistoryDepth>::force_from( (last_reward_era..current_era).collect(), Some("StakingLedger.claimed_rewards"), ); @@ -1463,6 +1469,10 @@ pub mod pallet { #[pallet::compact] _era_items_deleted: u32, ) -> DispatchResult { ensure_root(origin)?; + ensure!( + new_history_depth < T::MaxHistoryDepth::get(), + Error::::IncorrectHistoryDepth + ); if let Some(current_era) = Self::current_era() { HistoryDepth::::mutate(|history_depth| { let last_kept = current_era.checked_sub(*history_depth).unwrap_or(0); diff --git a/frame/staking/src/slashing.rs b/frame/staking/src/slashing.rs index 59b58e11eed00..b3d7ed55c9e63 100644 --- a/frame/staking/src/slashing.rs +++ b/frame/staking/src/slashing.rs @@ -120,7 +120,7 @@ impl> SlashingSpans { // the first slash is applied. setting equal to `window_start` would // put a time limit on nominations. last_nonzero_slash: 0, - prior: WeakBoundedVec::default(), + prior: Default::default(), } } @@ -296,14 +296,14 @@ pub(crate) fn compute_slash( } } - let mut nominators_slashed = WeakBoundedVec::default(); + let mut nominators_slashed = Default::default(); reward_payout += slash_nominators::(params, prior_slash_p, &mut nominators_slashed); Some(UnappliedSlash { validator: stash.clone(), own: val_slashed, others: nominators_slashed, - reporters: WeakBoundedVec::default(), + reporters: Default::default(), payout: reward_payout, }) } @@ -698,7 +698,7 @@ mod tests { span_index: 0, last_start: 1000, last_nonzero_slash: 0, - prior: WeakBoundedVec::default(), + prior: Default::default(), }; assert_eq!( @@ -799,7 +799,7 @@ mod tests { span_index: 1, last_start: 10, last_nonzero_slash: 0, - prior: WeakBoundedVec::default(), + prior: Default::default(), }; assert!(spans.end_span(10)); diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index 32df539e25fdf..847eb518650a2 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -105,7 +105,7 @@ fn basic_setup_works() { total: 1000, active: 1000, unlocking: BoundedVec::default(), - claimed_rewards: WeakBoundedVec::default(), + claimed_rewards: Default::default(), }) ); // Account 20 controls the stash from account 21, which is 200 * balance_factor units @@ -116,7 +116,7 @@ fn basic_setup_works() { total: 1000, active: 1000, unlocking: BoundedVec::default(), - claimed_rewards: WeakBoundedVec::default(), + claimed_rewards: Default::default(), }) ); // Account 1 does not control any stash @@ -139,7 +139,7 @@ fn basic_setup_works() { total: 500, active: 500, unlocking: BoundedVec::default(), - claimed_rewards: WeakBoundedVec::default(), + claimed_rewards: Default::default(), }) ); assert_eq!(Staking::nominators(101).unwrap().targets, vec![11, 21]); @@ -390,7 +390,7 @@ fn staking_should_work() { active: 1500, unlocking: BoundedVec::default(), claimed_rewards: - WeakBoundedVec::<_, ::MaxErasForRewards>::try_from(vec![0]) + WeakBoundedVec::<_, ::MaxHistoryDepth>::try_from(vec![0]) .expect("Test configuration needs changing"), }) ); @@ -943,7 +943,7 @@ fn reward_destination_works() { total: 1000, active: 1000, unlocking: BoundedVec::default(), - claimed_rewards: WeakBoundedVec::default(), + claimed_rewards: Default::default(), }) ); @@ -967,7 +967,7 @@ fn reward_destination_works() { active: 1000 + total_payout_0, unlocking: BoundedVec::default(), claimed_rewards: - WeakBoundedVec::<_, ::MaxErasForRewards>::try_from(vec![0]) + WeakBoundedVec::<_, ::MaxHistoryDepth>::try_from(vec![0]) .expect("Test configuration needs changing"), }) ); @@ -997,7 +997,7 @@ fn reward_destination_works() { active: 1000 + total_payout_0, unlocking: BoundedVec::default(), claimed_rewards: - WeakBoundedVec::<_, ::MaxErasForRewards>::try_from(vec![0, 1]) + WeakBoundedVec::<_, ::MaxHistoryDepth>::try_from(vec![0, 1]) .expect("Test configuration needs changing"), }) ); @@ -1028,7 +1028,7 @@ fn reward_destination_works() { active: 1000 + total_payout_0, unlocking: BoundedVec::default(), claimed_rewards: - WeakBoundedVec::<_, ::MaxErasForRewards>::try_from(vec![ + WeakBoundedVec::<_, ::MaxHistoryDepth>::try_from(vec![ 0, 1, 2 ]) .expect("Test configuration needs changing"), @@ -1096,7 +1096,7 @@ fn bond_extra_works() { total: 1000, active: 1000, unlocking: BoundedVec::default(), - claimed_rewards: WeakBoundedVec::default(), + claimed_rewards: Default::default(), }) ); @@ -1113,7 +1113,7 @@ fn bond_extra_works() { total: 1000 + 100, active: 1000 + 100, unlocking: BoundedVec::default(), - claimed_rewards: WeakBoundedVec::default(), + claimed_rewards: Default::default(), }) ); @@ -1127,7 +1127,7 @@ fn bond_extra_works() { total: 1000000, active: 1000000, unlocking: BoundedVec::default(), - claimed_rewards: WeakBoundedVec::default(), + claimed_rewards: Default::default(), }) ); }); @@ -1165,12 +1165,12 @@ fn bond_extra_and_withdraw_unbonded_works() { total: 1000, active: 1000, unlocking: BoundedVec::default(), - claimed_rewards: WeakBoundedVec::default(), + claimed_rewards: Default::default(), }) ); assert_eq!( Staking::eras_stakers(active_era(), 11), - Exposure { total: 1000, own: 1000, others: WeakBoundedVec::default() } + Exposure { total: 1000, own: 1000, others: Default::default() } ); // deposit the extra 100 units @@ -1183,13 +1183,13 @@ fn bond_extra_and_withdraw_unbonded_works() { total: 1000 + 100, active: 1000 + 100, unlocking: BoundedVec::default(), - claimed_rewards: WeakBoundedVec::default(), + claimed_rewards: Default::default(), }) ); // Exposure is a snapshot! only updated after the next era update. assert_ne!( Staking::eras_stakers(active_era(), 11), - Exposure { total: 1000 + 100, own: 1000 + 100, others: WeakBoundedVec::default() } + Exposure { total: 1000 + 100, own: 1000 + 100, others: Default::default() } ); // trigger next era. @@ -1204,13 +1204,13 @@ fn bond_extra_and_withdraw_unbonded_works() { total: 1000 + 100, active: 1000 + 100, unlocking: BoundedVec::default(), - claimed_rewards: WeakBoundedVec::default(), + claimed_rewards: Default::default(), }) ); // Exposure is now updated. assert_eq!( Staking::eras_stakers(active_era(), 11), - Exposure { total: 1000 + 100, own: 1000 + 100, others: WeakBoundedVec::default() } + Exposure { total: 1000 + 100, own: 1000 + 100, others: Default::default() } ); // Unbond almost all of the funds in stash. @@ -1225,7 +1225,7 @@ fn bond_extra_and_withdraw_unbonded_works() { UnlockChunk { value: 1000, era: 2 + 3 } ]) .expect("MaxUnlockingChunks>1"), - claimed_rewards: WeakBoundedVec::default(), + claimed_rewards: Default::default(), }), ); @@ -1241,7 +1241,7 @@ fn bond_extra_and_withdraw_unbonded_works() { UnlockChunk { value: 1000, era: 2 + 3 } ]) .expect("MaxUnlockingChunks>1"), - claimed_rewards: WeakBoundedVec::default(), + claimed_rewards: Default::default(), }), ); @@ -1260,7 +1260,7 @@ fn bond_extra_and_withdraw_unbonded_works() { UnlockChunk { value: 1000, era: 2 + 3 } ]) .expect("MaxUnlockingChunks>1"), - claimed_rewards: WeakBoundedVec::default(), + claimed_rewards: Default::default(), }), ); @@ -1276,7 +1276,7 @@ fn bond_extra_and_withdraw_unbonded_works() { total: 100, active: 100, unlocking: BoundedVec::default(), - claimed_rewards: WeakBoundedVec::default(), + claimed_rewards: Default::default(), }), ); }) @@ -1334,7 +1334,7 @@ fn rebond_works() { total: 1000, active: 1000, unlocking: BoundedVec::default(), - claimed_rewards: WeakBoundedVec::default(), + claimed_rewards: Default::default(), }) ); @@ -1356,7 +1356,7 @@ fn rebond_works() { UnlockChunk { value: 900, era: 2 + 3 } ]) .expect("MaxUnlockingChunks>1"), - claimed_rewards: WeakBoundedVec::default(), + claimed_rewards: Default::default(), }) ); @@ -1369,7 +1369,7 @@ fn rebond_works() { total: 1000, active: 1000, unlocking: BoundedVec::default(), - claimed_rewards: WeakBoundedVec::default(), + claimed_rewards: Default::default(), }) ); @@ -1385,7 +1385,7 @@ fn rebond_works() { UnlockChunk { value: 900, era: 5 } ]) .expect("MaxUnlockingChunks>1"), - claimed_rewards: WeakBoundedVec::default(), + claimed_rewards: Default::default(), }) ); @@ -1401,7 +1401,7 @@ fn rebond_works() { UnlockChunk { value: 400, era: 5 } ]) .expect("MaxUnlockingChunks>1"), - claimed_rewards: WeakBoundedVec::default(), + claimed_rewards: Default::default(), }) ); @@ -1414,7 +1414,7 @@ fn rebond_works() { total: 1000, active: 1000, unlocking: BoundedVec::default(), - claimed_rewards: WeakBoundedVec::default(), + claimed_rewards: Default::default(), }) ); @@ -1434,7 +1434,7 @@ fn rebond_works() { UnlockChunk { value: 300, era: 5 }, ]) .expect("MaxUnlockingChunks>3"), - claimed_rewards: WeakBoundedVec::default(), + claimed_rewards: Default::default(), }) ); @@ -1451,7 +1451,7 @@ fn rebond_works() { UnlockChunk { value: 100, era: 5 }, ]) .expect("MaxUnlockingChunks>2"), - claimed_rewards: WeakBoundedVec::default(), + claimed_rewards: Default::default(), }) ); }) @@ -1478,7 +1478,7 @@ fn rebond_is_fifo() { total: 1000, active: 1000, unlocking: BoundedVec::default(), - claimed_rewards: WeakBoundedVec::default(), + claimed_rewards: Default::default(), }) ); @@ -1496,7 +1496,7 @@ fn rebond_is_fifo() { UnlockChunk { value: 400, era: 2 + 3 }, ]) .expect("MaxUnlockingChunks>1"), - claimed_rewards: WeakBoundedVec::default(), + claimed_rewards: Default::default(), }) ); @@ -1515,7 +1515,7 @@ fn rebond_is_fifo() { UnlockChunk { value: 300, era: 3 + 3 }, ]) .expect("MaxUnlockingChunks>2"), - claimed_rewards: WeakBoundedVec::default(), + claimed_rewards: Default::default(), }) ); @@ -1535,7 +1535,7 @@ fn rebond_is_fifo() { UnlockChunk { value: 200, era: 4 + 3 }, ]) .expect("MaxUnlockingChunks>3"), - claimed_rewards: WeakBoundedVec::default(), + claimed_rewards: Default::default(), }) ); @@ -1552,7 +1552,7 @@ fn rebond_is_fifo() { UnlockChunk { value: 100, era: 3 + 3 }, ]) .expect("MaxUnlockingChunks>2"), - claimed_rewards: WeakBoundedVec::default(), + claimed_rewards: Default::default(), }) ); }) @@ -1584,7 +1584,7 @@ fn rebond_emits_right_value_in_event() { UnlockChunk { value: 900, era: 1 + 3 } ]) .expect("MaxUnlockingChunks>1"), - claimed_rewards: WeakBoundedVec::default(), + claimed_rewards: Default::default(), }) ); @@ -1600,7 +1600,7 @@ fn rebond_emits_right_value_in_event() { UnlockChunk { value: 800, era: 1 + 3 } ]) .expect("MaxUnlockingChunks>1"), - claimed_rewards: WeakBoundedVec::default(), + claimed_rewards: Default::default(), }) ); // Event emitted should be correct @@ -1615,7 +1615,7 @@ fn rebond_emits_right_value_in_event() { total: 1000, active: 1000, unlocking: BoundedVec::default(), - claimed_rewards: WeakBoundedVec::default(), + claimed_rewards: Default::default(), }) ); // Event emitted should be correct, only 800 @@ -1646,7 +1646,7 @@ fn reward_to_stake_works() { ErasStakers::::insert( 0, 21, - Exposure { total: 69, own: 69, others: WeakBoundedVec::default() }, + Exposure { total: 69, own: 69, others: Default::default() }, ); >::insert( &20, @@ -1655,7 +1655,7 @@ fn reward_to_stake_works() { total: 69, active: 69, unlocking: BoundedVec::default(), - claimed_rewards: WeakBoundedVec::default(), + claimed_rewards: Default::default(), }, ); @@ -1902,7 +1902,7 @@ fn bond_with_no_staked_value() { vec![UnlockChunk { value: 5, era: 3 }] ) .expect("MaxUnlockingChunks>1"), - claimed_rewards: WeakBoundedVec::default(), + claimed_rewards: Default::default(), }) ); @@ -2123,7 +2123,7 @@ fn reward_validator_slashing_validator_does_not_overflow() { let exposure = Exposure::::MaxIndividualExposures> { total: stake, own: stake, - others: WeakBoundedVec::default(), + others: Default::default(), }; let reward = EraRewardPoints { total: 1, @@ -2141,7 +2141,7 @@ fn reward_validator_slashing_validator_does_not_overflow() { Exposure::::MaxRewardableIndividualExposures> { total: stake, own: stake, - others: WeakBoundedVec::default(), + others: Default::default(), }; ErasStakersClipped::::insert(0, 11, exposure_clipped); ErasValidatorReward::::insert(0, stake); @@ -2351,7 +2351,7 @@ fn slashing_performed_according_exposure() { &[OffenceDetails { offender: ( 11, - Exposure { total: 500, own: 500, others: WeakBoundedVec::default() }, + Exposure { total: 500, own: 500, others: Default::default() }, ), reporters: vec![], }], @@ -3329,8 +3329,8 @@ fn test_payout_stakers() { active: 1000, unlocking: BoundedVec::default(), claimed_rewards: - WeakBoundedVec::<_, ::MaxErasForRewards>::try_from(vec![1]) - .expect("MaxErasForRewards>1"), + WeakBoundedVec::<_, ::MaxHistoryDepth>::try_from(vec![1]) + .expect("MaxHistoryDepth>1"), }) ); @@ -3353,7 +3353,7 @@ fn test_payout_stakers() { active: 1000, unlocking: BoundedVec::default(), claimed_rewards: - WeakBoundedVec::<_, ::MaxErasForRewards>::try_from( + WeakBoundedVec::<_, ::MaxHistoryDepth>::try_from( (1..=14).collect::>() ) .expect("Test configuration should be changed") @@ -3378,8 +3378,8 @@ fn test_payout_stakers() { active: 1000, unlocking: BoundedVec::default(), claimed_rewards: - WeakBoundedVec::<_, ::MaxErasForRewards>::try_from(vec![15, 98]) - .expect("MaxErasForRewards should be > 1"), + WeakBoundedVec::<_, ::MaxHistoryDepth>::try_from(vec![15, 98]) + .expect("MaxHistoryDepth should be > 1"), }) ); @@ -3395,10 +3395,10 @@ fn test_payout_stakers() { active: 1000, unlocking: BoundedVec::default(), claimed_rewards: - WeakBoundedVec::<_, ::MaxErasForRewards>::try_from(vec![ + WeakBoundedVec::<_, ::MaxHistoryDepth>::try_from(vec![ 15, 23, 42, 69, 98 ]) - .expect("MaxErasForRewards should be > 4") + .expect("MaxHistoryDepth should be > 4") }) ); }); @@ -3593,7 +3593,7 @@ fn bond_during_era_correctly_populates_claimed_rewards() { total: 1000, active: 1000, unlocking: BoundedVec::default(), - claimed_rewards: WeakBoundedVec::default(), + claimed_rewards: Default::default(), }) ); mock::start_active_era(5); @@ -3606,10 +3606,10 @@ fn bond_during_era_correctly_populates_claimed_rewards() { active: 1000, unlocking: BoundedVec::default(), claimed_rewards: - WeakBoundedVec::<_, ::MaxErasForRewards>::try_from( + WeakBoundedVec::<_, ::MaxHistoryDepth>::try_from( (0..5).collect::>() ) - .expect("MaxErasForRewards should be >= 5"), + .expect("MaxHistoryDepth should be >= 5"), }) ); mock::start_active_era(99); @@ -3622,7 +3622,7 @@ fn bond_during_era_correctly_populates_claimed_rewards() { active: 1000, unlocking: BoundedVec::default(), claimed_rewards: - WeakBoundedVec::<_, ::MaxErasForRewards>::try_from( + WeakBoundedVec::<_, ::MaxHistoryDepth>::try_from( (15..99).collect::>() ) .expect("Some test configuration may need changing"), @@ -3844,7 +3844,7 @@ fn cannot_rebond_to_lower_than_ed() { total: 10 * 1000, active: 10 * 1000, unlocking: BoundedVec::default(), - claimed_rewards: WeakBoundedVec::default(), + claimed_rewards: Default::default(), } ); @@ -3861,7 +3861,7 @@ fn cannot_rebond_to_lower_than_ed() { vec![UnlockChunk { value: 10 * 1000, era: 3 }] ) .expect("MaxUnlockingChunks>1"), - claimed_rewards: WeakBoundedVec::default(), + claimed_rewards: Default::default(), } ); @@ -3884,7 +3884,7 @@ fn cannot_bond_extra_to_lower_than_ed() { total: 10 * 1000, active: 10 * 1000, unlocking: BoundedVec::default(), - claimed_rewards: WeakBoundedVec::default(), + claimed_rewards: Default::default(), } ); @@ -3901,7 +3901,7 @@ fn cannot_bond_extra_to_lower_than_ed() { vec![UnlockChunk { value: 10 * 1000, era: 3 }] ) .expect("MaxUnlockingChunks>1"), - claimed_rewards: WeakBoundedVec::default(), + claimed_rewards: Default::default(), } ); @@ -3928,7 +3928,7 @@ fn do_not_die_when_active_is_ed() { total: 1000 * ed, active: 1000 * ed, unlocking: BoundedVec::default(), - claimed_rewards: WeakBoundedVec::default(), + claimed_rewards: Default::default(), } ); @@ -3945,7 +3945,7 @@ fn do_not_die_when_active_is_ed() { total: ed, active: ed, unlocking: BoundedVec::default(), - claimed_rewards: WeakBoundedVec::default(), + claimed_rewards: Default::default(), } ); }) From 545a98a51e674be4e6c3bf5a7afb7812c014bc9b Mon Sep 17 00:00:00 2001 From: Georges Dib Date: Tue, 12 Oct 2021 23:20:09 +0100 Subject: [PATCH 51/80] Make `OffendingValidators` a `BoundedVec` which is bounded by `MaxValidatorsCount` Some other fixes post merge --- frame/staking/src/mock.rs | 1 + frame/staking/src/pallet/mod.rs | 3 ++- frame/staking/src/slashing.rs | 6 ++++-- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/frame/staking/src/mock.rs b/frame/staking/src/mock.rs index 10eb24e9187b0..3eb99bbdb678d 100644 --- a/frame/staking/src/mock.rs +++ b/frame/staking/src/mock.rs @@ -34,6 +34,7 @@ use sp_runtime::{ traits::{IdentityLookup, Zero}, }; use sp_staking::offence::{OffenceDetails, OnOffenceHandler}; +use sp_std::collections::btree_map::BTreeMap; use std::cell::RefCell; pub const INIT_TIMESTAMP: u64 = 30_000; diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index 4331b9115c812..d2b57400abf5f 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -502,7 +502,8 @@ pub mod pallet { /// the era ends. #[pallet::storage] #[pallet::getter(fn offending_validators)] - pub type OffendingValidators = StorageValue<_, Vec<(u32, bool)>, ValueQuery>; + pub type OffendingValidators = + StorageValue<_, BoundedVec<(u32, bool), T::MaxValidatorsCount>, ValueQuery>; /// True if network has been upgraded to this version. /// Storage version of the pallet. diff --git a/frame/staking/src/slashing.rs b/frame/staking/src/slashing.rs index 41ccab6a8867c..af78bc2617465 100644 --- a/frame/staking/src/slashing.rs +++ b/frame/staking/src/slashing.rs @@ -56,7 +56,7 @@ use crate::{ use codec::{Decode, Encode, MaxEncodedLen}; use frame_support::{ ensure, - traits::{Currency, Get, Imbalance, OnUnbalanced}, + traits::{Currency, Imbalance, OnUnbalanced}, CloneNoBound, WeakBoundedVec, }; use scale_info::TypeInfo; @@ -346,7 +346,9 @@ fn add_offending_validator(stash: &T::AccountId, disable: bool) { match offending.binary_search_by_key(&validator_index_u32, |(index, _)| *index) { // this is a new offending validator Err(index) => { - offending.insert(index, (validator_index_u32, disable)); + offending + .try_insert(index, (validator_index_u32, disable)) + .expect("Cannot be more than MaxValidatorsCount"); let offending_threshold = T::OffendingValidatorsThreshold::get() * validators.len() as u32; From e8aff2939172b2b114cc71e6a100691a8e4ff30c Mon Sep 17 00:00:00 2001 From: Georges Dib Date: Tue, 12 Oct 2021 23:30:14 +0100 Subject: [PATCH 52/80] Fixing fmt --- frame/babe/src/tests.rs | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/frame/babe/src/tests.rs b/frame/babe/src/tests.rs index 53054b94c3df6..bb25d1792935c 100644 --- a/frame/babe/src/tests.rs +++ b/frame/babe/src/tests.rs @@ -415,11 +415,7 @@ fn report_equivocation_current_session_works() { assert_eq!( Staking::eras_stakers(1, validator), - pallet_staking::Exposure { - total: 10_000, - own: 10_000, - others: Default::default() - }, + pallet_staking::Exposure { total: 10_000, own: 10_000, others: Default::default() }, ); } @@ -473,11 +469,7 @@ fn report_equivocation_current_session_works() { assert_eq!(Staking::slashable_balance_of(validator), 10_000); assert_eq!( Staking::eras_stakers(2, validator), - pallet_staking::Exposure { - total: 10_000, - own: 10_000, - others: Default::default() - }, + pallet_staking::Exposure { total: 10_000, own: 10_000, others: Default::default() }, ); } }) From a53cfc9819c063ce74f0f377cb42a83243401043 Mon Sep 17 00:00:00 2001 From: Georges Dib Date: Tue, 12 Oct 2021 23:42:45 +0100 Subject: [PATCH 53/80] fmt --- frame/grandpa/src/tests.rs | 24 ++++-------------------- 1 file changed, 4 insertions(+), 20 deletions(-) diff --git a/frame/grandpa/src/tests.rs b/frame/grandpa/src/tests.rs index 1284eb200f261..88eadfd504f13 100644 --- a/frame/grandpa/src/tests.rs +++ b/frame/grandpa/src/tests.rs @@ -329,11 +329,7 @@ fn report_equivocation_current_set_works() { assert_eq!( Staking::eras_stakers(1, validator), - pallet_staking::Exposure { - total: 10_000, - own: 10_000, - others: Default::default() - }, + pallet_staking::Exposure { total: 10_000, own: 10_000, others: Default::default() }, ); } @@ -385,11 +381,7 @@ fn report_equivocation_current_set_works() { assert_eq!( Staking::eras_stakers(2, validator), - pallet_staking::Exposure { - total: 10_000, - own: 10_000, - others: Default::default() - }, + pallet_staking::Exposure { total: 10_000, own: 10_000, others: Default::default() }, ); } }); @@ -421,11 +413,7 @@ fn report_equivocation_old_set_works() { assert_eq!( Staking::eras_stakers(2, validator), - pallet_staking::Exposure { - total: 10_000, - own: 10_000, - others: Default::default() - }, + pallet_staking::Exposure { total: 10_000, own: 10_000, others: Default::default() }, ); } @@ -472,11 +460,7 @@ fn report_equivocation_old_set_works() { assert_eq!( Staking::eras_stakers(3, validator), - pallet_staking::Exposure { - total: 10_000, - own: 10_000, - others: Default::default() - }, + pallet_staking::Exposure { total: 10_000, own: 10_000, others: Default::default() }, ); } }); From 9105c63d2662d277c81d068ea940758e8517ba20 Mon Sep 17 00:00:00 2001 From: Georges Dib Date: Tue, 12 Oct 2021 23:50:50 +0100 Subject: [PATCH 54/80] fmt --- frame/staking/src/tests.rs | 85 ++++++++++++++++++-------------------- 1 file changed, 41 insertions(+), 44 deletions(-) diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index 621074d257857..d370832faf240 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -389,9 +389,10 @@ fn staking_should_work() { total: 1500, active: 1500, unlocking: BoundedVec::default(), - claimed_rewards: - WeakBoundedVec::<_, ::MaxHistoryDepth>::try_from(vec![0]) - .expect("Test configuration needs changing"), + claimed_rewards: WeakBoundedVec::<_, ::MaxHistoryDepth>::try_from( + vec![0] + ) + .expect("Test configuration needs changing"), }) ); // e.g. it cannot reserve more than 500 that it has free from the total 2000 @@ -966,9 +967,10 @@ fn reward_destination_works() { total: 1000 + total_payout_0, active: 1000 + total_payout_0, unlocking: BoundedVec::default(), - claimed_rewards: - WeakBoundedVec::<_, ::MaxHistoryDepth>::try_from(vec![0]) - .expect("Test configuration needs changing"), + claimed_rewards: WeakBoundedVec::<_, ::MaxHistoryDepth>::try_from( + vec![0] + ) + .expect("Test configuration needs changing"), }) ); @@ -996,9 +998,10 @@ fn reward_destination_works() { total: 1000 + total_payout_0, active: 1000 + total_payout_0, unlocking: BoundedVec::default(), - claimed_rewards: - WeakBoundedVec::<_, ::MaxHistoryDepth>::try_from(vec![0, 1]) - .expect("Test configuration needs changing"), + claimed_rewards: WeakBoundedVec::<_, ::MaxHistoryDepth>::try_from( + vec![0, 1] + ) + .expect("Test configuration needs changing"), }) ); @@ -1027,11 +1030,10 @@ fn reward_destination_works() { total: 1000 + total_payout_0, active: 1000 + total_payout_0, unlocking: BoundedVec::default(), - claimed_rewards: - WeakBoundedVec::<_, ::MaxHistoryDepth>::try_from(vec![ - 0, 1, 2 - ]) - .expect("Test configuration needs changing"), + claimed_rewards: WeakBoundedVec::<_, ::MaxHistoryDepth>::try_from( + vec![0, 1, 2] + ) + .expect("Test configuration needs changing"), }) ); // Check that amount in staked account is NOT increased. @@ -2349,10 +2351,7 @@ fn slashing_performed_according_exposure() { // Handle an offence with a historical exposure. on_offence_now( &[OffenceDetails { - offender: ( - 11, - Exposure { total: 500, own: 500, others: Default::default() }, - ), + offender: (11, Exposure { total: 500, own: 500, others: Default::default() }), reporters: vec![], }], &[Perbill::from_percent(50)], @@ -3458,9 +3457,10 @@ fn test_payout_stakers() { total: 1000, active: 1000, unlocking: BoundedVec::default(), - claimed_rewards: - WeakBoundedVec::<_, ::MaxHistoryDepth>::try_from(vec![1]) - .expect("MaxHistoryDepth>1"), + claimed_rewards: WeakBoundedVec::<_, ::MaxHistoryDepth>::try_from( + vec![1] + ) + .expect("MaxHistoryDepth>1"), }) ); @@ -3482,11 +3482,10 @@ fn test_payout_stakers() { total: 1000, active: 1000, unlocking: BoundedVec::default(), - claimed_rewards: - WeakBoundedVec::<_, ::MaxHistoryDepth>::try_from( - (1..=14).collect::>() - ) - .expect("Test configuration should be changed") + claimed_rewards: WeakBoundedVec::<_, ::MaxHistoryDepth>::try_from( + (1..=14).collect::>() + ) + .expect("Test configuration should be changed") }) ); @@ -3507,9 +3506,10 @@ fn test_payout_stakers() { total: 1000, active: 1000, unlocking: BoundedVec::default(), - claimed_rewards: - WeakBoundedVec::<_, ::MaxHistoryDepth>::try_from(vec![15, 98]) - .expect("MaxHistoryDepth should be > 1"), + claimed_rewards: WeakBoundedVec::<_, ::MaxHistoryDepth>::try_from( + vec![15, 98] + ) + .expect("MaxHistoryDepth should be > 1"), }) ); @@ -3524,11 +3524,10 @@ fn test_payout_stakers() { total: 1000, active: 1000, unlocking: BoundedVec::default(), - claimed_rewards: - WeakBoundedVec::<_, ::MaxHistoryDepth>::try_from(vec![ - 15, 23, 42, 69, 98 - ]) - .expect("MaxHistoryDepth should be > 4") + claimed_rewards: WeakBoundedVec::<_, ::MaxHistoryDepth>::try_from( + vec![15, 23, 42, 69, 98] + ) + .expect("MaxHistoryDepth should be > 4") }) ); }); @@ -3735,11 +3734,10 @@ fn bond_during_era_correctly_populates_claimed_rewards() { total: 1000, active: 1000, unlocking: BoundedVec::default(), - claimed_rewards: - WeakBoundedVec::<_, ::MaxHistoryDepth>::try_from( - (0..5).collect::>() - ) - .expect("MaxHistoryDepth should be >= 5"), + claimed_rewards: WeakBoundedVec::<_, ::MaxHistoryDepth>::try_from( + (0..5).collect::>() + ) + .expect("MaxHistoryDepth should be >= 5"), }) ); mock::start_active_era(99); @@ -3751,11 +3749,10 @@ fn bond_during_era_correctly_populates_claimed_rewards() { total: 1000, active: 1000, unlocking: BoundedVec::default(), - claimed_rewards: - WeakBoundedVec::<_, ::MaxHistoryDepth>::try_from( - (15..99).collect::>() - ) - .expect("Some test configuration may need changing"), + claimed_rewards: WeakBoundedVec::<_, ::MaxHistoryDepth>::try_from( + (15..99).collect::>() + ) + .expect("Some test configuration may need changing"), }) ); }); From 9cd2bd6f6498f591ebd989f40b9195ee8c3121f8 Mon Sep 17 00:00:00 2001 From: Georges Dib Date: Wed, 13 Oct 2021 22:28:23 +0100 Subject: [PATCH 55/80] Fixing tests --- .../test/tests/pallet_ui/storage_info_unsatisfied_nmap.stderr | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frame/support/test/tests/pallet_ui/storage_info_unsatisfied_nmap.stderr b/frame/support/test/tests/pallet_ui/storage_info_unsatisfied_nmap.stderr index 2b70102fdac24..ffbc5aeea6b4f 100644 --- a/frame/support/test/tests/pallet_ui/storage_info_unsatisfied_nmap.stderr +++ b/frame/support/test/tests/pallet_ui/storage_info_unsatisfied_nmap.stderr @@ -4,8 +4,8 @@ error[E0277]: the trait bound `Bar: MaxEncodedLen` is not satisfied 10 | #[pallet::generate_storage_info] | ^^^^^^^^^^^^^^^^^^^^^ the trait `MaxEncodedLen` is not implemented for `Bar` | - = note: required because of the requirements on the impl of `KeyGeneratorMaxEncodedLen` for `Key` - = note: required because of the requirements on the impl of `StorageInfoTrait` for `frame_support::pallet_prelude::StorageNMap<_GeneratedPrefixForStorageFoo, Key, u32>` + = note: required because of the requirements on the impl of `KeyGeneratorMaxEncodedLen` for `NMapKey` + = note: required because of the requirements on the impl of `StorageInfoTrait` for `frame_support::pallet_prelude::StorageNMap<_GeneratedPrefixForStorageFoo, NMapKey, u32>` note: required by `storage_info` --> $DIR/storage.rs:71:2 | From b54368da156b6a0ac257b589f7e69b69bfb22c1a Mon Sep 17 00:00:00 2001 From: Georges Dib Date: Wed, 20 Oct 2021 12:50:22 +0100 Subject: [PATCH 56/80] Adding storage info to frame session --- frame/session/src/historical/mod.rs | 58 +++++++---- frame/session/src/lib.rs | 126 ++++++++++++++--------- frame/staking/src/lib.rs | 9 +- frame/staking/src/pallet/impls.rs | 69 ++++++++----- frame/staking/src/pallet/mod.rs | 2 + frame/support/src/storage/bounded_vec.rs | 20 +++- primitives/core/src/crypto.rs | 31 +++--- 7 files changed, 204 insertions(+), 111 deletions(-) diff --git a/frame/session/src/historical/mod.rs b/frame/session/src/historical/mod.rs index 0801b2aca1701..ef99ba96b5c32 100644 --- a/frame/session/src/historical/mod.rs +++ b/frame/session/src/historical/mod.rs @@ -31,7 +31,7 @@ use codec::{Decode, Encode}; use frame_support::{ decl_module, decl_storage, print, traits::{ValidatorSet, ValidatorSetWithIdentification}, - Parameter, + BoundedVec, Parameter, }; use sp_runtime::{ traits::{Convert, OpaqueKeys}, @@ -94,7 +94,7 @@ impl Module { let up_to = sp_std::cmp::min(up_to, end); if up_to < start { - return // out of bounds. harmless. + return; // out of bounds. harmless. } (start..up_to).for_each(::HistoricalSessions::remove); @@ -118,7 +118,7 @@ impl ValidatorSet for Module { } fn validators() -> Vec { - super::Pallet::::validators() + super::Pallet::::validators().to_vec() } } @@ -129,16 +129,18 @@ impl ValidatorSetWithIdentification for Module { /// Specialization of the crate-level `SessionManager` which returns the set of full identification /// when creating a new session. -pub trait SessionManager: - crate::SessionManager +pub trait SessionManager: + crate::SessionManager { /// If there was a validator set change, its returns the set of new validators along with their /// full identifications. - fn new_session(new_index: SessionIndex) -> Option>; + fn new_session( + new_index: SessionIndex, + ) -> Option>; fn new_session_genesis( new_index: SessionIndex, - ) -> Option> { - >::new_session(new_index) + ) -> Option> { + >::new_session(new_index) } fn start_session(start_index: SessionIndex); fn end_session(end_index: SessionIndex); @@ -148,20 +150,27 @@ pub trait SessionManager: /// sets the historical trie root of the ending session. pub struct NoteHistoricalRoot(sp_std::marker::PhantomData<(T, I)>); -impl> NoteHistoricalRoot { - fn do_new_session(new_index: SessionIndex, is_genesis: bool) -> Option> { +impl< + T: Config, + I: SessionManager, + > NoteHistoricalRoot +{ + fn do_new_session( + new_index: SessionIndex, + is_genesis: bool, + ) -> Option> { StoredRange::mutate(|range| { range.get_or_insert_with(|| (new_index, new_index)).1 = new_index + 1; }); let new_validators_and_id = if is_genesis { - >::new_session_genesis(new_index) + >::new_session_genesis(new_index) } else { - >::new_session(new_index) + >::new_session(new_index) }; let new_validators_opt = new_validators_and_id .as_ref() - .map(|new_validators| new_validators.iter().map(|(v, _id)| v.clone()).collect()); + .map(|new_validators| new_validators.map_collect_ref(|(v, _id)| v.clone())); if let Some(new_validators) = new_validators_and_id { let count = new_validators.len() as ValidatorCount; @@ -170,7 +179,7 @@ impl> NoteHi Err(reason) => { print("Failed to generate historical ancestry-inclusion proof."); print(reason); - }, + } }; } else { let previous_index = new_index.saturating_sub(1); @@ -183,25 +192,30 @@ impl> NoteHi } } -impl crate::SessionManager for NoteHistoricalRoot +impl crate::SessionManager + for NoteHistoricalRoot where - I: SessionManager, + I: SessionManager, { - fn new_session(new_index: SessionIndex) -> Option> { + fn new_session( + new_index: SessionIndex, + ) -> Option> { Self::do_new_session(new_index, false) } - fn new_session_genesis(new_index: SessionIndex) -> Option> { + fn new_session_genesis( + new_index: SessionIndex, + ) -> Option> { Self::do_new_session(new_index, true) } fn start_session(start_index: SessionIndex) { - >::start_session(start_index) + >::start_session(start_index) } fn end_session(end_index: SessionIndex) { onchain::store_session_validator_set_to_offchain::(end_index); - >::end_session(end_index) + >::end_session(end_index) } } @@ -341,7 +355,7 @@ impl> frame_support::traits::KeyOwnerProofSystem<(KeyT let count = >::validators().len() as ValidatorCount; if count != proof.validator_count { - return None + return None; } Some((owner, id)) @@ -351,7 +365,7 @@ impl> frame_support::traits::KeyOwnerProofSystem<(KeyT let (root, count) = >::get(&proof.session)?; if count != proof.validator_count { - return None + return None; } let trie = ProvingTrie::::from_nodes(root, &proof.trie_nodes); diff --git a/frame/session/src/lib.rs b/frame/session/src/lib.rs index 10c7ea42b3e9b..385e919d0649a 100644 --- a/frame/session/src/lib.rs +++ b/frame/session/src/lib.rs @@ -120,6 +120,7 @@ use sp_runtime::{ }; use sp_staking::SessionIndex; use sp_std::{ + convert::TryFrom, marker::PhantomData, ops::{Rem, Sub}, prelude::*, @@ -134,7 +135,7 @@ use frame_support::{ StorageVersion, ValidatorRegistration, ValidatorSet, }, weights::Weight, - Parameter, + BoundedVec, Parameter, WeakBoundedVec, }; pub use pallet::*; @@ -224,7 +225,7 @@ impl< } /// A trait for managing creation of new validator set. -pub trait SessionManager { +pub trait SessionManager { /// Plan a new session, and optionally provide the new validator set. /// /// Even if the validator-set is the same as before, if any underlying economic conditions have @@ -238,12 +239,14 @@ pub trait SessionManager { /// /// `new_session(session)` is guaranteed to be called before `end_session(session-1)`. In other /// words, a new session must always be planned before an ongoing one can be finished. - fn new_session(new_index: SessionIndex) -> Option>; + fn new_session(new_index: SessionIndex) -> Option>; /// Same as `new_session`, but it this should only be called at genesis. /// /// The session manager might decide to treat this in a different way. Default impl is simply /// using [`new_session`](Self::new_session). - fn new_session_genesis(new_index: SessionIndex) -> Option> { + fn new_session_genesis( + new_index: SessionIndex, + ) -> Option> { Self::new_session(new_index) } /// End the session. @@ -257,8 +260,8 @@ pub trait SessionManager { fn start_session(start_index: SessionIndex); } -impl SessionManager for () { - fn new_session(_: SessionIndex) -> Option> { +impl SessionManager for () { + fn new_session(_: SessionIndex) -> Option> { None } fn start_session(_: SessionIndex) {} @@ -369,6 +372,7 @@ pub mod pallet { #[pallet::pallet] #[pallet::generate_store(pub(super) trait Store)] #[pallet::storage_version(STORAGE_VERSION)] + #[pallet::generate_storage_info] pub struct Pallet(_); #[pallet::config] @@ -393,16 +397,27 @@ pub mod pallet { type NextSessionRotation: EstimateNextSessionRotation; /// Handler for managing new session. - type SessionManager: SessionManager; + type SessionManager: SessionManager; /// Handler when a session has changed. type SessionHandler: SessionHandler; /// The keys. - type Keys: OpaqueKeys + Member + Parameter + Default + MaybeSerializeDeserialize; + type Keys: OpaqueKeys + + Member + + Parameter + + Default + + MaybeSerializeDeserialize + + MaxEncodedLen; /// Weight information for extrinsics in this pallet. type WeightInfo: WeightInfo; + + /// Maximum number of validators. + type MaxValidatorsCount: Get; + + /// Maximum size of the encoding of the validator's keys + type MaxKeysEncodingSize: Get; } #[pallet::genesis_config] @@ -455,7 +470,10 @@ pub mod pallet { "No initial validator provided by `SessionManager`, use \ session config keys to generate initial validator set.", ); - self.keys.iter().map(|x| x.1.clone()).collect() + BoundedVec::<_, T::MaxValidatorsCount>::try_from( + self.keys.iter().map(|x| x.1.clone()).collect::>(), + ) + .expect("Number of validators provided for session 0 is too big") }); assert!( !initial_validators_0.is_empty(), @@ -469,14 +487,11 @@ pub mod pallet { "Empty validator set for session 1 in genesis block!" ); - let queued_keys: Vec<_> = initial_validators_1 - .iter() - .cloned() - .map(|v| (v.clone(), >::load_keys(&v).unwrap_or_default())) - .collect(); + let queued_keys = initial_validators_1 + .map_collect(|v| (v.clone(), >::load_keys(&v).unwrap_or_default())); // Tell everyone about the genesis session keys - T::SessionHandler::on_genesis_session::(&queued_keys); + T::SessionHandler::on_genesis_session::(&(queued_keys.to_vec())); >::put(initial_validators_0); >::put(queued_keys); @@ -488,7 +503,8 @@ pub mod pallet { /// The current set of validators. #[pallet::storage] #[pallet::getter(fn validators)] - pub type Validators = StorageValue<_, Vec, ValueQuery>; + pub type Validators = + StorageValue<_, BoundedVec, ValueQuery>; /// Current index of the session. #[pallet::storage] @@ -504,7 +520,8 @@ pub mod pallet { /// will be used to determine the validator's session keys. #[pallet::storage] #[pallet::getter(fn queued_keys)] - pub type QueuedKeys = StorageValue<_, Vec<(T::ValidatorId, T::Keys)>, ValueQuery>; + pub type QueuedKeys = + StorageValue<_, BoundedVec<(T::ValidatorId, T::Keys), T::MaxValidatorsCount>, ValueQuery>; /// Indices of disabled validators. /// @@ -513,7 +530,8 @@ pub mod pallet { /// a new set of identities. #[pallet::storage] #[pallet::getter(fn disabled_validators)] - pub type DisabledValidators = StorageValue<_, Vec, ValueQuery>; + pub type DisabledValidators = + StorageValue<_, BoundedVec, ValueQuery>; /// The next session keys for a validator. #[pallet::storage] @@ -522,8 +540,13 @@ pub mod pallet { /// The owner of a key. The key is the `KeyTypeId` + the encoded key. #[pallet::storage] - pub type KeyOwner = - StorageMap<_, Twox64Concat, (KeyTypeId, Vec), T::ValidatorId, OptionQuery>; + pub type KeyOwner = StorageMap< + _, + Twox64Concat, + (KeyTypeId, WeakBoundedVec), + T::ValidatorId, + OptionQuery, + >; #[pallet::event] #[pallet::generate_deposit(pub(super) fn deposit_event)] @@ -631,8 +654,7 @@ impl Pallet { // Get queued session keys and validators. let session_keys = >::get(); - let validators = - session_keys.iter().map(|(validator, _)| validator.clone()).collect::>(); + let validators = session_keys.map_collect_ref(|(validator, _)| validator.clone()); >::put(&validators); if changed { @@ -667,7 +689,7 @@ impl Pallet { let mut now_session_keys = session_keys.iter(); let mut check_next_changed = |keys: &T::Keys| { if changed { - return + return; } // since a new validator set always leads to `changed` starting // as true, we can ensure that `now_session_keys` and `next_validators` @@ -675,18 +697,15 @@ impl Pallet { if let Some(&(_, ref old_keys)) = now_session_keys.next() { if old_keys != keys { changed = true; - return + return; } } }; - let queued_amalgamated = next_validators - .into_iter() - .map(|a| { - let k = Self::load_keys(&a).unwrap_or_default(); - check_next_changed(&k); - (a, k) - }) - .collect::>(); + let queued_amalgamated = next_validators.map_collect(|a| { + let k = Self::load_keys(&a).unwrap_or_default(); + check_next_changed(&k); + (a, k) + }); (queued_amalgamated, changed) }; @@ -704,14 +723,18 @@ impl Pallet { /// Disable the validator of index `i`, returns `false` if the validator was already disabled. pub fn disable_index(i: u32) -> bool { if i >= Validators::::decode_len().unwrap_or(0) as u32 { - return false + return false; } >::mutate(|disabled| { if let Err(index) = disabled.binary_search(&i) { - disabled.insert(index, i); + if disabled.try_insert(index, i).is_err() { + // This should never fail + log::warn!(target: "runtime::session", "disabling validator index {:?}", i); + return false; + } T::SessionHandler::on_disabled(i); - return true + return true; } false @@ -772,12 +795,11 @@ impl Pallet { Some(new_keys) }); - let _ = >::translate::, _>(|k| { - k.map(|k| { - k.into_iter() - .map(|(val, old_keys)| (val.clone(), upgrade(val, old_keys))) - .collect::>() - }) + let _ = >::translate::< + BoundedVec<(T::ValidatorId, Old), T::MaxValidatorsCount>, + _, + >(|k| { + k.map(|k| k.map_collect(|(val, old_keys)| (val.clone(), upgrade(val, old_keys)))) }); } @@ -826,7 +848,7 @@ impl Pallet { if let Some(old) = old_keys.as_ref().map(|k| k.get_raw(*id)) { if key == old { - continue + continue; } Self::clear_key_owner(*id, old); @@ -867,15 +889,27 @@ impl Pallet { /// Query the owner of a session key by returning the owner's validator ID. pub fn key_owner(id: KeyTypeId, key_data: &[u8]) -> Option { - >::get((id, key_data)) + let key_data_bounded = WeakBoundedVec::<_, T::MaxKeysEncodingSize>::force_from( + key_data.to_vec(), + Some("frame_session.key_owner"), + ); + >::get((id, key_data_bounded)) } fn put_key_owner(id: KeyTypeId, key_data: &[u8], v: &T::ValidatorId) { - >::insert((id, key_data), v) + let key_data_bounded = WeakBoundedVec::<_, T::MaxKeysEncodingSize>::force_from( + key_data.to_vec(), + Some("frame_session.put_key_owner"), + ); + >::insert((id, key_data_bounded), v) } fn clear_key_owner(id: KeyTypeId, key_data: &[u8]) { - >::remove((id, key_data)); + let key_data_bounded = WeakBoundedVec::<_, T::MaxKeysEncodingSize>::force_from( + key_data.to_vec(), + Some("frame_session.clear_key_owner"), + ); + >::remove((id, key_data_bounded)); } } @@ -894,7 +928,7 @@ impl ValidatorSet for Pallet { } fn validators() -> Vec { - Pallet::::validators() + Pallet::::validators().to_vec() } } diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index be02e8d91d326..c5dc400436cd8 100644 --- a/frame/staking/src/lib.rs +++ b/frame/staking/src/lib.rs @@ -498,7 +498,7 @@ impl } if unlocking_balance >= value { - break + break; } } @@ -636,7 +636,10 @@ where FullIdentificationOf = ExposureOf, >, T::SessionHandler: pallet_session::SessionHandler<::AccountId>, - T::SessionManager: pallet_session::SessionManager<::AccountId>, + T::SessionManager: pallet_session::SessionManager< + ::AccountId, + ::MaxValidatorsCount, + >, T::ValidatorIdOf: Convert< ::AccountId, Option<::AccountId>, @@ -647,7 +650,7 @@ where } fn validators() -> Vec<::AccountId> { - >::validators() + >::validators().to_vec() } fn prune_historical_up_to(up_to: SessionIndex) { diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index 02099d8543d4c..4ea029289f8ca 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -143,7 +143,7 @@ impl Pallet { // Nothing to do if they have no reward points. if validator_reward_points.is_zero() { - return Ok(Some(T::WeightInfo::payout_stakers_alive_staked(0)).into()) + return Ok(Some(T::WeightInfo::payout_stakers_alive_staked(0)).into()); } // This is the fraction of the total reward that the validator and the @@ -235,14 +235,18 @@ impl Pallet { Self::update_ledger(&controller, &l); r }), - RewardDestination::Account(dest_account) => - Some(T::Currency::deposit_creating(&dest_account, amount)), + RewardDestination::Account(dest_account) => { + Some(T::Currency::deposit_creating(&dest_account, amount)) + } RewardDestination::None => None, } } /// Plan a new session potentially trigger a new era. - fn new_session(session_index: SessionIndex, is_genesis: bool) -> Option> { + fn new_session( + session_index: SessionIndex, + is_genesis: bool, + ) -> Option> { if let Some(current_era) = Self::current_era() { // Initial era has been set. let current_era_start_session_index = Self::eras_start_session_index(current_era) @@ -264,14 +268,14 @@ impl Pallet { _ => { // Either `Forcing::ForceNone`, // or `Forcing::NotForcing if era_length >= T::SessionsPerEra::get()`. - return None - }, + return None; + } } // New era. let maybe_new_era_validators = Self::try_trigger_new_era(session_index, is_genesis); - if maybe_new_era_validators.is_some() && - matches!(ForceEra::::get(), Forcing::ForceNew) + if maybe_new_era_validators.is_some() + && matches!(ForceEra::::get(), Forcing::ForceNew) { ForceEra::::put(Forcing::NotForcing); } @@ -398,7 +402,7 @@ impl Pallet { pub fn trigger_new_era( start_session_index: SessionIndex, exposures: Vec<(T::AccountId, Exposure>)>, - ) -> Vec { + ) -> BoundedVec { // Increment or set current era. let new_planned_era = CurrentEra::::mutate(|s| { *s = Some(s.map(|s| s + 1).unwrap_or(0)); @@ -424,7 +428,7 @@ impl Pallet { pub(crate) fn try_trigger_new_era( start_session_index: SessionIndex, is_genesis: bool, - ) -> Option> { + ) -> Option> { let election_result = if is_genesis { T::GenesisElectionProvider::elect().map_err(|e| { log!(warn, "genesis election provider failed due to {:?}", e); @@ -457,12 +461,12 @@ impl Pallet { // TODO: this should be simplified #8911 CurrentEra::::put(0); ErasStartSessionIndex::::insert(&0, &start_session_index); - }, + } _ => (), } Self::deposit_event(Event::StakingElectionFailed); - return None + return None; } Self::deposit_event(Event::StakersElected); @@ -475,7 +479,7 @@ impl Pallet { pub fn store_stakers_info( exposures: Vec<(T::AccountId, Exposure>)>, new_planned_era: EraIndex, - ) -> Vec { + ) -> BoundedVec { let elected_stashes = exposures.iter().cloned().map(|(x, _)| x).collect::>(); // Populate stakers, exposures, and the snapshot of validator prefs. @@ -698,7 +702,7 @@ impl Pallet { Some(nominator) => { nominators_seen.saturating_inc(); nominator - }, + } None => break, }; @@ -876,7 +880,7 @@ impl ElectionDataProvider> for Pallet // We can't handle this case yet -- return an error. if maybe_max_len.map_or(false, |max_len| target_count > max_len as u32) { - return Err("Target snapshot too big") + return Err("Target snapshot too big"); } Ok(Self::get_npos_targets()) @@ -1022,13 +1026,17 @@ impl ElectionDataProvider> for Pallet /// /// 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 Pallet { - fn new_session(new_index: SessionIndex) -> Option> { +impl pallet_session::SessionManager for Pallet { + fn new_session( + new_index: SessionIndex, + ) -> Option> { log!(trace, "planning new session {}", new_index); CurrentPlannedSession::::put(new_index); Self::new_session(new_index, false) } - fn new_session_genesis(new_index: SessionIndex) -> Option> { + fn new_session_genesis( + new_index: SessionIndex, + ) -> Option> { log!(trace, "planning new session {} at genesis", new_index); CurrentPlannedSession::::put(new_index); Self::new_session(new_index, true) @@ -1043,12 +1051,18 @@ impl pallet_session::SessionManager for Pallet { } } -impl historical::SessionManager>> - for Pallet +impl + historical::SessionManager< + T::AccountId, + Exposure>, + T::MaxValidatorsCount, + > for Pallet { fn new_session( new_index: SessionIndex, - ) -> Option>)>> { + ) -> Option< + BoundedVec<(T::AccountId, Exposure>), T::MaxValidatorsCount>, + > { >::new_session(new_index).map(|validators| { let current_era = Self::current_era() // Must be some as a new era has been created. @@ -1065,7 +1079,9 @@ impl historical::SessionManager Option>)>> { + ) -> Option< + BoundedVec<(T::AccountId, Exposure>), T::MaxValidatorsCount>, + > { >::new_session_genesis(new_index).map( |validators| { let current_era = Self::current_era() @@ -1117,7 +1133,10 @@ where FullIdentificationOf = ExposureOf, >, T::SessionHandler: pallet_session::SessionHandler<::AccountId>, - T::SessionManager: pallet_session::SessionManager<::AccountId>, + T::SessionManager: pallet_session::SessionManager< + ::AccountId, + ::MaxValidatorsCount, + >, T::ValidatorIdOf: Convert< ::AccountId, Option<::AccountId>, @@ -1142,7 +1161,7 @@ where add_db_reads_writes(1, 0); if active_era.is_none() { // This offence need not be re-submitted. - return consumed_weight + return consumed_weight; } active_era.expect("value checked not to be `None`; qed").index }; @@ -1188,7 +1207,7 @@ where // Skip if the validator is invulnerable. if invulnerables.contains(stash) { - continue + continue; } let unapplied = slashing::compute_slash::(slashing::SlashParams { diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index 8e97a90e07544..750dde3ebbe8c 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -141,6 +141,8 @@ pub mod pallet { #[pallet::constant] type MaxNominatorRewardedPerValidator: Get; + type MaxValidatorsCount: Get; + /// The fraction of the validator set that is safe to be offending. /// After the threshold is reached a new era will be forced. type OffendingValidatorsThreshold: Get; diff --git a/frame/support/src/storage/bounded_vec.rs b/frame/support/src/storage/bounded_vec.rs index e51c6cd734113..bbe1c4f89201e 100644 --- a/frame/support/src/storage/bounded_vec.rs +++ b/frame/support/src/storage/bounded_vec.rs @@ -78,7 +78,7 @@ impl> Decode for BoundedVec { fn decode(input: &mut I) -> Result { let inner = Vec::::decode(input)?; if inner.len() > S::get() as usize { - return Err("BoundedVec exceeds its limit".into()) + return Err("BoundedVec exceeds its limit".into()); } Ok(Self(inner, PhantomData)) } @@ -137,6 +137,24 @@ impl BoundedVec { ) -> Option<&mut >::Output> { self.0.get_mut(index) } + + /// Utility to avoid having to transform `BoundedVec` into an + /// `Iterator` then use `map` and then `collect` to then `try_from` + /// back into a `BoundedVec` + pub fn map_collect(self, f: F) -> BoundedVec + where + F: FnMut(T) -> B, + { + BoundedVec::(self.into_iter().map(f).collect::>(), Default::default()) + } + + /// Same as `map_collect` but taking a reference to `self` + pub fn map_collect_ref(&self, f: F) -> BoundedVec + where + F: FnMut(&T) -> B, + { + BoundedVec::(self.0.iter().map(f).collect::>(), Default::default()) + } } impl> From> for Vec { diff --git a/primitives/core/src/crypto.rs b/primitives/core/src/crypto.rs index 21b8520c7780f..1b092d01d4b67 100644 --- a/primitives/core/src/crypto.rs +++ b/primitives/core/src/crypto.rs @@ -250,7 +250,7 @@ pub trait Ss58Codec: Sized + AsMut<[u8]> + AsRef<[u8]> + Default { let data = s.from_base58().map_err(|_| PublicError::BadBase58)?; if data.len() < 2 { - return Err(PublicError::BadLength) + return Err(PublicError::BadLength); } let (prefix_len, ident) = match data[0] { 0..=63 => (1, data[0] as u16), @@ -263,22 +263,22 @@ pub trait Ss58Codec: Sized + AsMut<[u8]> + AsRef<[u8]> + Default { let lower = (data[0] << 2) | (data[1] >> 6); let upper = data[1] & 0b00111111; (2, (lower as u16) | ((upper as u16) << 8)) - }, + } _ => return Err(PublicError::UnknownVersion), }; if data.len() != prefix_len + body_len + CHECKSUM_LEN { - return Err(PublicError::BadLength) + return Err(PublicError::BadLength); } let format = ident.into(); if !Self::format_is_allowed(format) { - return Err(PublicError::FormatNotAllowed) + return Err(PublicError::FormatNotAllowed); } let hash = ss58hash(&data[0..body_len + prefix_len]); let checksum = &hash.as_bytes()[0..CHECKSUM_LEN]; if data[body_len + prefix_len..body_len + prefix_len + CHECKSUM_LEN] != *checksum { // Invalid checksum. - return Err(PublicError::InvalidChecksum) + return Err(PublicError::InvalidChecksum); } res.as_mut().copy_from_slice(&data[prefix_len..body_len + prefix_len]); Ok((res, format)) @@ -309,7 +309,7 @@ pub trait Ss58Codec: Sized + AsMut<[u8]> + AsRef<[u8]> + Default { // lower bits of the upper byte in the low pos let second = ((ident >> 8) as u8) | ((ident & 0b0000_0000_0000_0011) as u8) << 6; vec![first | 0b01000000, second] - }, + } _ => unreachable!("masked out the upper two bits; qed"), }; v.extend(self.as_ref()); @@ -402,7 +402,7 @@ impl + AsRef<[u8]> + Default + Derive> Ss58Codec for T { r.as_mut().copy_from_slice(&d); r } else { - return Err(PublicError::BadLength) + return Err(PublicError::BadLength); } } else { Self::from_ss58check(s)? @@ -928,6 +928,7 @@ pub trait CryptoType { PassByInner, crate::RuntimeDebug, TypeInfo, + MaxEncodedLen, )] #[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))] pub struct KeyTypeId(pub [u8; 4]); @@ -950,7 +951,7 @@ impl<'a> TryFrom<&'a str> for KeyTypeId { fn try_from(x: &'a str) -> Result { let b = x.as_bytes(); if b.len() != 4 { - return Err(()) + return Err(()); } let mut res = KeyTypeId::default(); res.0.copy_from_slice(&b[0..4]); @@ -975,7 +976,7 @@ impl sp_std::fmt::Display for CryptoTypePublicPair { Ok(id) => id.to_string(), Err(_) => { format!("{:#?}", self.0) - }, + } }; write!(f, "{}-{}", id, HexDisplay::from(&self.1)) } @@ -1105,14 +1106,16 @@ mod tests { password, path: path.into_iter().chain(path_iter).collect(), }, - TestPair::GeneratedFromPhrase { phrase, password } => - TestPair::Standard { phrase, password, path: path_iter.collect() }, - x => + TestPair::GeneratedFromPhrase { phrase, password } => { + TestPair::Standard { phrase, password, path: path_iter.collect() } + } + x => { if path_iter.count() == 0 { x } else { - return Err(()) - }, + return Err(()); + } + } }, None, )) From 22f791533664d05fcd01ade3ad5cfc45522c0bad Mon Sep 17 00:00:00 2001 From: Georges Dib Date: Wed, 20 Oct 2021 12:59:09 +0100 Subject: [PATCH 57/80] Removing duplicate --- frame/staking/src/pallet/mod.rs | 35 +++++++++++++++------------------ 1 file changed, 16 insertions(+), 19 deletions(-) diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index 3ec61376520ac..174172d9b5060 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -175,8 +175,6 @@ pub mod pallet { /// successful call to `withdraw_unbonded` to remove some of the chunks. type MaxUnlockingChunks: Get; - type MaxValidatorsCount: Get; - /// The fraction of the validator set that is safe to be offending. /// After the threshold is reached a new era will be forced. type OffendingValidatorsThreshold: Get; @@ -982,24 +980,23 @@ pub mod pallet { ledger = ledger.consolidate_unlocked(current_era) } - let post_info_weight = if ledger.unlocking.is_empty() && - ledger.active < T::Currency::minimum_balance() - { - // This account must have called `unbond()` with some value that caused the active - // portion to fall below existential deposit + will have no more unlocking chunks - // left. We can now safely remove all staking-related information. - Self::kill_stash(&stash, num_slashing_spans)?; - // Remove the lock. - T::Currency::remove_lock(STAKING_ID, &stash); - // This is worst case scenario, so we use the full weight and return None - None - } else { - // This was the consequence of a partial unbond. just update the ledger and move on. - Self::update_ledger(&controller, &ledger); + let post_info_weight = + if ledger.unlocking.is_empty() && ledger.active < T::Currency::minimum_balance() { + // This account must have called `unbond()` with some value that caused the active + // portion to fall below existential deposit + will have no more unlocking chunks + // left. We can now safely remove all staking-related information. + Self::kill_stash(&stash, num_slashing_spans)?; + // Remove the lock. + T::Currency::remove_lock(STAKING_ID, &stash); + // This is worst case scenario, so we use the full weight and return None + None + } else { + // This was the consequence of a partial unbond. just update the ledger and move on. + Self::update_ledger(&controller, &ledger); - // This is only an update, so we use less overall weight. - Some(T::WeightInfo::withdraw_unbonded_update(num_slashing_spans)) - }; + // This is only an update, so we use less overall weight. + Some(T::WeightInfo::withdraw_unbonded_update(num_slashing_spans)) + }; // `old_total` should never be less than the new total because // `consolidate_unlocked` strictly subtracts balance. From 184a8cb6667786cb3b7a7fe3a28ba199fdfe803c Mon Sep 17 00:00:00 2001 From: Georges Dib Date: Thu, 21 Oct 2021 03:11:02 +0100 Subject: [PATCH 58/80] Replacing `Vec` by `BoundedVec` --- frame/session/src/lib.rs | 2 +- frame/staking/src/pallet/impls.rs | 121 ++++++++++++++++-------------- 2 files changed, 66 insertions(+), 57 deletions(-) diff --git a/frame/session/src/lib.rs b/frame/session/src/lib.rs index 385e919d0649a..6d4978f7e5915 100644 --- a/frame/session/src/lib.rs +++ b/frame/session/src/lib.rs @@ -730,7 +730,7 @@ impl Pallet { if let Err(index) = disabled.binary_search(&i) { if disabled.try_insert(index, i).is_err() { // This should never fail - log::warn!(target: "runtime::session", "disabling validator index {:?}", i); + log::error!(target: "runtime::session", "disabling validator index {:?}", i); return false; } T::SessionHandler::on_disabled(i); diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index 4e29a62571a2a..83708c8359a8f 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -410,10 +410,10 @@ impl Pallet { /// Returns the new validator set. pub fn trigger_new_era( start_session_index: SessionIndex, - exposures: Vec<( - T::AccountId, - Exposure, T::MaxIndividualExposures>, - )>, + exposures: BoundedVec< + (T::AccountId, Exposure, T::MaxIndividualExposures>), + T::MaxValidatorsCount, + >, ) -> BoundedVec { // Increment or set current era. let new_planned_era = CurrentEra::::mutate(|s| { @@ -489,13 +489,13 @@ impl Pallet { /// /// Store staking information for the new planned era pub fn store_stakers_info( - exposures: Vec<( - T::AccountId, - Exposure, T::MaxIndividualExposures>, - )>, + exposures: BoundedVec< + (T::AccountId, Exposure, T::MaxIndividualExposures>), + T::MaxValidatorsCount, + >, new_planned_era: EraIndex, ) -> BoundedVec { - let elected_stashes = exposures.iter().cloned().map(|(x, _)| x).collect::>(); + let elected_stashes = exposures.clone().map_collect(|(x, _)| x); // Populate stakers, exposures, and the snapshot of validator prefs. let mut total_stake: BalanceOf = Zero::zero(); @@ -525,7 +525,7 @@ impl Pallet { >::insert(&new_planned_era, total_stake); // Collect the pref of all winners. - for stash in &elected_stashes { + for stash in AsRef::>::as_ref(&elected_stashes) { let pref = Self::validators(stash); >::insert(&new_planned_era, stash, pref); } @@ -546,41 +546,53 @@ impl Pallet { /// [`Exposure`]. fn collect_exposures( supports: Supports, - ) -> Vec<(T::AccountId, Exposure, T::MaxIndividualExposures>)> { + ) -> BoundedVec< + (T::AccountId, Exposure, T::MaxIndividualExposures>), + T::MaxValidatorsCount, + > { let total_issuance = T::Currency::total_issuance(); let to_currency = |e: frame_election_provider_support::ExtendedBalance| { T::CurrencyToVote::to_currency(e, total_issuance) }; - supports - .into_iter() - .map(|(validator, support)| { - // Build `struct exposure` from `support`. - let mut others = Vec::with_capacity(support.voters.len()); - let mut own: BalanceOf = Zero::zero(); - let mut total: BalanceOf = Zero::zero(); - support - .voters - .into_iter() - .map(|(nominator, weight)| (nominator, to_currency(weight))) - .for_each(|(nominator, stake)| { - if nominator == validator { - own = own.saturating_add(stake); - } else { - others.push(IndividualExposure { who: nominator, value: stake }); - } - total = total.saturating_add(stake); - }); + let exposures = BoundedVec::<_, T::MaxValidatorsCount>::try_from( + supports + .into_iter() + .map(|(validator, support)| { + // Build `struct exposure` from `support`. + let mut others = Vec::with_capacity(support.voters.len()); + let mut own: BalanceOf = Zero::zero(); + let mut total: BalanceOf = Zero::zero(); + support + .voters + .into_iter() + .map(|(nominator, weight)| (nominator, to_currency(weight))) + .for_each(|(nominator, stake)| { + if nominator == validator { + own = own.saturating_add(stake); + } else { + others.push(IndividualExposure { who: nominator, value: stake }); + } + total = total.saturating_add(stake); + }); + + let others = WeakBoundedVec::<_, T::MaxIndividualExposures>::force_from( + others, + Some("exposure.others"), + ); + + let exposure = Exposure { own, others, total }; + (validator, exposure) + }) + .collect::)>>(), + ); - let others = WeakBoundedVec::<_, T::MaxIndividualExposures>::force_from( - others, - Some("exposure.others"), - ); + // This should never happen + if exposures.is_err() { + log!(error, "Too many validators in frame_staking.collect_exposures") + } - let exposure = Exposure { own, others, total }; - (validator, exposure) - }) - .collect::)>>() + exposures.unwrap_or_default() } /// Remove all associated data of a stash account from the staking system. @@ -1117,20 +1129,18 @@ impl T::MaxValidatorsCount, >, > { - >::new_session(new_index).map(|validators| { + >::new_session(new_index).map(|validators| { let current_era = Self::current_era() // Must be some as a new era has been created. .unwrap_or(0); - validators - .into_iter() - .map(|v| { - let exposure = Self::eras_stakers(current_era, &v); - (v, exposure) - }) - .collect() + validators.map_collect(|v| { + let exposure = Self::eras_stakers(current_era, &v); + (v, exposure) + }) }) } + fn new_session_genesis( new_index: SessionIndex, ) -> Option< @@ -1139,27 +1149,26 @@ impl T::MaxValidatorsCount, >, > { - >::new_session_genesis(new_index).map( + >::new_session_genesis(new_index).map( |validators| { let current_era = Self::current_era() // Must be some as a new era has been created. .unwrap_or(0); - validators - .into_iter() - .map(|v| { - let exposure = Self::eras_stakers(current_era, &v); - (v, exposure) - }) - .collect() + validators.map_collect(|v| { + let exposure = Self::eras_stakers(current_era, &v); + (v, exposure) + }) }, ) } + fn start_session(start_index: SessionIndex) { - >::start_session(start_index) + >::start_session(start_index) } + fn end_session(end_index: SessionIndex) { - >::end_session(end_index) + >::end_session(end_index) } } From 65d95919a2473a1a6b72b6d299a4a23f376eeb7a Mon Sep 17 00:00:00 2001 From: Georges Dib Date: Thu, 21 Oct 2021 03:29:17 +0100 Subject: [PATCH 59/80] Fixing election-provider-support --- .../src/helpers.rs | 8 +- .../election-provider-multi-phase/src/lib.rs | 50 +++++++------ .../src/unsigned.rs | 73 ++++++++++++------- 3 files changed, 79 insertions(+), 52 deletions(-) diff --git a/frame/election-provider-multi-phase/src/helpers.rs b/frame/election-provider-multi-phase/src/helpers.rs index a57e47f5d4a48..c542701298c15 100644 --- a/frame/election-provider-multi-phase/src/helpers.rs +++ b/frame/election-provider-multi-phase/src/helpers.rs @@ -32,10 +32,10 @@ macro_rules! log { }; } -type MaximumVotesPerVoter = = <::DataProvider as ElectionDataProvider< + ::AccountId, + ::BlockNumber, + ::MaxTargets, >>::MaximumVotesPerVoter; /// Generate a btree-map cache of the voters and their indices. diff --git a/frame/election-provider-multi-phase/src/lib.rs b/frame/election-provider-multi-phase/src/lib.rs index 157ab47a1a15b..c5aa1bd7d3be1 100644 --- a/frame/election-provider-multi-phase/src/lib.rs +++ b/frame/election-provider-multi-phase/src/lib.rs @@ -695,7 +695,15 @@ pub mod pallet { >; /// OCW election solution miner algorithm implementation. - type Solver: NposSolver; + type Solver: NposSolver< + Self::MaxTargets, + >::MaximumVotesPerVoter, + AccountId = Self::AccountId, + >; /// Origin that can control this pallet. Note that any action taken by this origin (such) /// as providing an emergency solution is not checked. Thus, it must be a trusted origin. @@ -733,14 +741,14 @@ pub mod pallet { Ok(_) => { Self::on_initialize_open_signed(); T::WeightInfo::on_initialize_open_signed() - }, + } Err(why) => { // Not much we can do about this at this point. log!(warn, "failed to open signed phase due to {:?}", why); T::WeightInfo::on_initialize_nothing() - }, + } } - }, + } Phase::Signed | Phase::Off if remaining <= unsigned_deadline && remaining > Zero::zero() => { @@ -772,11 +780,11 @@ pub mod pallet { Ok(_) => { Self::on_initialize_open_unsigned(enabled, now); T::WeightInfo::on_initialize_open_unsigned() - }, + } Err(why) => { log!(warn, "failed to open unsigned phase due to {:?}", why); T::WeightInfo::on_initialize_nothing() - }, + } } } else { Self::on_initialize_open_unsigned(enabled, now); @@ -802,10 +810,10 @@ pub mod pallet { match lock.try_lock() { Ok(_guard) => { Self::do_synchronized_offchain_worker(now); - }, + } Err(deadline) => { log!(debug, "offchain worker lock not released, deadline is {:?}", deadline); - }, + } }; } @@ -972,8 +980,8 @@ pub mod pallet { // ensure witness data is correct. ensure!( - num_signed_submissions >= - >::decode_len().unwrap_or_default() as u32, + num_signed_submissions + >= >::decode_len().unwrap_or_default() as u32, Error::::SignedInvalidWitness, ); @@ -1088,7 +1096,7 @@ pub mod pallet { if let Call::submit_unsigned { raw_solution, .. } = call { // Discard solution not coming from the local OCW. match source { - TransactionSource::Local | TransactionSource::InBlock => { /* allowed */ }, + TransactionSource::Local | TransactionSource::InBlock => { /* allowed */ } _ => return InvalidTransaction::Call.into(), } @@ -1254,15 +1262,15 @@ impl Pallet { Self::mine_check_save_submit() }); log!(debug, "initial offchain thread output: {:?}", initial_output); - }, + } Phase::Unsigned((true, opened)) if opened < now => { // Try and resubmit the cached solution, and recompute ONLY if it is not // feasible. let resubmit_output = Self::ensure_offchain_repeat_frequency(now) .and_then(|_| Self::restore_or_compute_then_maybe_submit()); log!(debug, "resubmit offchain thread output: {:?}", resubmit_output); - }, - _ => {}, + } + _ => {} } } @@ -1356,7 +1364,7 @@ impl Pallet { // Defensive-only. if targets.len() > target_limit || voters.len() > voter_limit { debug_assert!(false, "Snapshot limit has not been respected."); - return Err(ElectionError::DataProvider("Snapshot too big for submission.")) + return Err(ElectionError::DataProvider("Snapshot too big for submission.")); } Ok((targets, voters, desired_targets)) @@ -1466,7 +1474,7 @@ impl Pallet { // Check that all of the targets are valid based on the snapshot. if assignment.distribution.iter().any(|(d, _)| !targets.contains(d)) { - return Err(FeasibilityError::InvalidVote) + return Err(FeasibilityError::InvalidVote); } Ok(()) }) @@ -1559,12 +1567,12 @@ impl ElectionProvider fo Self::weigh_supports(&supports); Self::rotate_round(); Ok(supports) - }, + } Err(why) => { log!(error, "Entering emergency mode: {:?}", why); >::put(Phase::Emergency); Err(why) - }, + } } } } @@ -2110,9 +2118,9 @@ mod tests { }; let mut active = 1; - while weight_with(active) <= - ::BlockWeights::get().max_block || - active == all_voters + while weight_with(active) + <= ::BlockWeights::get().max_block + || active == all_voters { active += 1; } diff --git a/frame/election-provider-multi-phase/src/unsigned.rs b/frame/election-provider-multi-phase/src/unsigned.rs index 5b34d9220b435..b98e28d1279af 100644 --- a/frame/election-provider-multi-phase/src/unsigned.rs +++ b/frame/election-provider-multi-phase/src/unsigned.rs @@ -18,9 +18,9 @@ //! The unsigned phase, and its miner. use crate::{ - helpers, Call, Config, ElectionCompute, Error, FeasibilityError, Pallet, RawSolution, - ReadySolution, RoundSnapshot, SolutionAccuracyOf, SolutionOf, SolutionOrSnapshotSize, Weight, - WeightInfo, + helpers, Call, Config, ElectionCompute, ElectionDataProvider, Error, FeasibilityError, Pallet, + RawSolution, ReadySolution, RoundSnapshot, SolutionAccuracyOf, SolutionOf, + SolutionOrSnapshotSize, Weight, WeightInfo, }; use codec::Encode; use frame_election_provider_support::{NposSolver, PerThing128}; @@ -63,7 +63,14 @@ pub type Assignment = pub type IndexAssignmentOf = sp_npos_elections::IndexAssignmentOf>; /// Error type of the pallet's [`crate::Config::Solver`]. -pub type SolverErrorOf = <::Solver as NposSolver>::Error; +pub type SolverErrorOf = <::Solver as NposSolver< + ::MaxTargets, + <::DataProvider as ElectionDataProvider< + ::AccountId, + ::BlockNumber, + ::MaxTargets, + >>::MaximumVotesPerVoter, +>>::Error; /// Error type for operations related to the OCW npos solution miner. #[derive(frame_support::DebugNoBound, frame_support::PartialEqNoBound)] pub enum MinerError { @@ -109,15 +116,16 @@ fn save_solution(call: &Call) -> Result<(), MinerError> { let storage = StorageValueRef::persistent(&OFFCHAIN_CACHED_CALL); match storage.mutate::<_, (), _>(|_| Ok(call.clone())) { Ok(_) => Ok(()), - Err(MutateStorageError::ConcurrentModification(_)) => - Err(MinerError::FailedToStoreSolution), + Err(MutateStorageError::ConcurrentModification(_)) => { + Err(MinerError::FailedToStoreSolution) + } Err(MutateStorageError::ValueFunctionFailed(_)) => { // this branch should be unreachable according to the definition of // `StorageValueRef::mutate`: that function should only ever `Err` if the closure we // pass it returns an error. however, for safety in case the definition changes, we do // not optimize the branch away or panic. Err(MinerError::FailedToStoreSolution) - }, + } } } @@ -180,7 +188,7 @@ impl Pallet { let call = Self::mine_checked_call()?; save_solution(&call)?; Ok(call) - }, + } MinerError::Feasibility(_) => { log!(trace, "wiping infeasible solution."); // kill the infeasible solution, hopefully in the next runs (whenever they @@ -188,11 +196,11 @@ impl Pallet { kill_ocw_solution::(); clear_offchain_repeat_frequency(); Err(error) - }, + } _ => { // nothing to do. Return the error as-is. Err(error) - }, + } } })?; @@ -276,7 +284,16 @@ impl Pallet { pub fn mine_solution( ) -> Result<(RawSolution>, SolutionOrSnapshotSize), MinerError> where - S: NposSolver>, + S: NposSolver< + T::MaxTargets, + >::MaximumVotesPerVoter, + AccountId = T::AccountId, + Error = SolverErrorOf, + >, { let RoundSnapshot { voters, targets } = Self::snapshot().ok_or(MinerError::SnapshotUnAvailable)?; @@ -444,7 +461,7 @@ impl Pallet { // not much we can do if assignments are already empty. if high == low { - return Ok(()) + return Ok(()); } while high - low > 1 { @@ -455,8 +472,8 @@ impl Pallet { high = test; } } - let maximum_allowed_voters = if low < assignments.len() && - encoded_size_of(&assignments[..low + 1])? <= max_allowed_length + let maximum_allowed_voters = if low < assignments.len() + && encoded_size_of(&assignments[..low + 1])? <= max_allowed_length { low + 1 } else { @@ -468,8 +485,8 @@ impl Pallet { encoded_size_of(&assignments[..maximum_allowed_voters]).unwrap() <= max_allowed_length ); debug_assert!(if maximum_allowed_voters < assignments.len() { - encoded_size_of(&assignments[..maximum_allowed_voters + 1]).unwrap() > - max_allowed_length + encoded_size_of(&assignments[..maximum_allowed_voters + 1]).unwrap() + > max_allowed_length } else { true }); @@ -499,7 +516,7 @@ impl Pallet { max_weight: Weight, ) -> u32 { if size.voters < 1 { - return size.voters + return size.voters; } let max_voters = size.voters.max(1); @@ -518,7 +535,7 @@ impl Pallet { Some(voters) if voters < max_voters => Ok(voters), _ => Err(()), } - }, + } Ordering::Greater => voters.checked_sub(step).ok_or(()), Ordering::Equal => Ok(voters), } @@ -533,7 +550,7 @@ impl Pallet { // proceed with the binary search Ok(next) if next != voters => { voters = next; - }, + } // we are out of bounds, break out of the loop. Err(()) => break, // we found the right value - early exit the function. @@ -579,16 +596,17 @@ impl Pallet { |maybe_head: Result, _>| { match maybe_head { Ok(Some(head)) if now < head => Err("fork."), - Ok(Some(head)) if now >= head && now <= head + threshold => - Err("recently executed."), + Ok(Some(head)) if now >= head && now <= head + threshold => { + Err("recently executed.") + } Ok(Some(head)) if now > head + threshold => { // we can run again now. Write the new head. Ok(now) - }, + } _ => { // value doesn't exists. Probably this node just booted up. Write, and run Ok(now) - }, + } } }, ); @@ -597,8 +615,9 @@ impl Pallet { // all good Ok(_) => Ok(()), // failed to write. - Err(MutateStorageError::ConcurrentModification(_)) => - Err(MinerError::Lock("failed to write to offchain db (concurrent modification).")), + Err(MutateStorageError::ConcurrentModification(_)) => { + Err(MinerError::Lock("failed to write to offchain db (concurrent modification).")) + } // fork etc. Err(MutateStorageError::ValueFunctionFailed(why)) => Err(MinerError::Lock(why)), } @@ -622,8 +641,8 @@ impl Pallet { // ensure correct number of winners. ensure!( - Self::desired_targets().unwrap_or_default() == - raw_solution.solution.unique_targets().len() as u32, + Self::desired_targets().unwrap_or_default() + == raw_solution.solution.unique_targets().len() as u32, Error::::PreDispatchWrongWinnerCount, ); From 538dcd73c050c1d89760af98f255e06f4374385c Mon Sep 17 00:00:00 2001 From: Georges Dib Date: Thu, 21 Oct 2021 03:36:12 +0100 Subject: [PATCH 60/80] Adding `MaxEncodedLen` to `impl_opaque_keys` --- primitives/runtime/src/traits.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/primitives/runtime/src/traits.rs b/primitives/runtime/src/traits.rs index 6d79d740dc4e1..15e3d7b0644b1 100644 --- a/primitives/runtime/src/traits.rs +++ b/primitives/runtime/src/traits.rs @@ -1197,7 +1197,7 @@ impl<'a, T: codec::Input> codec::Input for AppendZerosInput<'a, T> { into[i] = b; i += 1; } else { - break + break; } } i @@ -1276,7 +1276,7 @@ impl AccountIdConver fn try_from_sub_account(x: &T) -> Option<(Self, S)> { x.using_encoded(|d| { if &d[0..4] != Id::TYPE_ID { - return None + return None; } let mut cursor = &d[4..]; let result = Decode::decode(&mut cursor).ok()?; @@ -1326,6 +1326,7 @@ macro_rules! impl_opaque_keys_inner { Default, Clone, PartialEq, Eq, $crate::codec::Encode, $crate::codec::Decode, + $crate::codec::MaxEncodedLen, $crate::scale_info::TypeInfo, $crate::RuntimeDebug, )] From 6f1bf5ace09fee3fa31e912c3972be44ebbb7dde Mon Sep 17 00:00:00 2001 From: Georges Dib Date: Thu, 21 Oct 2021 08:22:58 +0100 Subject: [PATCH 61/80] Some more bounding conversions Specifying type values --- bin/node/runtime/src/lib.rs | 29 ++++++++++++++++++----------- frame/staking/src/pallet/impls.rs | 27 +++++++++++++++++---------- frame/staking/src/pallet/mod.rs | 4 ++-- 3 files changed, 37 insertions(+), 23 deletions(-) diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index e12a6eb1fca2d..976469ef47bd2 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -289,17 +289,18 @@ impl InstanceFilter for ProxyType { ProxyType::Any => true, ProxyType::NonTransfer => !matches!( c, - Call::Balances(..) | - Call::Assets(..) | Call::Uniques(..) | - Call::Vesting(pallet_vesting::Call::vested_transfer { .. }) | - Call::Indices(pallet_indices::Call::transfer { .. }) + Call::Balances(..) + | Call::Assets(..) | Call::Uniques(..) + | Call::Vesting(pallet_vesting::Call::vested_transfer { .. }) + | Call::Indices(pallet_indices::Call::transfer { .. }) ), ProxyType::Governance => matches!( c, - Call::Democracy(..) | - Call::Council(..) | Call::Society(..) | - Call::TechnicalCommittee(..) | - Call::Elections(..) | Call::Treasury(..) + Call::Democracy(..) + | Call::Council(..) | Call::Society(..) + | Call::TechnicalCommittee(..) + | Call::Elections(..) + | Call::Treasury(..) ), ProxyType::Staking => matches!(c, Call::Staking(..)), } @@ -471,6 +472,8 @@ impl pallet_session::Config for Runtime { type SessionHandler = ::KeyTypeIdProviders; type Keys = SessionKeys; type WeightInfo = pallet_session::weights::SubstrateWeight; + type MaxValidatorsCount = MaxValidatorsCount; + type MaxKeysEncodingSize = MaxKeysEncodingSize; } impl pallet_session::historical::Config for Runtime { @@ -506,12 +509,15 @@ parameter_types! { pub const MaxPriorSlashingSpans: u32 = 1_000; pub const MaxValidatorsCount: u32 = 4_000; pub const MaxUnlockingChunks: u32 = 32; + pub const MaxKeysEncodingSize: u32 = 1_000; } use frame_election_provider_support::onchain; impl onchain::Config for Runtime { type Accuracy = Perbill; type DataProvider = Staking; + type MaxNominations = MaxNominations; + type MaxTargets = MaxValidatorsCount; } impl pallet_staking::Config for Runtime { @@ -624,10 +630,10 @@ impl frame_support::pallet_prelude::Get { let seed = sp_io::offchain::random_seed(); let random = ::decode(&mut TrailingZeroInput::new(&seed)) - .expect("input is padded with zeroes; qed") % - max.saturating_add(1); + .expect("input is padded with zeroes; qed") + % max.saturating_add(1); random as usize - }, + } }; Some((iters, 0)) @@ -665,6 +671,7 @@ impl pallet_election_provider_multi_phase::Config for Runtime { type ForceOrigin = EnsureRootOrHalfCouncil; type BenchmarkingConfig = BenchmarkConfig; type VoterSnapshotPerBlock = VoterSnapshotPerBlock; + type MaxTargets = MaxValidatorsCount; } parameter_types! { diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index 83708c8359a8f..5588cd9b399b4 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -979,7 +979,11 @@ impl ElectionDataProvider, T::MaxVali /// Panics if `targets` size is bigger than T::MaxNominations, or if it cannot convert `weight` /// into a `BalanceOf`. #[cfg(feature = "runtime-benchmarks")] - fn add_voter(voter: T::AccountId, weight: VoteWeight, targets: Vec) { + fn add_voter( + voter: T::AccountId, + weight: VoteWeight, + targets: BoundedVec, + ) { let stake = >::try_from(weight).unwrap_or_else(|_| { panic!("cannot convert a VoteWeight into BalanceOf, benchmark needs reconfiguring.") }); @@ -995,8 +999,6 @@ impl ElectionDataProvider, T::MaxVali }, ); - let targets = BoundedVec::<_, T::MaxNominations>::try_from(targets) - .expect("targets Vec length too large, benchmark needs reconfiguring"); Self::do_add_nominator(&voter, Nominations { targets, submitted_in: 0, suppressed: false }); } @@ -1033,12 +1035,15 @@ impl ElectionDataProvider, T::MaxVali /// # Panic /// - /// Panics if `voters` 3rd element is larger than T::MaxNominations, or if the 2nd element - /// cannot be converted into a `BalanceOf`. + /// Panics if `voters` 2nd element cannot be converted into a `BalanceOf`. #[cfg(feature = "runtime-benchmarks")] fn put_snapshot( - voters: Vec<(T::AccountId, VoteWeight, Vec)>, - targets: Vec, + voters: Vec<( + T::AccountId, + VoteWeight, + BoundedVec, + )>, + targets: BoundedVec, target_stake: Option, ) { targets.into_iter().for_each(|v| { @@ -1077,9 +1082,11 @@ impl ElectionDataProvider, T::MaxVali claimed_rewards: Default::default(), }, ); - let targets = BoundedVec::<_, T::MaxNominations>::try_from(t) - .expect("targets vec too large, benchmark needs reconfiguring."); - Self::do_add_nominator(&v, Nominations { targets, submitted_in: 0, suppressed: false }); + + Self::do_add_nominator( + &v, + Nominations { targets: t, submitted_in: 0, suppressed: false }, + ); }); } } diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index 4fb377d3f3123..629bd8b2a3032 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -44,7 +44,7 @@ mod impls; pub use impls::*; use crate::{ - log, migrations, slashing, weights::WeightInfo, ActiveEraInfo, BalanceOf, EraIndex, EraPayout, + migrations, slashing, weights::WeightInfo, ActiveEraInfo, BalanceOf, EraIndex, EraPayout, EraRewardPoints, Exposure, Forcing, NegativeImbalanceOf, Nominations, PositiveImbalanceOf, Releases, RewardDestination, SessionInterface, StakingLedger, UnappliedSlash, UnlockChunk, ValidatorPrefs, @@ -579,7 +579,7 @@ pub mod pallet { Invulnerables::::put(&invulnerables); for &(ref stash, ref controller, balance, ref status) in &self.stakers { - log!( + crate::log!( trace, "inserting genesis staker: {:?} => {:?} => {:?}", stash, From 21d87fc103bc0daccbece754b80f9c283693195a Mon Sep 17 00:00:00 2001 From: Georges Dib Date: Thu, 21 Oct 2021 16:25:25 +0100 Subject: [PATCH 62/80] Fixing tests --- frame/babe/src/mock.rs | 5 ++ frame/babe/src/tests.rs | 10 +-- .../src/helpers.rs | 2 +- .../election-provider-multi-phase/src/lib.rs | 50 +++++------ .../election-provider-multi-phase/src/mock.rs | 64 ++++++++++---- .../src/unsigned.rs | 12 ++- frame/election-provider-support/src/lib.rs | 16 ++-- .../election-provider-support/src/onchain.rs | 26 ++++-- frame/grandpa/src/mock.rs | 5 ++ frame/grandpa/src/tests.rs | 12 +-- frame/session/src/lib.rs | 2 +- frame/session/src/mock.rs | 28 +++--- frame/staking/src/mock.rs | 11 ++- frame/staking/src/tests.rs | 86 ++++++++++--------- 14 files changed, 206 insertions(+), 123 deletions(-) diff --git a/frame/babe/src/mock.rs b/frame/babe/src/mock.rs index 4602bd68ab460..347547ac4fce8 100644 --- a/frame/babe/src/mock.rs +++ b/frame/babe/src/mock.rs @@ -121,6 +121,8 @@ impl pallet_session::Config for Test { type SessionManager = pallet_session::historical::NoteHistoricalRoot; type SessionHandler = ::KeyTypeIdProviders; type Keys = MockSessionKeys; + type MaxValidatorsCount = MaxValidatorsCount; + type MaxKeysEncodingSize = MaxKeysEncodingSize; type WeightInfo = (); } @@ -195,6 +197,7 @@ parameter_types! { pub const MaxReportersCount: u32 = 1_000; pub const MaxPriorSlashingSpans: u32 = 1_000; pub const MaxValidatorsCount: u32 = 4_000; + pub const MaxKeysEncodingSize: u32 = 1_000; pub const MaxUnlockingChunks: u32 = 32; pub const OffendingValidatorsThreshold: Perbill = Perbill::from_percent(16); } @@ -202,6 +205,8 @@ parameter_types! { impl onchain::Config for Test { type Accuracy = Perbill; type DataProvider = Staking; + type MaxNominations = MaxNominations; + type MaxTargets = MaxValidatorsCount; } impl pallet_staking::Config for Test { diff --git a/frame/babe/src/tests.rs b/frame/babe/src/tests.rs index bb25d1792935c..33e9a7e4db923 100644 --- a/frame/babe/src/tests.rs +++ b/frame/babe/src/tests.rs @@ -219,8 +219,8 @@ fn can_estimate_current_epoch_progress() { ); } else { assert!( - Babe::estimate_current_session_progress(i).0.unwrap() < - Permill::from_percent(100) + Babe::estimate_current_session_progress(i).0.unwrap() + < Permill::from_percent(100) ); } } @@ -409,7 +409,7 @@ fn report_equivocation_current_session_works() { let validators = Session::validators(); // make sure that all authorities have the same balance - for validator in &validators { + for validator in &validators.to_vec() { assert_eq!(Balances::total_balance(validator), 10_000_000); assert_eq!(Staking::slashable_balance_of(validator), 10_000); @@ -460,9 +460,9 @@ fn report_equivocation_current_session_works() { ); // check that the balances of all other validators are left intact. - for validator in &validators { + for validator in &validators.to_vec() { if *validator == offending_validator_id { - continue + continue; } assert_eq!(Balances::total_balance(validator), 10_000_000); diff --git a/frame/election-provider-multi-phase/src/helpers.rs b/frame/election-provider-multi-phase/src/helpers.rs index c542701298c15..f9ba158d1b2f8 100644 --- a/frame/election-provider-multi-phase/src/helpers.rs +++ b/frame/election-provider-multi-phase/src/helpers.rs @@ -78,7 +78,7 @@ pub fn voter_index_fn( /// Same as [`voter_index_fn`] but the returned function owns all its necessary data; nothing is /// borrowed. pub fn voter_index_fn_owned( - cache: BTreeMap, + cache: BoundedBTreeMap>, ) -> impl Fn(&T::AccountId) -> Option> { move |who| { cache diff --git a/frame/election-provider-multi-phase/src/lib.rs b/frame/election-provider-multi-phase/src/lib.rs index c5aa1bd7d3be1..aeebf188af5c7 100644 --- a/frame/election-provider-multi-phase/src/lib.rs +++ b/frame/election-provider-multi-phase/src/lib.rs @@ -1294,16 +1294,7 @@ impl Pallet { /// Extracted for easier weight calculation. fn create_snapshot_internal( targets: BoundedVec, - voters: Vec< - crate::unsigned::Voter< - T, - >::MaximumVotesPerVoter, - >, - >, + voters: Vec>, desired_targets: u32, ) { let metadata = @@ -1334,20 +1325,7 @@ impl Pallet { /// /// Extracted for easier weight calculation. fn create_snapshot_external() -> Result< - ( - BoundedVec, - Vec< - crate::unsigned::Voter< - T, - >::MaximumVotesPerVoter, - >, - >, - u32, - ), + (BoundedVec, Vec>, u32), ElectionError, > { let target_limit = >::max_value().saturated_into::(); @@ -2026,13 +2004,35 @@ mod tests { roll_to(25); assert_eq!(MultiPhase::current_phase(), Phase::Off); - // On-chain backup works though. + // On-chain backup works though as long as size is less than MaxValidatorsCount. roll_to(29); let supports = MultiPhase::elect().unwrap(); assert!(supports.len() > 0); }); } + #[test] + fn snapshot_too_big_failure_onchain_fallback_fail() { + // the `MockStaking` is designed such that if it has too many targets, it simply fails. + ExtBuilder::default().build_and_execute(|| { + Targets::set((0..(crate::mock::MaxValidatorsCount::get() as u64 + 1)).collect::>()); + + // Signed phase failed to open. + roll_to(15); + assert_eq!(MultiPhase::current_phase(), Phase::Off); + + // Unsigned phase failed to open. + roll_to(25); + assert_eq!(MultiPhase::current_phase(), Phase::Off); + + // On-chain backup will not work when size is more than MaxValidatorsCount. + roll_to(29); + let err = MultiPhase::elect().unwrap_err(); + assert_eq!(err, ElectionError::Fallback("OnChainSequentialPhragmen failed")); + assert_eq!(MultiPhase::current_phase(), Phase::Emergency); + }); + } + #[test] fn snapshot_too_big_failure_no_fallback() { // and if the backup mode is nothing, we go into the emergency mode.. diff --git a/frame/election-provider-multi-phase/src/mock.rs b/frame/election-provider-multi-phase/src/mock.rs index d18fa4a9a52bb..13ce988dc3713 100644 --- a/frame/election-provider-multi-phase/src/mock.rs +++ b/frame/election-provider-multi-phase/src/mock.rs @@ -127,10 +127,16 @@ pub fn trim_helpers() -> TrimHelpers { let desired_targets = MultiPhase::desired_targets().unwrap(); + let voters_vec = voters + .clone() + .into_iter() + .map(|(who, voter_stake, votes)| (who, voter_stake, votes.to_vec())) + .collect(); + let ElectionResult { mut assignments, .. } = seq_phragmen::<_, SolutionAccuracyOf>( desired_targets as usize, - targets.clone(), - voters.clone(), + targets.to_vec(), + voters_vec, None, ) .unwrap(); @@ -159,18 +165,24 @@ pub fn raw_solution() -> RawSolution> { let RoundSnapshot { voters, targets } = MultiPhase::snapshot().unwrap(); let desired_targets = MultiPhase::desired_targets().unwrap(); + let voters_vec = voters + .clone() + .into_iter() + .map(|(who, voter_stake, votes)| (who, voter_stake, votes.to_vec())) + .collect::>(); + let ElectionResult { winners: _, assignments } = seq_phragmen::<_, SolutionAccuracyOf>( desired_targets as usize, - targets.clone(), - voters.clone(), + targets.to_vec(), + voters_vec.clone(), None, ) .unwrap(); // closures let cache = helpers::generate_voter_cache::(&voters); - let voter_index = helpers::voter_index_fn_linear::(&voters); + let voter_index = helpers::voter_index_fn_linear::(&voters_vec); let target_index = helpers::target_index_fn_linear::(&targets); let stake_of = helpers::stake_of_fn::(&voters, &cache); @@ -223,6 +235,8 @@ impl frame_system::Config for Runtime { const NORMAL_DISPATCH_RATIO: Perbill = Perbill::from_percent(75); parameter_types! { pub const ExistentialDeposit: u64 = 1; + pub const MaxValidatorsCount: u32 = 100_000; + pub const MaxNominations: u32 = 10; pub BlockWeights: frame_system::limits::BlockWeights = frame_system::limits::BlockWeights ::with_sensible_defaults(2 * frame_support::weights::constants::WEIGHT_PER_SECOND, NORMAL_DISPATCH_RATIO); } @@ -271,21 +285,23 @@ parameter_types! { pub static VoterSnapshotPerBlock: VoterIndex = u32::max_value(); pub static EpochLength: u64 = 30; - pub static OnChianFallback: bool = true; + pub static OnChainFallback: bool = true; } impl onchain::Config for Runtime { type Accuracy = sp_runtime::Perbill; type DataProvider = StakingMock; + type MaxNominations = MaxNominations; + type MaxTargets = MaxValidatorsCount; } pub struct MockFallback; -impl ElectionProvider for MockFallback { +impl ElectionProvider for MockFallback { type Error = &'static str; type DataProvider = StakingMock; fn elect() -> Result, Self::Error> { - if OnChianFallback::get() { + if OnChainFallback::get() { onchain::OnChainSequentialPhragmen::::elect() .map_err(|_| "OnChainSequentialPhragmen failed") } else { @@ -404,6 +420,7 @@ impl crate::Config for Runtime { type Solution = TestNposSolution; type VoterSnapshotPerBlock = VoterSnapshotPerBlock; type Solver = SequentialPhragmen, Balancing>; + type MaxTargets = MaxValidatorsCount; } impl frame_system::offchain::SendTransactionTypes for Runtime @@ -420,13 +437,16 @@ pub type Extrinsic = sp_runtime::testing::TestXt; pub struct ExtBuilder {} pub struct StakingMock; -impl ElectionDataProvider for StakingMock { +impl ElectionDataProvider for StakingMock { type MaximumVotesPerVoter = ConstU32<{ ::LIMIT as u32 }>; - fn targets(maybe_max_len: Option) -> data_provider::Result> { - let targets = Targets::get(); + fn targets( + maybe_max_len: Option, + ) -> data_provider::Result> { + let targets = BoundedVec::<_, MaxValidatorsCount>::try_from(Targets::get()) + .map_err(|_| "Targets too big")?; if maybe_max_len.map_or(false, |max_len| targets.len() > max_len) { - return Err("Targets too big") + return Err("Targets too big"); } Ok(targets) @@ -434,13 +454,27 @@ impl ElectionDataProvider for StakingMock { fn voters( maybe_max_len: Option, - ) -> data_provider::Result)>> { + ) -> data_provider::Result< + Vec<(AccountId, VoteWeight, BoundedVec)>, + > { let mut voters = Voters::get(); if let Some(max_len) = maybe_max_len { voters.truncate(max_len) } - Ok(voters) + let voters_bounded = voters + .into_iter() + .map(|(who, voter_stake, votes)| { + ( + who, + voter_stake, + BoundedVec::<_, Self::MaximumVotesPerVoter>::try_from(votes).expect( + "Too many votes per voter, a test configuration adjustment may be needed", + ), + ) + }) + .collect(); + Ok(voters_bounded) } fn desired_targets() -> data_provider::Result { @@ -503,7 +537,7 @@ impl ExtBuilder { self } pub fn onchain_fallback(self, onchain: bool) -> Self { - ::set(onchain); + ::set(onchain); self } pub fn miner_weight(self, weight: Weight) -> Self { diff --git a/frame/election-provider-multi-phase/src/unsigned.rs b/frame/election-provider-multi-phase/src/unsigned.rs index b98e28d1279af..00eb1c666b89c 100644 --- a/frame/election-provider-multi-phase/src/unsigned.rs +++ b/frame/election-provider-multi-phase/src/unsigned.rs @@ -47,11 +47,17 @@ pub(crate) const OFFCHAIN_CACHED_CALL: &[u8] = b"parity/multi-phase-unsigned-ele /// A voter's fundamental data: their ID, their stake, and the list of candidates for whom they /// voted. -/// `Limit` bounds the vec size -pub type Voter = ( +pub type Voter = ( ::AccountId, sp_npos_elections::VoteWeight, - BoundedVec<::AccountId, Limit>, + BoundedVec< + ::AccountId, + <::DataProvider as ElectionDataProvider< + ::AccountId, + ::BlockNumber, + ::MaxTargets, + >>::MaximumVotesPerVoter, + >, ); /// The relative distribution of a voter's stake among the winning targets. diff --git a/frame/election-provider-support/src/lib.rs b/frame/election-provider-support/src/lib.rs index 29d556289816e..a5448ce6d9819 100644 --- a/frame/election-provider-support/src/lib.rs +++ b/frame/election-provider-support/src/lib.rs @@ -84,32 +84,36 @@ //! type AccountId = u64; //! type Balance = u64; //! type BlockNumber = u32; +//! type MaxTargets = frame_support::pallet_prelude::ConstU32<10>; //! //! mod data_provider_mod { //! use super::*; +//! use frame_support::BoundedVec; +//! use sp_std::convert::TryFrom; //! //! pub trait Config: Sized { //! type ElectionProvider: ElectionProvider< //! AccountId, //! BlockNumber, +//! MaxTargets, //! DataProvider = Module, //! >; //! } //! //! pub struct Module(std::marker::PhantomData); //! -//! impl ElectionDataProvider for Module { +//! impl ElectionDataProvider for Module { //! type MaximumVotesPerVoter = frame_support::pallet_prelude::ConstU32<1>; //! fn desired_targets() -> data_provider::Result { //! Ok(1) //! } //! fn voters(maybe_max_len: Option) -//! -> data_provider::Result)>> +//! -> data_provider::Result)>> //! { //! Ok(Default::default()) //! } -//! fn targets(maybe_max_len: Option) -> data_provider::Result> { -//! Ok(vec![10, 20, 30]) +//! fn targets(maybe_max_len: Option) -> data_provider::Result> { +//! Ok(BoundedVec::try_from(vec![10, 20, 30]).expect("MaxTargets >=3")) //! } //! fn next_election_prediction(now: BlockNumber) -> BlockNumber { //! 0 @@ -124,10 +128,10 @@ //! pub struct GenericElectionProvider(std::marker::PhantomData); //! //! pub trait Config { -//! type DataProvider: ElectionDataProvider; +//! type DataProvider: ElectionDataProvider; //! } //! -//! impl ElectionProvider for GenericElectionProvider { +//! impl ElectionProvider for GenericElectionProvider { //! type Error = &'static str; //! type DataProvider = T::DataProvider; //! diff --git a/frame/election-provider-support/src/onchain.rs b/frame/election-provider-support/src/onchain.rs index d27c3febacca9..5cc8c5f53abed 100644 --- a/frame/election-provider-support/src/onchain.rs +++ b/frame/election-provider-support/src/onchain.rs @@ -123,6 +123,8 @@ mod tests { type AccountId = u64; type BlockNumber = u64; + type MaxTargets = frame_support::pallet_prelude::ConstU32<10>; + type MaxNominations = frame_support::pallet_prelude::ConstU32<2>; pub type Header = sp_runtime::generic::Header; pub type UncheckedExtrinsic = sp_runtime::generic::UncheckedExtrinsic; @@ -167,25 +169,35 @@ mod tests { impl Config for Runtime { type Accuracy = Perbill; type DataProvider = mock_data_provider::DataProvider; + type MaxNominations = MaxNominations; + type MaxTargets = MaxTargets; } type OnChainPhragmen = OnChainSequentialPhragmen; mod mock_data_provider { use super::*; - use crate::data_provider; + use crate::{data_provider, BoundedVec}; + use std::convert::TryFrom; pub struct DataProvider; - impl ElectionDataProvider for DataProvider { - type MaximumVotesPerVoter = frame_support::pallet_prelude::ConstU32<2>; + impl ElectionDataProvider for DataProvider { + type MaximumVotesPerVoter = MaxNominations; fn voters( _: Option, - ) -> data_provider::Result)>> { - Ok(vec![(1, 10, vec![10, 20]), (2, 20, vec![30, 20]), (3, 30, vec![10, 30])]) + ) -> data_provider::Result< + Vec<(AccountId, VoteWeight, BoundedVec)>, + > { + let vec_1 = BoundedVec::try_from(vec![10, 20]).expect("MaximumVotesPerVoter >= 2"); + let vec_2 = BoundedVec::try_from(vec![30, 20]).expect("MaximumVotesPerVoter >= 2"); + let vec_3 = BoundedVec::try_from(vec![10, 30]).expect("MaximumVotesPerVoter >= 2"); + Ok(vec![(1, 10, vec_1), (2, 20, vec_2), (3, 30, vec_3)]) } - fn targets(_: Option) -> data_provider::Result> { - Ok(vec![10, 20, 30]) + fn targets( + _: Option, + ) -> data_provider::Result> { + Ok(BoundedVec::try_from(vec![10, 20, 30]).expect("MaxTargets >= 3")) } fn desired_targets() -> data_provider::Result { diff --git a/frame/grandpa/src/mock.rs b/frame/grandpa/src/mock.rs index 7f7f0b48a506c..c5885945837a1 100644 --- a/frame/grandpa/src/mock.rs +++ b/frame/grandpa/src/mock.rs @@ -123,6 +123,8 @@ impl pallet_session::Config for Test { type SessionManager = pallet_session::historical::NoteHistoricalRoot; type SessionHandler = ::KeyTypeIdProviders; type Keys = TestSessionKeys; + type MaxValidatorsCount = MaxValidatorsCount; + type MaxKeysEncodingSize = MaxKeysEncodingSize; type WeightInfo = (); } @@ -197,6 +199,7 @@ parameter_types! { pub const MaxReportersCount: u32 = 1_000; pub const MaxPriorSlashingSpans: u32 = 1_000; pub const MaxValidatorsCount: u32 = 4_000; + pub const MaxKeysEncodingSize: u32 = 1_000; pub const MaxUnlockingChunks: u32 = 32; pub const OffendingValidatorsThreshold: Perbill = Perbill::from_percent(17); } @@ -204,6 +207,8 @@ parameter_types! { impl onchain::Config for Test { type Accuracy = Perbill; type DataProvider = Staking; + type MaxNominations = MaxNominations; + type MaxTargets = MaxValidatorsCount; } impl pallet_staking::Config for Test { diff --git a/frame/grandpa/src/tests.rs b/frame/grandpa/src/tests.rs index 88eadfd504f13..126cb4694717e 100644 --- a/frame/grandpa/src/tests.rs +++ b/frame/grandpa/src/tests.rs @@ -323,7 +323,7 @@ fn report_equivocation_current_set_works() { let validators = Session::validators(); // make sure that all validators have the same balance - for validator in &validators { + for validator in &validators.to_vec() { assert_eq!(Balances::total_balance(validator), 10_000_000); assert_eq!(Staking::slashable_balance_of(validator), 10_000); @@ -371,9 +371,9 @@ fn report_equivocation_current_set_works() { ); // check that the balances of all other validators are left intact. - for validator in &validators { + for validator in &validators.to_vec() { if *validator == equivocation_validator_id { - continue + continue; } assert_eq!(Balances::total_balance(validator), 10_000_000); @@ -407,7 +407,7 @@ fn report_equivocation_old_set_works() { start_era(2); // make sure that all authorities have the same balance - for validator in &validators { + for validator in &validators.to_vec() { assert_eq!(Balances::total_balance(validator), 10_000_000); assert_eq!(Staking::slashable_balance_of(validator), 10_000); @@ -450,9 +450,9 @@ fn report_equivocation_old_set_works() { ); // check that the balances of all other validators are left intact. - for validator in &validators { + for validator in &validators.to_vec() { if *validator == equivocation_validator_id { - continue + continue; } assert_eq!(Balances::total_balance(validator), 10_000_000); diff --git a/frame/session/src/lib.rs b/frame/session/src/lib.rs index 6d4978f7e5915..f256ff024dd8b 100644 --- a/frame/session/src/lib.rs +++ b/frame/session/src/lib.rs @@ -95,7 +95,7 @@ //! use pallet_session as session; //! //! fn validators() -> Vec<::ValidatorId> { -//! >::validators() +//! >::validators().to_vec() //! } //! # fn main(){} //! ``` diff --git a/frame/session/src/mock.rs b/frame/session/src/mock.rs index 277dec610659b..84c43a41ceafd 100644 --- a/frame/session/src/mock.rs +++ b/frame/session/src/mock.rs @@ -100,8 +100,10 @@ frame_support::construct_runtime!( ); thread_local! { - pub static VALIDATORS: RefCell> = RefCell::new(vec![1, 2, 3]); - pub static NEXT_VALIDATORS: RefCell> = RefCell::new(vec![1, 2, 3]); + pub static VALIDATORS: RefCell> = + RefCell::new(BoundedVec::try_from(vec![1, 2, 3]).expect("MaxValidatorsCount > 3")); + pub static NEXT_VALIDATORS: RefCell> = + RefCell::new(BoundedVec::try_from(vec![1, 2, 3]).expect("MaxValidatorsCount > 3")); pub static AUTHORITIES: RefCell> = RefCell::new(vec![UintAuthorityId(1), UintAuthorityId(2), UintAuthorityId(3)]); pub static FORCE_SESSION_END: RefCell = RefCell::new(false); @@ -117,8 +119,8 @@ pub struct TestShouldEndSession; impl ShouldEndSession for TestShouldEndSession { fn should_end_session(now: u64) -> bool { let l = SESSION_LENGTH.with(|l| *l.borrow()); - now % l == 0 || - FORCE_SESSION_END.with(|l| { + now % l == 0 + || FORCE_SESSION_END.with(|l| { let r = *l.borrow(); *l.borrow_mut() = false; r @@ -152,10 +154,10 @@ impl SessionHandler for TestSessionHandler { } pub struct TestSessionManager; -impl SessionManager for TestSessionManager { +impl SessionManager for TestSessionManager { fn end_session(_: SessionIndex) {} fn start_session(_: SessionIndex) {} - fn new_session(_: SessionIndex) -> Option> { + fn new_session(_: SessionIndex) -> Option> { if !TEST_SESSION_CHANGED.with(|l| *l.borrow()) { VALIDATORS.with(|v| { let mut v = v.borrow_mut(); @@ -173,12 +175,12 @@ impl SessionManager for TestSessionManager { } #[cfg(feature = "historical")] -impl crate::historical::SessionManager for TestSessionManager { +impl crate::historical::SessionManager for TestSessionManager { fn end_session(_: SessionIndex) {} fn start_session(_: SessionIndex) {} - fn new_session(new_index: SessionIndex) -> Option> { - >::new_session(new_index) - .map(|vals| vals.into_iter().map(|val| (val, val)).collect()) + fn new_session(new_index: SessionIndex) -> Option> { + >::new_session(new_index) + .map(|vals| vals.map_collect(|val| (val, val))) } } @@ -199,6 +201,8 @@ pub fn session_changed() -> bool { } pub fn set_next_validators(next: Vec) { + let next = BoundedVec::<_, MaxValidatorsCount>::try_from(next) + .expect("frame_session.set_next_validators: some test parameters need changing"); NEXT_VALIDATORS.with(|v| *v.borrow_mut() = next); } @@ -231,6 +235,8 @@ pub fn new_test_ext() -> sp_io::TestExternalities { parameter_types! { pub const MinimumPeriod: u64 = 5; pub const BlockHashCount: u64 = 250; + pub const MaxValidatorsCount: u32 = 1_000; + pub const MaxKeysEncodingSize: u32 = 1_000; pub BlockWeights: frame_system::limits::BlockWeights = frame_system::limits::BlockWeights::simple_max(1024); } @@ -279,6 +285,8 @@ impl Config for Test { type ValidatorIdOf = ConvertInto; type Keys = MockSessionKeys; type Event = Event; + type MaxValidatorsCount = MaxValidatorsCount; + type MaxKeysEncodingSize = MaxKeysEncodingSize; type NextSessionRotation = (); type WeightInfo = (); } diff --git a/frame/staking/src/mock.rs b/frame/staking/src/mock.rs index 3eb99bbdb678d..4d25bc94a6e53 100644 --- a/frame/staking/src/mock.rs +++ b/frame/staking/src/mock.rs @@ -179,6 +179,8 @@ impl pallet_session::Config for Test { type ValidatorId = AccountId; type ValidatorIdOf = crate::StashOf; type NextSessionRotation = pallet_session::PeriodicSessions; + type MaxValidatorsCount = MaxValidatorsCount; + type MaxKeysEncodingSize = MaxKeysEncodingSize; type WeightInfo = (); } @@ -246,6 +248,7 @@ parameter_types! { pub const MaxReportersCount: u32 = 1_000; pub const MaxPriorSlashingSpans: u32 = 1_000; pub const MaxValidatorsCount: u32 = 100; + pub const MaxKeysEncodingSize: u32 = 1_000; pub const MaxUnlockingChunks: u32 = 32; } @@ -259,6 +262,8 @@ impl pallet_bags_list::Config for Test { impl onchain::Config for Test { type Accuracy = Perbill; type DataProvider = Staking; + type MaxNominations = MaxNominations; + type MaxTargets = MaxValidatorsCount; } impl crate::pallet::pallet::Config for Test { @@ -603,7 +608,7 @@ fn check_nominators() { e.others.iter().filter(|e| e.who == nominator).collect::>(); let len = individual.len(); match len { - 0 => { /* not supporting this validator at all. */ }, + 0 => { /* not supporting this validator at all. */ } 1 => sum += individual[0].value, _ => panic!("nominator cannot back a validator more than once."), }; @@ -787,9 +792,9 @@ pub(crate) fn on_offence_in_era( for &(bonded_era, start_session) in bonded_eras.iter() { if bonded_era == era { let _ = Staking::on_offence(offenders, slash_fraction, start_session); - return + return; } else if bonded_era > era { - break + break; } } diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index d370832faf240..8c9eda62c918e 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -282,9 +282,9 @@ fn rewards_should_work() { assert_eq_error_rate!(Balances::total_balance(&21), init_balance_21, 2); assert_eq_error_rate!( Balances::total_balance(&100), - init_balance_100 + - part_for_100_from_10 * total_payout_0 * 2 / 3 + - part_for_100_from_20 * total_payout_0 * 1 / 3, + init_balance_100 + + part_for_100_from_10 * total_payout_0 * 2 / 3 + + part_for_100_from_20 * total_payout_0 * 1 / 3, 2 ); assert_eq_error_rate!(Balances::total_balance(&101), init_balance_101, 2); @@ -320,9 +320,9 @@ fn rewards_should_work() { assert_eq_error_rate!(Balances::total_balance(&21), init_balance_21, 2); assert_eq_error_rate!( Balances::total_balance(&100), - init_balance_100 + - part_for_100_from_10 * (total_payout_0 * 2 / 3 + total_payout_1) + - part_for_100_from_20 * total_payout_0 * 1 / 3, + init_balance_100 + + part_for_100_from_10 * (total_payout_0 * 2 / 3 + total_payout_1) + + part_for_100_from_20 * total_payout_0 * 1 / 3, 2 ); assert_eq_error_rate!(Balances::total_balance(&101), init_balance_101, 2); @@ -3308,48 +3308,48 @@ fn six_session_delay() { let init_active_era = active_era(); // pallet-session is delaying session by one, thus the next session to plan is +2. - assert_eq!(>::new_session(init_session + 2), None); + assert_eq!(>::new_session(init_session + 2), None); assert_eq!( - >::new_session(init_session + 3), + >::new_session(init_session + 3), Some(val_set.clone()) ); - assert_eq!(>::new_session(init_session + 4), None); - assert_eq!(>::new_session(init_session + 5), None); + assert_eq!(>::new_session(init_session + 4), None); + assert_eq!(>::new_session(init_session + 5), None); assert_eq!( - >::new_session(init_session + 6), + >::new_session(init_session + 6), Some(val_set.clone()) ); - >::end_session(init_session); - >::start_session(init_session + 1); + >::end_session(init_session); + >::start_session(init_session + 1); assert_eq!(active_era(), init_active_era); - >::end_session(init_session + 1); - >::start_session(init_session + 2); + >::end_session(init_session + 1); + >::start_session(init_session + 2); assert_eq!(active_era(), init_active_era); // Reward current era Staking::reward_by_ids(vec![(11, 1)]); // New active era is triggered here. - >::end_session(init_session + 2); - >::start_session(init_session + 3); + >::end_session(init_session + 2); + >::start_session(init_session + 3); assert_eq!(active_era(), init_active_era + 1); - >::end_session(init_session + 3); - >::start_session(init_session + 4); + >::end_session(init_session + 3); + >::start_session(init_session + 4); assert_eq!(active_era(), init_active_era + 1); - >::end_session(init_session + 4); - >::start_session(init_session + 5); + >::end_session(init_session + 4); + >::start_session(init_session + 5); assert_eq!(active_era(), init_active_era + 1); // Reward current era Staking::reward_by_ids(vec![(21, 2)]); // New active era is triggered here. - >::end_session(init_session + 5); - >::start_session(init_session + 6); + >::end_session(init_session + 5); + >::start_session(init_session + 6); assert_eq!(active_era(), init_active_era + 2); // That reward are correct @@ -4093,8 +4093,8 @@ mod election_data_provider { #[test] fn targets_2sec_block() { let mut validators = 1000; - while ::WeightInfo::get_npos_targets(validators) < - 2 * frame_support::weights::constants::WEIGHT_PER_SECOND + while ::WeightInfo::get_npos_targets(validators) + < 2 * frame_support::weights::constants::WEIGHT_PER_SECOND { validators += 1; } @@ -4111,8 +4111,8 @@ mod election_data_provider { let slashing_spans = validators; let mut nominators = 1000; - while ::WeightInfo::get_npos_voters(validators, nominators, slashing_spans) < - 2 * frame_support::weights::constants::WEIGHT_PER_SECOND + while ::WeightInfo::get_npos_voters(validators, nominators, slashing_spans) + < 2 * frame_support::weights::constants::WEIGHT_PER_SECOND { nominators += 1; } @@ -4139,12 +4139,16 @@ mod election_data_provider { ExtBuilder::default().build_and_execute(|| { assert_eq!(Staking::nominators(101).unwrap().targets, vec![11, 21]); assert_eq!( - >::voters(None) - .unwrap() - .iter() - .find(|x| x.0 == 101) - .unwrap() - .2, + >::voters(None) + .unwrap() + .iter() + .find(|x| x.0 == 101) + .unwrap() + .2, vec![11, 21] ); @@ -4154,7 +4158,7 @@ mod election_data_provider { // 11 is gone. start_active_era(2); assert_eq!( - >::voters(None) + >::voters(None) .unwrap() .iter() .find(|x| x.0 == 101) @@ -4166,7 +4170,7 @@ mod election_data_provider { // resubmit and it is back assert_ok!(Staking::nominate(Origin::signed(100), vec![11, 21])); assert_eq!( - >::voters(None) + >::voters(None) .unwrap() .iter() .find(|x| x.0 == 101) @@ -4184,8 +4188,8 @@ mod election_data_provider { .build_and_execute(|| { // sum of all nominators who'd be voters (1), plus the self-votes (4). assert_eq!( - ::SortedListProvider::count() + - >::iter().count() as u32, + ::SortedListProvider::count() + + >::iter().count() as u32, 5 ); @@ -4224,8 +4228,8 @@ mod election_data_provider { // and total voters assert_eq!( - ::SortedListProvider::count() + - >::iter().count() as u32, + ::SortedListProvider::count() + + >::iter().count() as u32, 7 ); @@ -4269,8 +4273,8 @@ mod election_data_provider { // and total voters assert_eq!( - ::SortedListProvider::count() + - >::iter().count() as u32, + ::SortedListProvider::count() + + >::iter().count() as u32, 6 ); From 3a67669fb16341a55eabed6660c7159b0456b3a6 Mon Sep 17 00:00:00 2001 From: Georges Dib Date: Fri, 22 Oct 2021 04:02:23 +0100 Subject: [PATCH 63/80] Fixing more tests --- frame/im-online/src/mock.rs | 29 ++++++++---------- frame/im-online/src/tests.rs | 59 +++++++++++++++++++++++++----------- 2 files changed, 54 insertions(+), 34 deletions(-) diff --git a/frame/im-online/src/mock.rs b/frame/im-online/src/mock.rs index 1e4d4b43d5789..0704e33277ef8 100644 --- a/frame/im-online/src/mock.rs +++ b/frame/im-online/src/mock.rs @@ -21,7 +21,7 @@ use std::cell::RefCell; -use frame_support::{parameter_types, weights::Weight}; +use frame_support::{parameter_types, weights::Weight, BoundedVec}; use pallet_session::historical as pallet_session_historical; use sp_core::H256; use sp_runtime::{ @@ -35,7 +35,7 @@ use sp_staking::{ }; use crate as imonline; -use crate::Config; +use crate::{Config, TryFrom}; type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; type Block = frame_system::mocking::MockBlock; @@ -54,29 +54,23 @@ frame_support::construct_runtime!( ); thread_local! { - pub static VALIDATORS: RefCell>> = RefCell::new(Some(vec![ - 1, - 2, - 3, - ])); + pub static VALIDATORS: RefCell>> = + RefCell::new(Some(BoundedVec::try_from(vec![1, 2, 3]).expect("MaxKeys > 3"))); } pub struct TestSessionManager; -impl pallet_session::SessionManager for TestSessionManager { - fn new_session(_new_index: SessionIndex) -> Option> { +impl pallet_session::SessionManager for TestSessionManager { + fn new_session(_new_index: SessionIndex) -> Option> { VALIDATORS.with(|l| l.borrow_mut().take()) } fn end_session(_: SessionIndex) {} fn start_session(_: SessionIndex) {} } -impl pallet_session::historical::SessionManager for TestSessionManager { - fn new_session(_new_index: SessionIndex) -> Option> { - VALIDATORS.with(|l| { - l.borrow_mut() - .take() - .map(|validators| validators.iter().map(|v| (*v, *v)).collect()) - }) +impl pallet_session::historical::SessionManager for TestSessionManager { + fn new_session(_new_index: SessionIndex) -> Option> { + VALIDATORS + .with(|l| l.borrow_mut().take().map(|validators| validators.map_collect(|v| (v, v)))) } fn end_session(_: SessionIndex) {} fn start_session(_: SessionIndex) {} @@ -156,6 +150,8 @@ impl pallet_session::Config for Runtime { type Keys = UintAuthorityId; type Event = Event; type NextSessionRotation = pallet_session::PeriodicSessions; + type MaxValidatorsCount = MaxKeys; + type MaxKeysEncodingSize = MaxKeysEncodingSize; type WeightInfo = (); } @@ -213,6 +209,7 @@ impl frame_support::traits::EstimateNextSessionRotation for TestNextSession parameter_types! { pub const UnsignedPriority: u64 = 1 << 20; pub const MaxKeys: u32 = 10_000; + pub const MaxKeysEncodingSize: u32 = 1_000; pub const MaxPeerInHeartbeats: u32 = 10_000; pub const MaxPeerDataEncodingSize: u32 = 1_000; } diff --git a/frame/im-online/src/tests.rs b/frame/im-online/src/tests.rs index bb2c4c7cae548..1ae569bf8065f 100644 --- a/frame/im-online/src/tests.rs +++ b/frame/im-online/src/tests.rs @@ -21,7 +21,7 @@ use super::*; use crate::mock::*; -use frame_support::{assert_noop, dispatch}; +use frame_support::{assert_noop, dispatch, BoundedVec}; use sp_core::{ offchain::{ testing::{TestOffchainExt, TestTransactionPoolExt}, @@ -65,7 +65,7 @@ fn should_report_offline_validators() { // buffer new validators advance_session(); // enact the change and buffer another one - let validators = vec![1, 2, 3, 4, 5, 6]; + let validators = BoundedVec::try_from(vec![1, 2, 3, 4, 5, 6]).expect("MaxKeys >= 6"); VALIDATORS.with(|l| *l.borrow_mut() = Some(validators.clone())); advance_session(); @@ -89,7 +89,8 @@ fn should_report_offline_validators() { // should not report when heartbeat is sent for (idx, v) in validators.into_iter().take(4).enumerate() { - let _ = heartbeat(block, 3, idx as u32, v.into(), Session::validators()).unwrap(); + let _ = + heartbeat(block, 3, idx as u32, v.into(), Session::validators().to_vec()).unwrap(); } advance_session(); @@ -135,8 +136,9 @@ fn heartbeat( signature: signature.clone(), }) .map_err(|e| match e { - TransactionValidityError::Invalid(InvalidTransaction::Custom(INVALID_VALIDATORS_LEN)) => - "invalid validators len", + TransactionValidityError::Invalid(InvalidTransaction::Custom(INVALID_VALIDATORS_LEN)) => { + "invalid validators len" + } e @ _ => <&'static str>::from(e), })?; ImOnline::heartbeat(Origin::none(), heartbeat, signature) @@ -147,7 +149,10 @@ fn should_mark_online_validator_when_heartbeat_is_received() { new_test_ext().execute_with(|| { advance_session(); // given - VALIDATORS.with(|l| *l.borrow_mut() = Some(vec![1, 2, 3, 4, 5, 6])); + VALIDATORS.with(|l| { + *l.borrow_mut() = + Some(BoundedVec::try_from(vec![1, 2, 3, 4, 5, 6]).expect("MaxKeys >= 6")) + }); assert_eq!(Session::validators(), Vec::::new()); // enact the change and buffer another one advance_session(); @@ -160,7 +165,7 @@ fn should_mark_online_validator_when_heartbeat_is_received() { assert!(!ImOnline::is_online(2)); // when - let _ = heartbeat(1, 2, 0, 1.into(), Session::validators()).unwrap(); + let _ = heartbeat(1, 2, 0, 1.into(), Session::validators().to_vec()).unwrap(); // then assert!(ImOnline::is_online(0)); @@ -168,7 +173,7 @@ fn should_mark_online_validator_when_heartbeat_is_received() { assert!(!ImOnline::is_online(2)); // and when - let _ = heartbeat(1, 2, 2, 3.into(), Session::validators()).unwrap(); + let _ = heartbeat(1, 2, 2, 3.into(), Session::validators().to_vec()).unwrap(); // then assert!(ImOnline::is_online(0)); @@ -182,7 +187,10 @@ fn late_heartbeat_and_invalid_keys_len_should_fail() { new_test_ext().execute_with(|| { advance_session(); // given - VALIDATORS.with(|l| *l.borrow_mut() = Some(vec![1, 2, 3, 4, 5, 6])); + VALIDATORS.with(|l| { + *l.borrow_mut() = + Some(BoundedVec::try_from(vec![1, 2, 3, 4, 5, 6]).expect("MaxKeys >= 6")) + }); assert_eq!(Session::validators(), Vec::::new()); // enact the change and buffer another one advance_session(); @@ -192,11 +200,11 @@ fn late_heartbeat_and_invalid_keys_len_should_fail() { // when assert_noop!( - heartbeat(1, 3, 0, 1.into(), Session::validators()), + heartbeat(1, 3, 0, 1.into(), Session::validators().to_vec()), "Transaction is outdated" ); assert_noop!( - heartbeat(1, 1, 0, 1.into(), Session::validators()), + heartbeat(1, 1, 0, 1.into(), Session::validators().to_vec()), "Transaction is outdated" ); @@ -224,7 +232,10 @@ fn should_generate_heartbeats() { // buffer new validators Session::rotate_session(); // enact the change and buffer another one - VALIDATORS.with(|l| *l.borrow_mut() = Some(vec![1, 2, 3, 4, 5, 6])); + VALIDATORS.with(|l| { + *l.borrow_mut() = + Some(BoundedVec::try_from(vec![1, 2, 3, 4, 5, 6]).expect("MaxKeys >= 6")) + }); Session::rotate_session(); // when @@ -260,7 +271,9 @@ fn should_cleanup_received_heartbeats_on_session_end() { new_test_ext().execute_with(|| { advance_session(); - VALIDATORS.with(|l| *l.borrow_mut() = Some(vec![1, 2, 3])); + VALIDATORS.with(|l| { + *l.borrow_mut() = Some(BoundedVec::try_from(vec![1, 2, 3]).expect("MaxKeys >= 3")) + }); assert_eq!(Session::validators(), Vec::::new()); // enact the change and buffer another one @@ -270,7 +283,7 @@ fn should_cleanup_received_heartbeats_on_session_end() { assert_eq!(Session::validators(), vec![1, 2, 3]); // send an heartbeat from authority id 0 at session 2 - let _ = heartbeat(1, 2, 0, 1.into(), Session::validators()).unwrap(); + let _ = heartbeat(1, 2, 0, 1.into(), Session::validators().to_vec()).unwrap(); // the heartbeat is stored assert!(!ImOnline::received_heartbeats(&2, &0).is_none()); @@ -291,7 +304,10 @@ fn should_mark_online_validator_when_block_is_authored() { new_test_ext().execute_with(|| { advance_session(); // given - VALIDATORS.with(|l| *l.borrow_mut() = Some(vec![1, 2, 3, 4, 5, 6])); + VALIDATORS.with(|l| { + *l.borrow_mut() = + Some(BoundedVec::try_from(vec![1, 2, 3, 4, 5, 6]).expect("MaxKeys >= 6")) + }); assert_eq!(Session::validators(), Vec::::new()); // enact the change and buffer another one advance_session(); @@ -328,7 +344,10 @@ fn should_not_send_a_report_if_already_online() { ext.execute_with(|| { advance_session(); // given - VALIDATORS.with(|l| *l.borrow_mut() = Some(vec![1, 2, 3, 4, 5, 6])); + VALIDATORS.with(|l| { + *l.borrow_mut() = + Some(BoundedVec::try_from(vec![1, 2, 3, 4, 5, 6]).expect("MaxKeys >= 6")) + }); assert_eq!(Session::validators(), Vec::::new()); // enact the change and buffer another one advance_session(); @@ -391,7 +410,9 @@ fn should_handle_missing_progress_estimates() { Session::rotate_session(); // enact the change and buffer another one - VALIDATORS.with(|l| *l.borrow_mut() = Some(vec![0, 1, 2])); + VALIDATORS.with(|l| { + *l.borrow_mut() = Some(BoundedVec::try_from(vec![0, 1, 2]).expect("MaxKeys >= 3")) + }); Session::rotate_session(); // we will return `None` on the next call to `estimate_current_session_progress` @@ -425,7 +446,9 @@ fn should_handle_non_linear_session_progress() { // mock the session length as being 10 blocks long, // enact the change and buffer another one - VALIDATORS.with(|l| *l.borrow_mut() = Some(vec![0, 1, 2])); + VALIDATORS.with(|l| { + *l.borrow_mut() = Some(BoundedVec::try_from(vec![0, 1, 2]).expect("MaxKeys >= 3")) + }); // mock the session length has being 10 which should make us assume the fallback for half // session will be reached by block 5. From 4c1c74be472d18040ac8016398f54c5bd9f8bcec Mon Sep 17 00:00:00 2001 From: Georges Dib Date: Fri, 22 Oct 2021 04:22:26 +0100 Subject: [PATCH 64/80] Some more test fixes --- frame/authority-discovery/src/lib.rs | 3 +++ frame/beefy-mmr/src/mock.rs | 16 ++++++++++------ frame/beefy/src/mock.rs | 16 ++++++++++------ frame/offences/benchmarking/src/mock.rs | 5 +++++ frame/session/benchmarking/src/mock.rs | 5 +++++ 5 files changed, 33 insertions(+), 12 deletions(-) diff --git a/frame/authority-discovery/src/lib.rs b/frame/authority-discovery/src/lib.rs index 8fced0d18cff1..2e8163e6d2e6e 100644 --- a/frame/authority-discovery/src/lib.rs +++ b/frame/authority-discovery/src/lib.rs @@ -204,6 +204,7 @@ mod tests { parameter_types! { pub const DisabledValidatorsThreshold: Perbill = Perbill::from_percent(33); pub const MaxAuthorities: u32 = 100; + pub const MaxKeysEncodingSize: u32 = 1_000; } impl Config for Test { @@ -219,6 +220,8 @@ mod tests { type ValidatorId = AuthorityId; type ValidatorIdOf = ConvertInto; type NextSessionRotation = pallet_session::PeriodicSessions; + type MaxValidatorsCount = MaxAuthorities; + type MaxKeysEncodingSize = MaxKeysEncodingSize; type WeightInfo = (); } diff --git a/frame/beefy-mmr/src/mock.rs b/frame/beefy-mmr/src/mock.rs index 95b87c360510a..f8b9c418537d5 100644 --- a/frame/beefy-mmr/src/mock.rs +++ b/frame/beefy-mmr/src/mock.rs @@ -15,12 +15,12 @@ // See the License for the specific language governing permissions and // limitations under the License. -use std::vec; +use std::{convert::TryFrom, vec}; use beefy_primitives::mmr::MmrLeafVersion; use frame_support::{ construct_runtime, parameter_types, sp_io::TestExternalities, traits::GenesisBuild, - BasicExternalities, + BasicExternalities, BoundedVec, }; use sp_core::{Hasher, H256}; use sp_runtime::{ @@ -91,6 +91,8 @@ impl frame_system::Config for Test { parameter_types! { pub const Period: u64 = 1; pub const Offset: u64 = 0; + pub const MaxValidatorsCount: u32 = 10; + pub const MaxKeysEncodingSize: u32 = 1_000; } impl pallet_session::Config for Test { @@ -102,6 +104,8 @@ impl pallet_session::Config for Test { type SessionManager = MockSessionManager; type SessionHandler = ::KeyTypeIdProviders; type Keys = MockSessionKeys; + type MaxValidatorsCount = MaxValidatorsCount; + type MaxKeysEncodingSize = MaxKeysEncodingSize; type WeightInfo = (); } @@ -149,14 +153,14 @@ impl pallet_beefy_mmr::ParachainHeadsProvider for DummyParaHeads { } pub struct MockSessionManager; -impl pallet_session::SessionManager for MockSessionManager { +impl pallet_session::SessionManager for MockSessionManager { fn end_session(_: sp_staking::SessionIndex) {} fn start_session(_: sp_staking::SessionIndex) {} - fn new_session(idx: sp_staking::SessionIndex) -> Option> { + fn new_session(idx: sp_staking::SessionIndex) -> Option> { if idx == 0 || idx == 1 { - Some(vec![1, 2]) + Some(BoundedVec::try_from(vec![1, 2]).expect("MaxValidatorsCount >= 2")) } else if idx == 2 { - Some(vec![3, 4]) + Some(BoundedVec::try_from(vec![3, 4]).expect("MaxValidatorsCount >= 2")) } else { None } diff --git a/frame/beefy/src/mock.rs b/frame/beefy/src/mock.rs index a1fbeda4ab35c..bb8476e13b076 100644 --- a/frame/beefy/src/mock.rs +++ b/frame/beefy/src/mock.rs @@ -15,11 +15,11 @@ // See the License for the specific language governing permissions and // limitations under the License. -use std::vec; +use std::{convert::TryFrom, vec}; use frame_support::{ construct_runtime, parameter_types, sp_io::TestExternalities, traits::GenesisBuild, - BasicExternalities, + BasicExternalities, BoundedVec, }; use sp_core::H256; use sp_runtime::{ @@ -94,6 +94,8 @@ parameter_types! { pub const Period: u64 = 1; pub const Offset: u64 = 0; pub const DisabledValidatorsThreshold: Perbill = Perbill::from_percent(33); + pub const MaxValidatorsCount: u32 = 100; + pub const MaxKeysEncodingSize: u32 = 1_000; } impl pallet_session::Config for Test { @@ -105,19 +107,21 @@ impl pallet_session::Config for Test { type SessionManager = MockSessionManager; type SessionHandler = ::KeyTypeIdProviders; type Keys = MockSessionKeys; + type MaxValidatorsCount = MaxValidatorsCount; + type MaxKeysEncodingSize = MaxKeysEncodingSize; type WeightInfo = (); } pub struct MockSessionManager; -impl pallet_session::SessionManager for MockSessionManager { +impl pallet_session::SessionManager for MockSessionManager { fn end_session(_: sp_staking::SessionIndex) {} fn start_session(_: sp_staking::SessionIndex) {} - fn new_session(idx: sp_staking::SessionIndex) -> Option> { + fn new_session(idx: sp_staking::SessionIndex) -> Option> { if idx == 0 || idx == 1 { - Some(vec![1, 2]) + Some(BoundedVec::try_from(vec![1, 2]).expect("MaxValidatorsCount >=2")) } else if idx == 2 { - Some(vec![3, 4]) + Some(BoundedVec::try_from(vec![3, 4]).expect("MaxValidatorsCount >=2")) } else { None } diff --git a/frame/offences/benchmarking/src/mock.rs b/frame/offences/benchmarking/src/mock.rs index 505553e5bc86b..012384788d92e 100644 --- a/frame/offences/benchmarking/src/mock.rs +++ b/frame/offences/benchmarking/src/mock.rs @@ -129,6 +129,8 @@ impl pallet_session::Config for Test { type Event = Event; type ValidatorId = AccountId; type ValidatorIdOf = pallet_staking::StashOf; + type MaxValidatorsCount = MaxValidatorsCount; + type MaxKeysEncodingSize = MaxKeysEncodingSize; type WeightInfo = (); } @@ -156,6 +158,7 @@ parameter_types! { pub const MaxReportersCount: u32 = 1_000; pub const MaxPriorSlashingSpans: u32 = 1_000; pub const MaxValidatorsCount: u32 = 4_000; + pub const MaxKeysEncodingSize: u32 = 1_000; pub const MaxUnlockingChunks: u32 = 32; } @@ -164,6 +167,8 @@ pub type Extrinsic = sp_runtime::testing::TestXt; impl onchain::Config for Test { type Accuracy = Perbill; type DataProvider = Staking; + type MaxNominations = MaxNominations; + type MaxTargets = MaxValidatorsCount; } impl pallet_staking::Config for Test { diff --git a/frame/session/benchmarking/src/mock.rs b/frame/session/benchmarking/src/mock.rs index e77e0e9a0ee4f..26fe930681275 100644 --- a/frame/session/benchmarking/src/mock.rs +++ b/frame/session/benchmarking/src/mock.rs @@ -129,6 +129,8 @@ impl pallet_session::Config for Test { type Event = Event; type ValidatorId = AccountId; type ValidatorIdOf = pallet_staking::StashOf; + type MaxValidatorsCount = MaxValidatorsCount; + type MaxKeysEncodingSize = MaxKeysEncodingSize; type WeightInfo = (); } pallet_staking_reward_curve::build! { @@ -153,6 +155,7 @@ parameter_types! { pub const MaxReportersCount: u32 = 1_000; pub const MaxPriorSlashingSpans: u32 = 1_000; pub const MaxValidatorsCount: u32 = 4_000; + pub const MaxKeysEncodingSize: u32 = 1_000; pub const MaxUnlockingChunks: u32 = 32; } @@ -169,6 +172,8 @@ where impl onchain::Config for Test { type Accuracy = sp_runtime::Perbill; type DataProvider = Staking; + type MaxNominations = MaxNominations; + type MaxTargets = MaxValidatorsCount; } impl pallet_staking::Config for Test { From d74bee4f6259258d178939d2ab199fe760822f26 Mon Sep 17 00:00:00 2001 From: Georges Dib Date: Fri, 22 Oct 2021 16:26:41 +0100 Subject: [PATCH 65/80] Merging `MaxKeys` with `MaxValidatorsCount` --- bin/node/runtime/src/lib.rs | 3 +-- frame/offences/benchmarking/src/mock.rs | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 976469ef47bd2..98a70aa5550b6 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -958,7 +958,6 @@ parameter_types! { /// We prioritize im-online heartbeats over election solution submission. pub const StakingUnsignedPriority: TransactionPriority = TransactionPriority::max_value() / 2; pub const MaxAuthorities: u32 = 100; - pub const MaxKeys: u32 = 10_000; pub const MaxPeerInHeartbeats: u32 = 10_000; pub const MaxPeerDataEncodingSize: u32 = 1_000; } @@ -1025,7 +1024,7 @@ impl pallet_im_online::Config for Runtime { type ReportUnresponsiveness = Offences; type UnsignedPriority = ImOnlineUnsignedPriority; type WeightInfo = pallet_im_online::weights::SubstrateWeight; - type MaxKeys = MaxKeys; + type MaxKeys = MaxValidatorsCount; type MaxPeerInHeartbeats = MaxPeerInHeartbeats; type MaxPeerDataEncodingSize = MaxPeerDataEncodingSize; } diff --git a/frame/offences/benchmarking/src/mock.rs b/frame/offences/benchmarking/src/mock.rs index 012384788d92e..38719b3ac80e0 100644 --- a/frame/offences/benchmarking/src/mock.rs +++ b/frame/offences/benchmarking/src/mock.rs @@ -148,7 +148,6 @@ parameter_types! { pub const RewardCurve: &'static sp_runtime::curve::PiecewiseLinear<'static> = &I_NPOS; pub const MaxRewardableIndividualExposures: u32 = 64; pub const MaxIndividualExposures: u32 = 64; - pub const MaxKeys: u32 = 10_000; pub const MaxPeerInHeartbeats: u32 = 10_000; pub const MaxPeerDataEncodingSize: u32 = 1_000; pub const MaxNominations: u32 = 16; @@ -211,7 +210,7 @@ impl pallet_im_online::Config for Test { type ReportUnresponsiveness = Offences; type UnsignedPriority = (); type WeightInfo = (); - type MaxKeys = MaxKeys; + type MaxKeys = MaxValidatorsCount; type MaxPeerInHeartbeats = MaxPeerInHeartbeats; type MaxPeerDataEncodingSize = MaxPeerDataEncodingSize; } From bae95252f7223d8c59bec36ea6b8112def2696fa Mon Sep 17 00:00:00 2001 From: Georges Dib Date: Sat, 23 Oct 2021 13:58:53 +0100 Subject: [PATCH 66/80] Merging `MaxAuthorities` and `MaxValidatorsCount` Cleanups --- bin/node/runtime/src/lib.rs | 7 +++---- frame/aura/src/lib.rs | 5 +++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 98a70aa5550b6..e5ed62f013bb9 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -379,7 +379,7 @@ impl pallet_babe::Config for Runtime { pallet_babe::EquivocationHandler; type WeightInfo = (); - type MaxAuthorities = MaxAuthorities; + type MaxAuthorities = MaxValidatorsCount; } parameter_types! { @@ -957,7 +957,6 @@ parameter_types! { pub const ImOnlineUnsignedPriority: TransactionPriority = TransactionPriority::max_value(); /// We prioritize im-online heartbeats over election solution submission. pub const StakingUnsignedPriority: TransactionPriority = TransactionPriority::max_value() / 2; - pub const MaxAuthorities: u32 = 100; pub const MaxPeerInHeartbeats: u32 = 10_000; pub const MaxPeerDataEncodingSize: u32 = 1_000; } @@ -1036,7 +1035,7 @@ impl pallet_offences::Config for Runtime { } impl pallet_authority_discovery::Config for Runtime { - type MaxAuthorities = MaxAuthorities; + type MaxAuthorities = MaxValidatorsCount; } impl pallet_grandpa::Config for Runtime { @@ -1060,7 +1059,7 @@ impl pallet_grandpa::Config for Runtime { >; type WeightInfo = (); - type MaxAuthorities = MaxAuthorities; + type MaxAuthorities = MaxValidatorsCount; } parameter_types! { diff --git a/frame/aura/src/lib.rs b/frame/aura/src/lib.rs index 4b5294835403a..0edb247bcae67 100644 --- a/frame/aura/src/lib.rs +++ b/frame/aura/src/lib.rs @@ -72,6 +72,7 @@ pub mod pallet { + Default + MaybeSerializeDeserialize + MaxEncodedLen; + /// The maximum number of authorities that the pallet can hold. type MaxAuthorities: Get; @@ -173,7 +174,7 @@ impl Pallet { let pre_runtime_digests = digest.logs.iter().filter_map(|d| d.as_pre_runtime()); for (id, mut data) in pre_runtime_digests { if id == AURA_ENGINE_ID { - return Slot::decode(&mut data).ok() + return Slot::decode(&mut data).ok(); } } @@ -240,7 +241,7 @@ impl FindAuthor for Pallet { if id == AURA_ENGINE_ID { let slot = Slot::decode(&mut data).ok()?; let author_index = *slot % Self::authorities().len() as u64; - return Some(author_index as u32) + return Some(author_index as u32); } } From 6d4e1d1de491c28733419024679126bf36f8a698 Mon Sep 17 00:00:00 2001 From: Georges Dib Date: Sun, 24 Oct 2021 19:31:22 +0100 Subject: [PATCH 67/80] Bounding `OffenceDetails` and moving implementation to `frame-support` --- bin/node-template/runtime/src/lib.rs | 2 + bin/node/runtime/src/lib.rs | 4 + frame/babe/src/equivocation.rs | 17 ++-- frame/babe/src/lib.rs | 21 ++-- frame/grandpa/src/equivocation.rs | 21 ++-- frame/grandpa/src/lib.rs | 23 +++-- frame/im-online/src/lib.rs | 43 ++++---- frame/offences/benchmarking/src/lib.rs | 13 ++- frame/offences/src/lib.rs | 36 +++++-- frame/offences/src/migration.rs | 16 ++- frame/staking/src/lib.rs | 16 +-- frame/staking/src/pallet/impls.rs | 21 ++-- frame/support/src/lib.rs | 2 +- frame/support/src/traits.rs | 3 + frame/support/src/traits/staking.rs | 131 +++++++++++++++++++++++++ primitives/staking/src/offence.rs | 72 +------------- test-utils/runtime/src/lib.rs | 38 +++---- 17 files changed, 301 insertions(+), 178 deletions(-) create mode 100644 frame/support/src/traits/staking.rs diff --git a/bin/node-template/runtime/src/lib.rs b/bin/node-template/runtime/src/lib.rs index 4b49cb48ef352..46155839a039e 100644 --- a/bin/node-template/runtime/src/lib.rs +++ b/bin/node-template/runtime/src/lib.rs @@ -197,6 +197,7 @@ impl pallet_randomness_collective_flip::Config for Runtime {} parameter_types! { pub const MaxAuthorities: u32 = 32; + pub const MaxReportersCount: u32 = 100; } impl pallet_aura::Config for Runtime { @@ -223,6 +224,7 @@ impl pallet_grandpa::Config for Runtime { type WeightInfo = (); type MaxAuthorities = MaxAuthorities; + type MaxReportersCount = MaxReportersCount; } parameter_types! { diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index e5ed62f013bb9..994628c85fdfe 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -380,6 +380,7 @@ impl pallet_babe::Config for Runtime { type WeightInfo = (); type MaxAuthorities = MaxValidatorsCount; + type MaxReportersCount = MaxReportersCount; } parameter_types! { @@ -1026,12 +1027,14 @@ impl pallet_im_online::Config for Runtime { type MaxKeys = MaxValidatorsCount; type MaxPeerInHeartbeats = MaxPeerInHeartbeats; type MaxPeerDataEncodingSize = MaxPeerDataEncodingSize; + type MaxReportersCount = MaxReportersCount; } impl pallet_offences::Config for Runtime { type Event = Event; type IdentificationTuple = pallet_session::historical::IdentificationTuple; type OnOffenceHandler = Staking; + type MaxReportersCount = MaxReportersCount; } impl pallet_authority_discovery::Config for Runtime { @@ -1060,6 +1063,7 @@ impl pallet_grandpa::Config for Runtime { type WeightInfo = (); type MaxAuthorities = MaxValidatorsCount; + type MaxReportersCount = MaxReportersCount; } parameter_types! { diff --git a/frame/babe/src/equivocation.rs b/frame/babe/src/equivocation.rs index 2397918d1ef13..91704638413a1 100644 --- a/frame/babe/src/equivocation.rs +++ b/frame/babe/src/equivocation.rs @@ -33,7 +33,7 @@ //! that the `ValidateUnsigned` for the BABE pallet is used in the runtime //! definition. -use frame_support::traits::{Get, KeyOwnerProofSystem}; +use frame_support::traits::{Get, KeyOwnerProofSystem, ReportOffence}; use sp_consensus_babe::{EquivocationProof, Slot}; use sp_runtime::{ transaction_validity::{ @@ -43,7 +43,7 @@ use sp_runtime::{ DispatchResult, Perbill, }; use sp_staking::{ - offence::{Kind, Offence, OffenceError, ReportOffence}, + offence::{Kind, Offence, OffenceError}, SessionIndex, }; use sp_std::prelude::*; @@ -62,7 +62,7 @@ pub trait HandleEquivocation { /// Report an offence proved by the given reporters. fn report_offence( - reporters: Vec, + reporters: frame_support::WeakBoundedVec, offence: BabeEquivocationOffence, ) -> Result<(), OffenceError>; @@ -83,7 +83,7 @@ impl HandleEquivocation for () { type ReportLongevity = (); fn report_offence( - _reporters: Vec, + _reporters: frame_support::WeakBoundedVec, _offence: BabeEquivocationOffence, ) -> Result<(), OffenceError> { Ok(()) @@ -131,6 +131,7 @@ where T::AccountId, T::KeyOwnerIdentification, BabeEquivocationOffence, + T::MaxReportersCount, >, // The longevity (in blocks) that the equivocation report is valid for. When using the staking // pallet this should be the bonding duration. @@ -139,7 +140,7 @@ where type ReportLongevity = L; fn report_offence( - reporters: Vec, + reporters: frame_support::WeakBoundedVec, offence: BabeEquivocationOffence, ) -> Result<(), OffenceError> { R::report_offence(reporters, offence) @@ -189,15 +190,15 @@ impl Pallet { if let Call::report_equivocation_unsigned { equivocation_proof, key_owner_proof } = call { // discard equivocation report not coming from the local node match source { - TransactionSource::Local | TransactionSource::InBlock => { /* allowed */ }, + TransactionSource::Local | TransactionSource::InBlock => { /* allowed */ } _ => { log::warn!( target: "runtime::babe", "rejecting unsigned report equivocation transaction because it is not local/in-block.", ); - return InvalidTransaction::Call.into() - }, + return InvalidTransaction::Call.into(); + } } // check report staleness diff --git a/frame/babe/src/lib.rs b/frame/babe/src/lib.rs index 9c755eea6c446..02d3044b479ea 100644 --- a/frame/babe/src/lib.rs +++ b/frame/babe/src/lib.rs @@ -176,6 +176,10 @@ pub mod pallet { /// Max number of authorities allowed #[pallet::constant] type MaxAuthorities: Get; + + /// Maximum number of reporters. + #[pallet::constant] + type MaxReportersCount: Get; } #[pallet::error] @@ -441,11 +445,11 @@ impl FindAuthor for Pallet { for (id, mut data) in digests.into_iter() { if id == BABE_ENGINE_ID { let pre_digest: PreDigest = PreDigest::decode(&mut data).ok()?; - return Some(pre_digest.authority_index()) + return Some(pre_digest.authority_index()); } } - return None + return None; } } @@ -661,7 +665,7 @@ impl Pallet { // => let's ensure that we only modify the storage once per block let initialized = Self::initialized().is_some(); if initialized { - return + return; } let maybe_pre_digest: Option = @@ -790,7 +794,7 @@ impl Pallet { // validate the equivocation proof if !sp_consensus_babe::check_equivocation_proof(equivocation_proof) { - return Err(Error::::InvalidEquivocationProof.into()) + return Err(Error::::InvalidEquivocationProof.into()); } let validator_set_count = key_owner_proof.validator_count(); @@ -802,7 +806,7 @@ impl Pallet { // check that the slot number is consistent with the session index // in the key ownership proof (i.e. slot is for that epoch) if epoch_index != session_index { - return Err(Error::::InvalidKeyOwnershipProof.into()) + return Err(Error::::InvalidKeyOwnershipProof.into()); } // check the membership proof and extract the offender's id @@ -814,8 +818,11 @@ impl Pallet { BabeEquivocationOffence { slot, validator_set_count, offender, session_index }; let reporters = match reporter { - Some(id) => vec![id], - None => vec![], + Some(id) => WeakBoundedVec::<_, _>::force_from( + vec![id], + Some("pallet_babe.do_report_equivocation"), + ), + None => WeakBoundedVec::default(), }; T::HandleEquivocation::report_offence(reporters, offence) diff --git a/frame/grandpa/src/equivocation.rs b/frame/grandpa/src/equivocation.rs index 8a23ce6e1ef1e..3409698a794af 100644 --- a/frame/grandpa/src/equivocation.rs +++ b/frame/grandpa/src/equivocation.rs @@ -38,7 +38,7 @@ use sp_std::prelude::*; use codec::{self as codec, Decode, Encode}; -use frame_support::traits::{Get, KeyOwnerProofSystem}; +use frame_support::traits::{Get, KeyOwnerProofSystem, ReportOffence}; use sp_finality_grandpa::{EquivocationProof, RoundNumber, SetId}; use sp_runtime::{ transaction_validity::{ @@ -48,7 +48,7 @@ use sp_runtime::{ DispatchResult, Perbill, }; use sp_staking::{ - offence::{Kind, Offence, OffenceError, ReportOffence}, + offence::{Kind, Offence, OffenceError}, SessionIndex, }; @@ -68,7 +68,7 @@ pub trait HandleEquivocation { /// Report an offence proved by the given reporters. fn report_offence( - reporters: Vec, + reporters: frame_support::WeakBoundedVec, offence: Self::Offence, ) -> Result<(), OffenceError>; @@ -93,7 +93,7 @@ impl HandleEquivocation for () { type ReportLongevity = (); fn report_offence( - _reporters: Vec, + _reporters: frame_support::WeakBoundedVec, _offence: GrandpaEquivocationOffence, ) -> Result<(), OffenceError> { Ok(()) @@ -140,7 +140,7 @@ where T: Config + pallet_authorship::Config + frame_system::offchain::SendTransactionTypes>, // A system for reporting offences after valid equivocation reports are // processed. - R: ReportOffence, + R: ReportOffence, // The longevity (in blocks) that the equivocation report is valid for. When using the staking // pallet this should be the bonding duration. L: Get, @@ -150,7 +150,10 @@ where type Offence = O; type ReportLongevity = L; - fn report_offence(reporters: Vec, offence: O) -> Result<(), OffenceError> { + fn report_offence( + reporters: frame_support::WeakBoundedVec, + offence: O, + ) -> Result<(), OffenceError> { R::report_offence(reporters, offence) } @@ -208,15 +211,15 @@ impl Pallet { if let Call::report_equivocation_unsigned { equivocation_proof, key_owner_proof } = call { // discard equivocation report not coming from the local node match source { - TransactionSource::Local | TransactionSource::InBlock => { /* allowed */ }, + TransactionSource::Local | TransactionSource::InBlock => { /* allowed */ } _ => { log::warn!( target: "runtime::afg", "rejecting unsigned report equivocation transaction because it is not local/in-block." ); - return InvalidTransaction::Call.into() - }, + return InvalidTransaction::Call.into(); + } } // check report staleness diff --git a/frame/grandpa/src/lib.rs b/frame/grandpa/src/lib.rs index 9f6967a7d3c85..c0509fb9e9e51 100644 --- a/frame/grandpa/src/lib.rs +++ b/frame/grandpa/src/lib.rs @@ -126,6 +126,10 @@ pub mod pallet { /// Max Authorities in use #[pallet::constant] type MaxAuthorities: Get; + + /// Maximum number of reporters. + #[pallet::constant] + type MaxReportersCount: Get; } #[pallet::hooks] @@ -174,7 +178,7 @@ pub mod pallet { >::put(StoredState::Paused); Self::deposit_event(Event::Paused); } - }, + } StoredState::PendingResume { scheduled_at, delay } => { // signal change to resume if block_number == scheduled_at { @@ -186,8 +190,8 @@ pub mod pallet { >::put(StoredState::Live); Self::deposit_event(Event::Resumed); } - }, - _ => {}, + } + _ => {} } } } @@ -550,7 +554,7 @@ impl Pallet { // validate equivocation proof (check votes are different and // signatures are valid). if !sp_finality_grandpa::check_equivocation_proof(equivocation_proof) { - return Err(Error::::InvalidEquivocationProof.into()) + return Err(Error::::InvalidEquivocationProof.into()); } // fetch the current and previous sets last session index. on the @@ -569,17 +573,20 @@ impl Pallet { // check that the session id for the membership proof is within the // bounds of the set id reported in the equivocation. - if session_index > set_id_session_index || - previous_set_id_session_index + if session_index > set_id_session_index + || previous_set_id_session_index .map(|previous_index| session_index <= previous_index) .unwrap_or(false) { - return Err(Error::::InvalidEquivocationProof.into()) + return Err(Error::::InvalidEquivocationProof.into()); } // report to the offences module rewarding the sender. T::HandleEquivocation::report_offence( - reporter.into_iter().collect(), + WeakBoundedVec::<_, _>::force_from( + reporter.into_iter().collect::>(), + Some("frame_granpda.do_report_equivocation"), + ), >::Offence::new( session_index, validator_count, diff --git a/frame/im-online/src/lib.rs b/frame/im-online/src/lib.rs index d76bbaaa2fd14..c0705c4c7b0f7 100644 --- a/frame/im-online/src/lib.rs +++ b/frame/im-online/src/lib.rs @@ -78,7 +78,7 @@ use codec::{Decode, Encode, MaxEncodedLen}; use core::convert::TryFrom; use frame_support::{ traits::{ - EstimateNextSessionRotation, Get, OneSessionHandler, ValidatorSet, + EstimateNextSessionRotation, Get, OneSessionHandler, ReportOffence, ValidatorSet, ValidatorSetWithIdentification, WrapperOpaque, }, BoundedSlice, WeakBoundedVec, @@ -94,7 +94,7 @@ use sp_runtime::{ PerThing, Perbill, Permill, RuntimeDebug, SaturatedConversion, }; use sp_staking::{ - offence::{Kind, Offence, ReportOffence}, + offence::{Kind, Offence}, SessionIndex, }; use sp_std::{convert::TryInto, prelude::*}; @@ -193,10 +193,10 @@ impl sp_std::fmt::Debug for OffchainErr write!(fmt, "Too early to send heartbeat."), OffchainErr::WaitingForInclusion(ref block) => { write!(fmt, "Heartbeat already sent at {:?}. Waiting for inclusion.", block) - }, + } OffchainErr::AlreadyOnline(auth_idx) => { write!(fmt, "Authority {} is already online", auth_idx) - }, + } OffchainErr::FailedSigning => write!(fmt, "Failed to sign heartbeat"), OffchainErr::FailedToAcquireLock => write!(fmt, "Failed to acquire lock"), OffchainErr::NetworkState => write!(fmt, "Failed to fetch network state"), @@ -354,11 +354,15 @@ pub mod pallet { /// chance the authority will produce a block and they won't be necessary. type NextSessionRotation: EstimateNextSessionRotation; + /// Maximum number of reporters of unreponsiveness offences. + type MaxReportersCount: Get; + /// A type that gives us the ability to submit unresponsiveness offence reports. type ReportUnresponsiveness: ReportOffence< Self::AccountId, IdentificationTuple, UnresponsivenessOffence>, + Self::MaxReportersCount, >; /// A configuration for base priority of unsigned transactions. @@ -555,19 +559,19 @@ pub mod pallet { if let Call::heartbeat { heartbeat, signature } = call { if >::is_online(heartbeat.authority_index) { // we already received a heartbeat for this authority - return InvalidTransaction::Stale.into() + return InvalidTransaction::Stale.into(); } // check if session index from heartbeat is recent let current_session = T::ValidatorSet::session_index(); if heartbeat.session_index != current_session { - return InvalidTransaction::Stale.into() + return InvalidTransaction::Stale.into(); } // verify that the incoming (unverified) pubkey is actually an authority id let keys = Keys::::get(); if keys.len() as u32 != heartbeat.validators_len { - return InvalidTransaction::Custom(INVALID_VALIDATORS_LEN).into() + return InvalidTransaction::Custom(INVALID_VALIDATORS_LEN).into(); } let authority_id = match keys.get(heartbeat.authority_index as usize) { Some(id) => id, @@ -580,7 +584,7 @@ pub mod pallet { }); if !signature_valid { - return InvalidTransaction::BadProof.into() + return InvalidTransaction::BadProof.into(); } ValidTransaction::with_tag_prefix("ImOnline") @@ -624,7 +628,7 @@ impl Pallet { let current_validators = T::ValidatorSet::validators(); if authority_index >= current_validators.len() as u32 { - return false + return false; } let authority = ¤t_validators[authority_index as usize]; @@ -635,8 +639,8 @@ impl Pallet { fn is_online_aux(authority_index: AuthIndex, authority: &ValidatorId) -> bool { let current_session = T::ValidatorSet::session_index(); - ReceivedHeartbeats::::contains_key(¤t_session, &authority_index) || - AuthoredBlocks::::get(¤t_session, authority) != 0 + ReceivedHeartbeats::::contains_key(¤t_session, &authority_index) + || AuthoredBlocks::::get(¤t_session, authority) != 0 } /// Returns `true` if a heartbeat has been received for the authority at `authority_index` in @@ -686,8 +690,8 @@ impl Pallet { // haven't sent an heartbeat yet we'll send one unconditionally. the idea is to prevent // all nodes from sending the heartbeats at the same block and causing a temporary (but // deterministic) spike in transactions. - progress >= START_HEARTBEAT_FINAL_PERIOD || - progress >= START_HEARTBEAT_RANDOM_PERIOD && random_choice(progress) + progress >= START_HEARTBEAT_FINAL_PERIOD + || progress >= START_HEARTBEAT_RANDOM_PERIOD && random_choice(progress) } else { // otherwise we fallback to using the block number calculated at the beginning // of the session that should roughly correspond to the middle of the session @@ -696,7 +700,7 @@ impl Pallet { }; if !should_heartbeat { - return Err(OffchainErr::TooEarly) + return Err(OffchainErr::TooEarly); } let session_index = T::ValidatorSet::session_index(); @@ -738,7 +742,7 @@ impl Pallet { }; if Self::is_online(authority_index) { - return Err(OffchainErr::AlreadyOnline(authority_index)) + return Err(OffchainErr::AlreadyOnline(authority_index)); } // acquire lock for that authority at current heartbeat to make sure we don't @@ -804,15 +808,16 @@ impl Pallet { // we will re-send it. match status { // we are still waiting for inclusion. - Ok(Some(status)) if status.is_recent(session_index, now) => - Err(OffchainErr::WaitingForInclusion(status.sent_at)), + Ok(Some(status)) if status.is_recent(session_index, now) => { + Err(OffchainErr::WaitingForInclusion(status.sent_at)) + } // attempt to set new status _ => Ok(HeartbeatStatus { session_index, sent_at: now }), } }, ); if let Err(MutateStorageError::ValueFunctionFailed(err)) = res { - return Err(err) + return Err(err); } let mut new_status = res.map_err(|_| OffchainErr::FailedToAcquireLock)?; @@ -913,7 +918,7 @@ impl OneSessionHandler for Pallet { let validator_set_count = keys.len() as u32; let offence = UnresponsivenessOffence { session_index, validator_set_count, offenders }; - if let Err(e) = T::ReportUnresponsiveness::report_offence(vec![], offence) { + if let Err(e) = T::ReportUnresponsiveness::report_offence(Default::default(), offence) { sp_runtime::print(e); } } diff --git a/frame/offences/benchmarking/src/lib.rs b/frame/offences/benchmarking/src/lib.rs index d56337287b3ed..c501bd80c55e0 100644 --- a/frame/offences/benchmarking/src/lib.rs +++ b/frame/offences/benchmarking/src/lib.rs @@ -25,7 +25,7 @@ use sp_std::{convert::TryFrom, prelude::*, vec}; use frame_benchmarking::{account, benchmarks}; use frame_support::{ - traits::{Currency, Get, ValidatorSet, ValidatorSetWithIdentification}, + traits::{Currency, Get, ReportOffence, ValidatorSet, ValidatorSetWithIdentification}, WeakBoundedVec, }; use frame_system::{Config as SystemConfig, Pallet as System, RawOrigin}; @@ -34,7 +34,7 @@ use sp_runtime::{ traits::{Convert, Saturating, StaticLookup, UniqueSaturatedInto}, Perbill, }; -use sp_staking::offence::{Offence, ReportOffence}; +use sp_staking::offence::Offence; use pallet_babe::BabeEquivocationOffence; use pallet_balances::Config as BalancesConfig; @@ -52,7 +52,6 @@ use pallet_staking::{ const SEED: u32 = 0; -const MAX_REPORTERS: u32 = 100; const MAX_OFFENDERS: u32 = 100; const MAX_NOMINATORS: u32 = 100; @@ -276,7 +275,7 @@ fn check_events::Event>>(expec benchmarks! { report_offence_im_online { - let r in 1 .. MAX_REPORTERS; + let r in 1 .. ::MaxReportersCount::get(); // we skip 1 offender, because in such case there is no slashing let o in 2 .. MAX_OFFENDERS; let n in 0 .. MAX_NOMINATORS.min(::MaxNominations::get()); @@ -306,7 +305,7 @@ benchmarks! { assert_eq!(System::::event_count(), 0); }: { let _ = ::ReportUnresponsiveness::report_offence( - reporters.clone(), + WeakBoundedVec::try_from(reporters.clone()).expect("We pushed less than MaxReportersCount"), offence ); } @@ -389,7 +388,7 @@ benchmarks! { // for grandpa equivocation reports the number of reporters // and offenders is always 1 - let reporters = vec![account("reporter", 1, SEED)]; + let reporters = WeakBoundedVec::try_from(vec![account("reporter", 1, SEED)]).expect("MaxReportersCount > 0"); // make sure reporters actually get rewarded Staking::::set_slash_reward_fraction(Perbill::one()); @@ -424,7 +423,7 @@ benchmarks! { // for babe equivocation reports the number of reporters // and offenders is always 1 - let reporters = vec![account("reporter", 1, SEED)]; + let reporters = WeakBoundedVec::try_from(vec![account("reporter", 1, SEED)]).expect("MaxReportersCount > 0"); // make sure reporters actually get rewarded Staking::::set_slash_reward_fraction(Perbill::one()); diff --git a/frame/offences/src/lib.rs b/frame/offences/src/lib.rs index 3392cd6e4a884..d7c7915c389a2 100644 --- a/frame/offences/src/lib.rs +++ b/frame/offences/src/lib.rs @@ -26,11 +26,16 @@ mod migration; mod mock; mod tests; -use codec::{Decode, Encode}; -use frame_support::weights::Weight; +use codec::{Decode, Encode, MaxEncodedLen}; +use frame_support::{ + pallet_prelude::Get, + traits::{OffenceDetails, OnOffenceHandler, ReportOffence}, + weights::Weight, + WeakBoundedVec, +}; use sp_runtime::{traits::Hash, Perbill}; use sp_staking::{ - offence::{Kind, Offence, OffenceDetails, OffenceError, OnOffenceHandler, ReportOffence}, + offence::{Kind, Offence, OffenceError}, SessionIndex, }; use sp_std::prelude::*; @@ -81,9 +86,16 @@ pub mod pallet { /// The overarching event type. type Event: From + IsType<::Event>; /// Full identification of the validator. - type IdentificationTuple: Parameter + Ord; + type IdentificationTuple: Parameter + Ord + MaxEncodedLen; /// A handler called for every offence report. - type OnOffenceHandler: OnOffenceHandler; + type OnOffenceHandler: OnOffenceHandler< + Self::AccountId, + Self::IdentificationTuple, + Weight, + Self::MaxReportersCount, + >; + /// Maximum number of reporters. + type MaxReportersCount: Get; } /// The primary structure that holds all offence records keyed by report identifiers. @@ -93,7 +105,7 @@ pub mod pallet { _, Twox64Concat, ReportIdOf, - OffenceDetails, + OffenceDetails, >; /// A vector of reports of the same kind that happened at the same time slot. @@ -142,11 +154,14 @@ pub mod pallet { } impl> - ReportOffence for Pallet + ReportOffence for Pallet where T::IdentificationTuple: Clone, { - fn report_offence(reporters: Vec, offence: O) -> Result<(), OffenceError> { + fn report_offence( + reporters: WeakBoundedVec, + offence: O, + ) -> Result<(), OffenceError> { let offenders = offence.offenders(); let time_slot = offence.time_slot(); let validator_set_count = offence.validator_set_count(); @@ -204,7 +219,7 @@ impl Pallet { /// Triages the offence report and returns the set of offenders that was involved in unique /// reports along with the list of the concurrent offences. fn triage_offence_report>( - reporters: Vec, + reporters: WeakBoundedVec, time_slot: &O::TimeSlot, offenders: Vec, ) -> Option> { @@ -244,7 +259,8 @@ impl Pallet { struct TriageOutcome { /// Other reports for the same report kinds. - concurrent_offenders: Vec>, + concurrent_offenders: + Vec>, } /// An auxiliary struct for working with storage of indexes localized for a specific offence diff --git a/frame/offences/src/migration.rs b/frame/offences/src/migration.rs index b6e32cbe69e26..93116118c4155 100644 --- a/frame/offences/src/migration.rs +++ b/frame/offences/src/migration.rs @@ -15,16 +15,24 @@ // See the License for the specific language governing permissions and // limitations under the License. -use super::{Config, OffenceDetails, Perbill, SessionIndex}; +use super::{Config, Perbill, SessionIndex}; use frame_support::{ - generate_storage_alias, pallet_prelude::ValueQuery, traits::Get, weights::Weight, + generate_storage_alias, + pallet_prelude::ValueQuery, + traits::{Get, OffenceDetails, OnOffenceHandler}, + weights::Weight, }; -use sp_staking::offence::OnOffenceHandler; use sp_std::vec::Vec; /// Type of data stored as a deferred offence type DeferredOffenceOf = ( - Vec::AccountId, ::IdentificationTuple>>, + Vec< + OffenceDetails< + ::AccountId, + ::IdentificationTuple, + ::MaxReportersCount, + >, + >, Vec, SessionIndex, ); diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index a426aabb0063a..2df029ef2c445 100644 --- a/frame/staking/src/lib.rs +++ b/frame/staking/src/lib.rs @@ -303,7 +303,7 @@ mod pallet; use codec::{Decode, Encode, HasCompact, MaxEncodedLen}; use frame_support::{ storage::bounded_btree_map::BoundedBTreeMap, - traits::{Currency, Get}, + traits::{Currency, Get, ReportOffence}, weights::Weight, BoundedVec, CloneNoBound, DefaultNoBound, EqNoBound, OrdNoBound, PartialEqNoBound, RuntimeDebugNoBound, WeakBoundedVec, @@ -315,7 +315,7 @@ use sp_runtime::{ Perbill, RuntimeDebug, }; use sp_staking::{ - offence::{Offence, OffenceError, ReportOffence}, + offence::{Offence, OffenceError}, SessionIndex, }; use sp_std::{ @@ -888,14 +888,18 @@ pub struct FilterHistoricalOffences { _inner: sp_std::marker::PhantomData<(T, R)>, } -impl ReportOffence - for FilterHistoricalOffences, R> +impl + ReportOffence for FilterHistoricalOffences, R> where T: Config, - R: ReportOffence, + R: ReportOffence, O: Offence, + MaxReportersCount: Get, { - fn report_offence(reporters: Vec, offence: O) -> Result<(), OffenceError> { + fn report_offence( + reporters: WeakBoundedVec, + offence: O, + ) -> Result<(), OffenceError> { // Disallow any slashing from before the current bonding period. let offence_session = offence.session_index(); let bonded_eras = BondedEras::::get(); diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index 5588cd9b399b4..2136b5980ce07 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -25,7 +25,7 @@ use frame_support::{ pallet_prelude::*, traits::{ Currency, CurrencyToVote, EstimateNextNewSession, Get, Imbalance, LockableCurrency, - OnUnbalanced, UnixTime, WithdrawReasons, + OffenceDetails, OnOffenceHandler, OnUnbalanced, UnixTime, WithdrawReasons, }, weights::{Weight, WithPostDispatchInfo}, WeakBoundedVec, @@ -36,10 +36,7 @@ use sp_runtime::{ traits::{Bounded, Convert, SaturatedConversion, Saturating, Zero}, Perbill, }; -use sp_staking::{ - offence::{OffenceDetails, OnOffenceHandler}, - SessionIndex, -}; +use sp_staking::SessionIndex; use sp_std::{collections::btree_map::BTreeMap, convert::TryFrom, prelude::*}; use crate::{ @@ -1197,8 +1194,12 @@ where /// This is intended to be used with `FilterHistoricalOffences`. impl - OnOffenceHandler, Weight> - for Pallet + OnOffenceHandler< + T::AccountId, + pallet_session::historical::IdentificationTuple, + Weight, + T::MaxReportersCount, + > for Pallet where T: pallet_session::Config::AccountId>, T: pallet_session::historical::Config< @@ -1223,6 +1224,7 @@ where offenders: &[OffenceDetails< T::AccountId, pallet_session::historical::IdentificationTuple, + T::MaxReportersCount, >], slash_fraction: &[Perbill], slash_session: SessionIndex, @@ -1306,10 +1308,7 @@ where let rw = upper_bound + nominators_len * upper_bound; add_db_reads_writes(rw, rw); } - unapplied.reporters = WeakBoundedVec::<_, T::MaxReportersCount>::force_from( - details.reporters.clone(), - Some("unapplied.reporters"), - ); + unapplied.reporters = details.reporters.clone(); if slash_defer_duration == 0 { // Apply right away. slashing::apply_slash::(unapplied); diff --git a/frame/support/src/lib.rs b/frame/support/src/lib.rs index a711fdbc3a8d8..a958c1a117641 100644 --- a/frame/support/src/lib.rs +++ b/frame/support/src/lib.rs @@ -741,7 +741,7 @@ pub use frame_support_procedural::crate_to_crate_version; #[macro_export] macro_rules! fail { ( $y:expr ) => {{ - return Err($y.into()) + return Err($y.into()); }}; } diff --git a/frame/support/src/traits.rs b/frame/support/src/traits.rs index 513267c5c8ba6..03375aff83e15 100644 --- a/frame/support/src/traits.rs +++ b/frame/support/src/traits.rs @@ -45,6 +45,9 @@ pub use validation::{ ValidatorSetWithIdentification, VerifySeal, }; +mod staking; +pub use staking::{OffenceDetails, OnOffenceHandler, ReportOffence}; + mod filter; pub use filter::{ClearFilterGuard, FilterStack, FilterStackGuard, InstanceFilter, IntegrityTest}; diff --git a/frame/support/src/traits/staking.rs b/frame/support/src/traits/staking.rs new file mode 100644 index 0000000000000..7e0e8999b6fb5 --- /dev/null +++ b/frame/support/src/traits/staking.rs @@ -0,0 +1,131 @@ +// This file is part of Substrate. + +// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Common traits and types that are useful for describing staking + +use crate::{traits::Get, WeakBoundedVec}; +use codec::{Decode, Encode, MaxEncodedLen}; +use sp_runtime::Perbill; +use sp_staking::{ + offence::{Offence, OffenceError}, + SessionIndex, +}; + +/// A trait for decoupling offence reporters from the actual handling of offence reports. +pub trait ReportOffence, MaxReportersCount: Get> { + /// Report an `offence` and reward given `reporters`. + fn report_offence( + reporters: WeakBoundedVec, + offence: O, + ) -> Result<(), OffenceError>; + + /// Returns true iff all of the given offenders have been previously reported + /// at the given time slot. This function is useful to prevent the sending of + /// duplicate offence reports. + fn is_known_offence(offenders: &[Offender], time_slot: &O::TimeSlot) -> bool; +} + +impl, MaxReportersCount: Get> + ReportOffence for () +{ + fn report_offence( + _reporters: WeakBoundedVec, + _offence: O, + ) -> Result<(), OffenceError> { + Ok(()) + } + + fn is_known_offence(_offenders: &[Offender], _time_slot: &O::TimeSlot) -> bool { + true + } +} + +/// A trait to take action on an offence. +/// +/// Used to decouple the module that handles offences and +/// the one that should punish for those offences. +pub trait OnOffenceHandler< + Reporter: MaxEncodedLen, + Offender: MaxEncodedLen, + Res, + MaxReportersCount: Get, +> +{ + /// A handler for an offence of a particular kind. + /// + /// Note that this contains a list of all previous offenders + /// as well. The implementer should cater for a case, where + /// the same authorities were reported for the same offence + /// in the past (see `OffenceCount`). + /// + /// The vector of `slash_fraction` contains `Perbill`s + /// the authorities should be slashed and is computed + /// according to the `OffenceCount` already. This is of the same length as `offenders.` + /// Zero is a valid value for a fraction. + /// + /// The `session` parameter is the session index of the offence. + /// + /// The receiver might decide to not accept this offence. In this case, the call site is + /// responsible for queuing the report and re-submitting again. + fn on_offence( + offenders: &[OffenceDetails], + slash_fraction: &[Perbill], + session: SessionIndex, + ) -> Res; +} + +impl< + Reporter: MaxEncodedLen, + Offender: MaxEncodedLen, + Res: Default, + MaxReportersCount: Get, + > OnOffenceHandler for () +{ + fn on_offence( + _offenders: &[OffenceDetails], + _slash_fraction: &[Perbill], + _session: SessionIndex, + ) -> Res { + Default::default() + } +} + +/// A details about an offending authority for a particular kind of offence. +/// `MaxReportersCount` bounds weakly the number of reporters +#[derive( + Clone, + PartialEq, + Eq, + Encode, + Decode, + MaxEncodedLen, + sp_runtime::RuntimeDebug, + scale_info::TypeInfo, +)] +#[codec(mel_bound(MaxReportersCount: Get))] +#[scale_info(skip_type_params(MaxReportersCount))] +pub struct OffenceDetails< + Reporter: MaxEncodedLen, + Offender: MaxEncodedLen, + MaxReportersCount: Get, +> { + /// The offending authority id + pub offender: Offender, + /// A list of reporters of offences of this authority ID. Possibly empty where there are no + /// particular reporters. + pub reporters: WeakBoundedVec, +} diff --git a/primitives/staking/src/offence.rs b/primitives/staking/src/offence.rs index a91cb47c117b6..de78f084e9abd 100644 --- a/primitives/staking/src/offence.rs +++ b/primitives/staking/src/offence.rs @@ -20,7 +20,6 @@ use sp_std::vec::Vec; -use codec::{Decode, Encode}; use sp_runtime::Perbill; use crate::SessionIndex; @@ -105,76 +104,7 @@ impl sp_runtime::traits::Printable for OffenceError { Self::Other(e) => { "Other".print(); e.print(); - }, + } } } } - -/// A trait for decoupling offence reporters from the actual handling of offence reports. -pub trait ReportOffence> { - /// Report an `offence` and reward given `reporters`. - fn report_offence(reporters: Vec, offence: O) -> Result<(), OffenceError>; - - /// Returns true iff all of the given offenders have been previously reported - /// at the given time slot. This function is useful to prevent the sending of - /// duplicate offence reports. - fn is_known_offence(offenders: &[Offender], time_slot: &O::TimeSlot) -> bool; -} - -impl> ReportOffence for () { - fn report_offence(_reporters: Vec, _offence: O) -> Result<(), OffenceError> { - Ok(()) - } - - fn is_known_offence(_offenders: &[Offender], _time_slot: &O::TimeSlot) -> bool { - true - } -} - -/// A trait to take action on an offence. -/// -/// Used to decouple the module that handles offences and -/// the one that should punish for those offences. -pub trait OnOffenceHandler { - /// A handler for an offence of a particular kind. - /// - /// Note that this contains a list of all previous offenders - /// as well. The implementer should cater for a case, where - /// the same authorities were reported for the same offence - /// in the past (see `OffenceCount`). - /// - /// The vector of `slash_fraction` contains `Perbill`s - /// the authorities should be slashed and is computed - /// according to the `OffenceCount` already. This is of the same length as `offenders.` - /// Zero is a valid value for a fraction. - /// - /// The `session` parameter is the session index of the offence. - /// - /// The receiver might decide to not accept this offence. In this case, the call site is - /// responsible for queuing the report and re-submitting again. - fn on_offence( - offenders: &[OffenceDetails], - slash_fraction: &[Perbill], - session: SessionIndex, - ) -> Res; -} - -impl OnOffenceHandler for () { - fn on_offence( - _offenders: &[OffenceDetails], - _slash_fraction: &[Perbill], - _session: SessionIndex, - ) -> Res { - Default::default() - } -} - -/// A details about an offending authority for a particular kind of offence. -#[derive(Clone, PartialEq, Eq, Encode, Decode, sp_runtime::RuntimeDebug, scale_info::TypeInfo)] -pub struct OffenceDetails { - /// The offending authority id - pub offender: Offender, - /// A list of reporters of offences of this authority ID. Possibly empty where there are no - /// particular reporters. - pub reporters: Vec, -} diff --git a/test-utils/runtime/src/lib.rs b/test-utils/runtime/src/lib.rs index 943c41c247f75..3008ca5e2d677 100644 --- a/test-utils/runtime/src/lib.rs +++ b/test-utils/runtime/src/lib.rs @@ -185,7 +185,7 @@ impl BlindCheckable for Extrinsic { fn check(self) -> Result { match self { Extrinsic::AuthoritiesChange(new_auth) => Ok(Extrinsic::AuthoritiesChange(new_auth)), - Extrinsic::Transfer { transfer, signature, exhaust_resources_when_not_first } => + Extrinsic::Transfer { transfer, signature, exhaust_resources_when_not_first } => { if sp_runtime::verify_encoded_lazy(&signature, &transfer, &transfer.from) { Ok(Extrinsic::Transfer { transfer, @@ -194,11 +194,13 @@ impl BlindCheckable for Extrinsic { }) } else { Err(InvalidTransaction::BadProof.into()) - }, + } + } Extrinsic::IncludeData(v) => Ok(Extrinsic::IncludeData(v)), Extrinsic::StorageChange(key, value) => Ok(Extrinsic::StorageChange(key, value)), - Extrinsic::ChangesTrieConfigUpdate(new_config) => - Ok(Extrinsic::ChangesTrieConfigUpdate(new_config)), + Extrinsic::ChangesTrieConfigUpdate(new_config) => { + Ok(Extrinsic::ChangesTrieConfigUpdate(new_config)) + } Extrinsic::OffchainIndexSet(key, value) => Ok(Extrinsic::OffchainIndexSet(key, value)), Extrinsic::OffchainIndexClear(key) => Ok(Extrinsic::OffchainIndexClear(key)), Extrinsic::Store(data) => Ok(Extrinsic::Store(data)), @@ -501,13 +503,13 @@ impl frame_support::traits::PalletInfo for Runtime { fn index() -> Option { let type_id = sp_std::any::TypeId::of::

(); if type_id == sp_std::any::TypeId::of::>() { - return Some(0) + return Some(0); } if type_id == sp_std::any::TypeId::of::>() { - return Some(1) + return Some(1); } if type_id == sp_std::any::TypeId::of::>() { - return Some(2) + return Some(2); } None @@ -515,13 +517,13 @@ impl frame_support::traits::PalletInfo for Runtime { fn name() -> Option<&'static str> { let type_id = sp_std::any::TypeId::of::

(); if type_id == sp_std::any::TypeId::of::>() { - return Some("System") + return Some("System"); } if type_id == sp_std::any::TypeId::of::>() { - return Some("Timestamp") + return Some("Timestamp"); } if type_id == sp_std::any::TypeId::of::>() { - return Some("Babe") + return Some("Babe"); } None @@ -529,13 +531,13 @@ impl frame_support::traits::PalletInfo for Runtime { fn module_name() -> Option<&'static str> { let type_id = sp_std::any::TypeId::of::

(); if type_id == sp_std::any::TypeId::of::>() { - return Some("system") + return Some("system"); } if type_id == sp_std::any::TypeId::of::>() { - return Some("pallet_timestamp") + return Some("pallet_timestamp"); } if type_id == sp_std::any::TypeId::of::>() { - return Some("pallet_babe") + return Some("pallet_babe"); } None @@ -544,13 +546,13 @@ impl frame_support::traits::PalletInfo for Runtime { use frame_support::traits::PalletInfoAccess as _; let type_id = sp_std::any::TypeId::of::

(); if type_id == sp_std::any::TypeId::of::>() { - return Some(system::Pallet::::crate_version()) + return Some(system::Pallet::::crate_version()); } if type_id == sp_std::any::TypeId::of::>() { - return Some(pallet_timestamp::Pallet::::crate_version()) + return Some(pallet_timestamp::Pallet::::crate_version()); } if type_id == sp_std::any::TypeId::of::>() { - return Some(pallet_babe::Pallet::::crate_version()) + return Some(pallet_babe::Pallet::::crate_version()); } None @@ -608,6 +610,7 @@ parameter_types! { pub const EpochDuration: u64 = 6; pub const ExpectedBlockTime: u64 = 10_000; pub const MaxAuthorities: u32 = 10; + pub const MaxReportersCount: u32 = 100; } impl pallet_babe::Config for Runtime { @@ -633,6 +636,7 @@ impl pallet_babe::Config for Runtime { type WeightInfo = (); type MaxAuthorities = MaxAuthorities; + type MaxReportersCount = MaxReportersCount; } /// Adds one to the given input and returns the final result. @@ -662,7 +666,7 @@ fn code_using_trie() -> u64 { let key: &[u8] = &v[i].0; let val: &[u8] = &v[i].1; if !t.insert(key, val).is_ok() { - return 101 + return 101; } } t From 839047124dd1ac7a9734b6cd846658f1542255f4 Mon Sep 17 00:00:00 2001 From: Georges Dib Date: Wed, 27 Oct 2021 06:20:09 +0100 Subject: [PATCH 68/80] Fixing tests --- frame/babe/src/mock.rs | 2 + frame/grandpa/src/mock.rs | 2 + frame/im-online/src/mock.rs | 18 ++-- frame/offences/src/migration.rs | 6 +- frame/offences/src/mock.rs | 19 +++- frame/offences/src/tests.rs | 54 ++++++----- frame/staking/src/mock.rs | 8 +- frame/staking/src/tests.rs | 137 +++++++++++++++++----------- frame/support/src/traits/staking.rs | 20 ++-- 9 files changed, 162 insertions(+), 104 deletions(-) diff --git a/frame/babe/src/mock.rs b/frame/babe/src/mock.rs index 347547ac4fce8..590fa88af22ca 100644 --- a/frame/babe/src/mock.rs +++ b/frame/babe/src/mock.rs @@ -245,6 +245,7 @@ impl pallet_offences::Config for Test { type Event = Event; type IdentificationTuple = pallet_session::historical::IdentificationTuple; type OnOffenceHandler = Staking; + type MaxReportersCount = MaxReportersCount; } parameter_types! { @@ -276,6 +277,7 @@ impl Config for Test { type WeightInfo = (); type MaxAuthorities = MaxAuthorities; + type MaxReportersCount = MaxReportersCount; } pub fn go_to_block(n: u64, s: u64) { diff --git a/frame/grandpa/src/mock.rs b/frame/grandpa/src/mock.rs index c5885945837a1..7b8bfd403067b 100644 --- a/frame/grandpa/src/mock.rs +++ b/frame/grandpa/src/mock.rs @@ -247,6 +247,7 @@ impl pallet_offences::Config for Test { type Event = Event; type IdentificationTuple = pallet_session::historical::IdentificationTuple; type OnOffenceHandler = Staking; + type MaxReportersCount = MaxReportersCount; } parameter_types! { @@ -274,6 +275,7 @@ impl Config for Test { type WeightInfo = (); type MaxAuthorities = MaxAuthorities; + type MaxReportersCount = MaxReportersCount; } pub fn grandpa_log(log: ConsensusLog) -> DigestItem { diff --git a/frame/im-online/src/mock.rs b/frame/im-online/src/mock.rs index 0704e33277ef8..14a6219ad7ade 100644 --- a/frame/im-online/src/mock.rs +++ b/frame/im-online/src/mock.rs @@ -21,7 +21,7 @@ use std::cell::RefCell; -use frame_support::{parameter_types, weights::Weight, BoundedVec}; +use frame_support::{parameter_types, traits::ReportOffence, weights::Weight, BoundedVec}; use pallet_session::historical as pallet_session_historical; use sp_core::H256; use sp_runtime::{ @@ -29,10 +29,7 @@ use sp_runtime::{ traits::{BlakeTwo256, ConvertInto, IdentityLookup}, Permill, }; -use sp_staking::{ - offence::{OffenceError, ReportOffence}, - SessionIndex, -}; +use sp_staking::{offence::OffenceError, SessionIndex}; use crate as imonline; use crate::{Config, TryFrom}; @@ -87,9 +84,12 @@ thread_local! { /// A mock offence report handler. pub struct OffenceHandler; -impl ReportOffence for OffenceHandler { - fn report_offence(reporters: Vec, offence: Offence) -> Result<(), OffenceError> { - OFFENCES.with(|l| l.borrow_mut().push((reporters, offence))); +impl ReportOffence for OffenceHandler { + fn report_offence( + reporters: frame_support::WeakBoundedVec, + offence: Offence, + ) -> Result<(), OffenceError> { + OFFENCES.with(|l| l.borrow_mut().push((reporters.to_vec(), offence))); Ok(()) } @@ -212,6 +212,7 @@ parameter_types! { pub const MaxKeysEncodingSize: u32 = 1_000; pub const MaxPeerInHeartbeats: u32 = 10_000; pub const MaxPeerDataEncodingSize: u32 = 1_000; + pub const MaxReportersCount: u32 = 100; } impl Config for Runtime { @@ -225,6 +226,7 @@ impl Config for Runtime { type MaxKeys = MaxKeys; type MaxPeerInHeartbeats = MaxPeerInHeartbeats; type MaxPeerDataEncodingSize = MaxPeerDataEncodingSize; + type MaxReportersCount = MaxReportersCount; } impl frame_system::offchain::SendTransactionTypes for Runtime diff --git a/frame/offences/src/migration.rs b/frame/offences/src/migration.rs index 93116118c4155..df4ff048d2bac 100644 --- a/frame/offences/src/migration.rs +++ b/frame/offences/src/migration.rs @@ -60,9 +60,8 @@ pub fn remove_deferred_storage() -> Weight { mod test { use super::*; use crate::mock::{new_test_ext, with_on_offence_fractions, Offences, Runtime as T}; - use frame_support::traits::OnRuntimeUpgrade; + use frame_support::traits::{OffenceDetails, OnRuntimeUpgrade}; use sp_runtime::Perbill; - use sp_staking::offence::OffenceDetails; #[test] fn should_resubmit_deferred_offences() { @@ -76,9 +75,10 @@ mod test { let offence_details = OffenceDetails::< ::AccountId, ::IdentificationTuple, + ::MaxReportersCount, > { offender: 5, - reporters: vec![], + reporters: Default::default(), }; // push deferred offence diff --git a/frame/offences/src/mock.rs b/frame/offences/src/mock.rs index 5e4c94944b6fd..042d02a733e95 100644 --- a/frame/offences/src/mock.rs +++ b/frame/offences/src/mock.rs @@ -21,9 +21,10 @@ use crate as offences; use crate::Config; -use codec::Encode; +use codec::{Encode, MaxEncodedLen}; use frame_support::{ parameter_types, + traits::OffenceDetails, weights::{ constants::{RocksDbWeight, WEIGHT_PER_SECOND}, Weight, @@ -36,7 +37,7 @@ use sp_runtime::{ Perbill, }; use sp_staking::{ - offence::{self, Kind, OffenceDetails}, + offence::{self, Kind}, SessionIndex, }; use std::cell::RefCell; @@ -48,11 +49,14 @@ thread_local! { pub static OFFENCE_WEIGHT: RefCell = RefCell::new(Default::default()); } -impl offence::OnOffenceHandler +impl< + Reporter: MaxEncodedLen + Eq + sp_std::fmt::Debug, + Offender: MaxEncodedLen + Eq + sp_std::fmt::Debug, + > frame_support::traits::OnOffenceHandler for OnOffenceHandler { fn on_offence( - _offenders: &[OffenceDetails], + _offenders: &[OffenceDetails], slash_fraction: &[Perbill], _offence_session: SessionIndex, ) -> Weight { @@ -84,6 +88,7 @@ frame_support::construct_runtime!( parameter_types! { pub const BlockHashCount: u64 = 250; + pub const MaxReportersCount: u32 = 100; pub BlockWeights: frame_system::limits::BlockWeights = frame_system::limits::BlockWeights::simple_max(2 * WEIGHT_PER_SECOND); } @@ -117,6 +122,7 @@ impl Config for Runtime { type Event = Event; type IdentificationTuple = u64; type OnOffenceHandler = OnOffenceHandler; + type MaxReportersCount = MaxReportersCount; } pub fn new_test_ext() -> sp_io::TestExternalities { @@ -129,7 +135,10 @@ pub fn new_test_ext() -> sp_io::TestExternalities { pub const KIND: [u8; 16] = *b"test_report_1234"; /// Returns all offence details for the specific `kind` happened at the specific time slot. -pub fn offence_reports(kind: Kind, time_slot: u128) -> Vec> { +pub fn offence_reports( + kind: Kind, + time_slot: u128, +) -> Vec> { >::get(&kind, &time_slot.encode()) .into_iter() .map(|report_id| { diff --git a/frame/offences/src/tests.rs b/frame/offences/src/tests.rs index 18cfa9410a6c6..bf1e3d6216116 100644 --- a/frame/offences/src/tests.rs +++ b/frame/offences/src/tests.rs @@ -19,6 +19,8 @@ #![cfg(test)] +use std::rc::Weak; + use super::*; use crate::mock::{ new_test_ext, offence_reports, report_id, with_on_offence_fractions, Event, Offence, Offences, @@ -37,7 +39,7 @@ fn should_report_an_authority_and_trigger_on_offence() { let offence = Offence { validator_set_count: 5, time_slot, offenders: vec![5] }; // when - Offences::report_offence(vec![], offence).unwrap(); + Offences::report_offence(Default::default(), offence).unwrap(); // then with_on_offence_fractions(|f| { @@ -54,7 +56,7 @@ fn should_not_report_the_same_authority_twice_in_the_same_slot() { assert_eq!(offence_reports(KIND, time_slot), vec![]); let offence = Offence { validator_set_count: 5, time_slot, offenders: vec![5] }; - Offences::report_offence(vec![], offence.clone()).unwrap(); + Offences::report_offence(Default::default(), offence.clone()).unwrap(); with_on_offence_fractions(|f| { assert_eq!(f.clone(), vec![Perbill::from_percent(25)]); f.clear(); @@ -62,7 +64,10 @@ fn should_not_report_the_same_authority_twice_in_the_same_slot() { // when // report for the second time - assert_eq!(Offences::report_offence(vec![], offence), Err(OffenceError::DuplicateReport)); + assert_eq!( + Offences::report_offence(Default::default(), offence), + Err(OffenceError::DuplicateReport) + ); // then with_on_offence_fractions(|f| { @@ -79,7 +84,7 @@ fn should_report_in_different_time_slot() { assert_eq!(offence_reports(KIND, time_slot), vec![]); let mut offence = Offence { validator_set_count: 5, time_slot, offenders: vec![5] }; - Offences::report_offence(vec![], offence.clone()).unwrap(); + Offences::report_offence(Default::default(), offence.clone()).unwrap(); with_on_offence_fractions(|f| { assert_eq!(f.clone(), vec![Perbill::from_percent(25)]); f.clear(); @@ -88,7 +93,7 @@ fn should_report_in_different_time_slot() { // when // report for the second time offence.time_slot += 1; - Offences::report_offence(vec![], offence).unwrap(); + Offences::report_offence(Default::default(), offence).unwrap(); // then with_on_offence_fractions(|f| { @@ -107,7 +112,7 @@ fn should_deposit_event() { let offence = Offence { validator_set_count: 5, time_slot, offenders: vec![5] }; // when - Offences::report_offence(vec![], offence).unwrap(); + Offences::report_offence(Default::default(), offence).unwrap(); // then assert_eq!( @@ -129,7 +134,7 @@ fn doesnt_deposit_event_for_dups() { assert_eq!(offence_reports(KIND, time_slot), vec![]); let offence = Offence { validator_set_count: 5, time_slot, offenders: vec![5] }; - Offences::report_offence(vec![], offence.clone()).unwrap(); + Offences::report_offence(Default::default(), offence.clone()).unwrap(); with_on_offence_fractions(|f| { assert_eq!(f.clone(), vec![Perbill::from_percent(25)]); f.clear(); @@ -137,7 +142,10 @@ fn doesnt_deposit_event_for_dups() { // when // report for the second time - assert_eq!(Offences::report_offence(vec![], offence), Err(OffenceError::DuplicateReport)); + assert_eq!( + Offences::report_offence(Default::default(), offence), + Err(OffenceError::DuplicateReport) + ); // then // there is only one event. @@ -167,23 +175,23 @@ fn reports_if_an_offence_is_dup() { // the report for authority 0 at time slot 42 should not be a known // offence - assert!(!>::is_known_offence( + assert!(!>::is_known_offence( &test_offence.offenders, &test_offence.time_slot )); // we report an offence for authority 0 at time slot 42 - Offences::report_offence(vec![], test_offence.clone()).unwrap(); + Offences::report_offence(Default::default(), test_offence.clone()).unwrap(); // the same report should be a known offence now - assert!(>::is_known_offence( + assert!(>::is_known_offence( &test_offence.offenders, &test_offence.time_slot )); // and reporting it again should yield a duplicate report error assert_eq!( - Offences::report_offence(vec![], test_offence.clone()), + Offences::report_offence(Default::default(), test_offence.clone()), Err(OffenceError::DuplicateReport) ); @@ -191,18 +199,18 @@ fn reports_if_an_offence_is_dup() { test_offence.offenders.push(1); // it should not be a known offence anymore - assert!(!>::is_known_offence( + assert!(!>::is_known_offence( &test_offence.offenders, &test_offence.time_slot )); // and reporting it again should work without any error - assert_eq!(Offences::report_offence(vec![], test_offence.clone()), Ok(())); + assert_eq!(Offences::report_offence(Default::default(), test_offence.clone()), Ok(())); // creating a new offence for the same authorities on the next slot // should be considered a new offence and thefore not known let test_offence_next_slot = offence(time_slot + 1, vec![0, 1]); - assert!(!>::is_known_offence( + assert!(!>::is_known_offence( &test_offence_next_slot.offenders, &test_offence_next_slot.time_slot )); @@ -220,7 +228,7 @@ fn should_properly_count_offences() { let offence1 = Offence { validator_set_count: 5, time_slot, offenders: vec![5] }; let offence2 = Offence { validator_set_count: 5, time_slot, offenders: vec![4] }; - Offences::report_offence(vec![], offence1).unwrap(); + Offences::report_offence(Default::default(), offence1).unwrap(); with_on_offence_fractions(|f| { assert_eq!(f.clone(), vec![Perbill::from_percent(25)]); f.clear(); @@ -228,15 +236,15 @@ fn should_properly_count_offences() { // when // report for the second time - Offences::report_offence(vec![], offence2).unwrap(); + Offences::report_offence(Default::default(), offence2).unwrap(); // then // the 1st authority should have count 2 and the 2nd one should be reported only once. assert_eq!( offence_reports(KIND, time_slot), vec![ - OffenceDetails { offender: 5, reporters: vec![] }, - OffenceDetails { offender: 4, reporters: vec![] }, + OffenceDetails { offender: 5, reporters: Default::default() }, + OffenceDetails { offender: 4, reporters: Default::default() }, ] ); }); @@ -257,7 +265,7 @@ fn should_properly_sort_offences() { Offence { validator_set_count: 5, time_slot: time_slot + 1, offenders: vec![6, 7] }; let offence4 = Offence { validator_set_count: 5, time_slot: time_slot - 1, offenders: vec![3] }; - Offences::report_offence(vec![], offence1).unwrap(); + Offences::report_offence(Default::default(), offence1).unwrap(); with_on_offence_fractions(|f| { assert_eq!(f.clone(), vec![Perbill::from_percent(25)]); f.clear(); @@ -265,9 +273,9 @@ fn should_properly_sort_offences() { // when // report for the second time - Offences::report_offence(vec![], offence2).unwrap(); - Offences::report_offence(vec![], offence3).unwrap(); - Offences::report_offence(vec![], offence4).unwrap(); + Offences::report_offence(Default::default(), offence2).unwrap(); + Offences::report_offence(Default::default(), offence3).unwrap(); + Offences::report_offence(Default::default(), offence4).unwrap(); // then let same_kind_reports = Vec::<(u128, sp_core::H256)>::decode( diff --git a/frame/staking/src/mock.rs b/frame/staking/src/mock.rs index 4d25bc94a6e53..d9b40b61c6296 100644 --- a/frame/staking/src/mock.rs +++ b/frame/staking/src/mock.rs @@ -22,7 +22,8 @@ use frame_election_provider_support::{onchain, SortedListProvider}; use frame_support::{ assert_ok, parameter_types, traits::{ - Currency, FindAuthor, GenesisBuild, Get, Hooks, Imbalance, OnUnbalanced, OneSessionHandler, + Currency, FindAuthor, GenesisBuild, Get, Hooks, Imbalance, OffenceDetails, + OnOffenceHandler, OnUnbalanced, OneSessionHandler, }, weights::constants::RocksDbWeight, }; @@ -33,7 +34,6 @@ use sp_runtime::{ testing::{Header, TestXt, UintAuthorityId}, traits::{IdentityLookup, Zero}, }; -use sp_staking::offence::{OffenceDetails, OnOffenceHandler}; use sp_std::collections::btree_map::BTreeMap; use std::cell::RefCell; @@ -784,6 +784,7 @@ pub(crate) fn on_offence_in_era( offenders: &[OffenceDetails< AccountId, pallet_session::historical::IdentificationTuple, + MaxReportersCount, >], slash_fraction: &[Perbill], era: EraIndex, @@ -813,6 +814,7 @@ pub(crate) fn on_offence_now( offenders: &[OffenceDetails< AccountId, pallet_session::historical::IdentificationTuple, + MaxReportersCount, >], slash_fraction: &[Perbill], ) { @@ -824,7 +826,7 @@ pub(crate) fn add_slash(who: &AccountId) { on_offence_now( &[OffenceDetails { offender: (who.clone(), Staking::eras_stakers(active_era(), who.clone())), - reporters: vec![], + reporters: Default::default(), }], &[Perbill::from_percent(10)], ); diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index 8c9eda62c918e..8efc642260e20 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -23,7 +23,7 @@ use frame_support::{ assert_noop, assert_ok, dispatch::WithPostDispatchInfo, pallet_prelude::*, - traits::{Currency, Get, ReservableCurrency}, + traits::{Currency, Get, OffenceDetails, OnOffenceHandler, ReservableCurrency}, weights::{extract_actual_weight, GetDispatchInfo}, }; use mock::*; @@ -33,10 +33,7 @@ use sp_runtime::{ traits::{BadOrigin, Dispatchable}, Perbill, Percent, }; -use sp_staking::{ - offence::{OffenceDetails, OnOffenceHandler}, - SessionIndex, -}; +use sp_staking::SessionIndex; use sp_std::{collections::btree_map::BTreeMap, prelude::*}; use substrate_test_utils::assert_eq_uvec; @@ -631,7 +628,10 @@ fn nominators_also_get_slashed_pro_rata() { // 11 goes offline on_offence_now( - &[OffenceDetails { offender: (11, initial_exposure.clone()), reporters: vec![] }], + &[OffenceDetails { + offender: (11, initial_exposure.clone()), + reporters: Default::default(), + }], &[slash_percent], ); @@ -2175,7 +2175,7 @@ fn reward_validator_slashing_validator_does_not_overflow() { on_offence_now( &[OffenceDetails { offender: (11, Staking::eras_stakers(active_era(), 11)), - reporters: vec![], + reporters: Default::default(), }], &[Perbill::from_percent(100)], ); @@ -2290,7 +2290,7 @@ fn offence_forces_new_era() { on_offence_now( &[OffenceDetails { offender: (11, Staking::eras_stakers(active_era(), 11)), - reporters: vec![], + reporters: Default::default(), }], &[Perbill::from_percent(5)], ); @@ -2308,7 +2308,7 @@ fn offence_ensures_new_era_without_clobbering() { on_offence_now( &[OffenceDetails { offender: (11, Staking::eras_stakers(active_era(), 11)), - reporters: vec![], + reporters: Default::default(), }], &[Perbill::from_percent(5)], ); @@ -2326,7 +2326,7 @@ fn offence_deselects_validator_even_when_slash_is_zero() { on_offence_now( &[OffenceDetails { offender: (11, Staking::eras_stakers(active_era(), 11)), - reporters: vec![], + reporters: Default::default(), }], &[Perbill::from_percent(0)], ); @@ -2352,7 +2352,7 @@ fn slashing_performed_according_exposure() { on_offence_now( &[OffenceDetails { offender: (11, Exposure { total: 500, own: 500, others: Default::default() }), - reporters: vec![], + reporters: Default::default(), }], &[Perbill::from_percent(50)], ); @@ -2373,7 +2373,7 @@ fn slash_in_old_span_does_not_deselect() { on_offence_now( &[OffenceDetails { offender: (11, Staking::eras_stakers(active_era(), 11)), - reporters: vec![], + reporters: Default::default(), }], &[Perbill::from_percent(0)], ); @@ -2396,7 +2396,7 @@ fn slash_in_old_span_does_not_deselect() { on_offence_in_era( &[OffenceDetails { offender: (11, Staking::eras_stakers(active_era(), 11)), - reporters: vec![], + reporters: Default::default(), }], &[Perbill::from_percent(0)], 1, @@ -2411,7 +2411,7 @@ fn slash_in_old_span_does_not_deselect() { on_offence_in_era( &[OffenceDetails { offender: (11, Staking::eras_stakers(active_era(), 11)), - reporters: vec![], + reporters: Default::default(), }], // NOTE: A 100% slash here would clean up the account, causing de-registration. &[Perbill::from_percent(95)], @@ -2441,7 +2441,8 @@ fn reporters_receive_their_slice() { on_offence_now( &[OffenceDetails { offender: (11, Staking::eras_stakers(active_era(), 11)), - reporters: vec![1, 2], + reporters: WeakBoundedVec::<_, _>::try_from(vec![1, 2]) + .expect("MaxReportersCount >= 2"), }], &[Perbill::from_percent(50)], ); @@ -2468,7 +2469,8 @@ fn subsequent_reports_in_same_span_pay_out_less() { on_offence_now( &[OffenceDetails { offender: (11, Staking::eras_stakers(active_era(), 11)), - reporters: vec![1], + reporters: WeakBoundedVec::<_, _>::try_from(vec![1]) + .expect("MaxReportersCount >= 1"), }], &[Perbill::from_percent(20)], ); @@ -2481,7 +2483,8 @@ fn subsequent_reports_in_same_span_pay_out_less() { on_offence_now( &[OffenceDetails { offender: (11, Staking::eras_stakers(active_era(), 11)), - reporters: vec![1], + reporters: WeakBoundedVec::<_, _>::try_from(vec![1]) + .expect("MaxReportersCount >= 1"), }], &[Perbill::from_percent(50)], ); @@ -2512,11 +2515,11 @@ fn invulnerables_are_not_slashed() { &[ OffenceDetails { offender: (11, Staking::eras_stakers(active_era(), 11)), - reporters: vec![], + reporters: Default::default(), }, OffenceDetails { offender: (21, Staking::eras_stakers(active_era(), 21)), - reporters: vec![], + reporters: Default::default(), }, ], &[Perbill::from_percent(50), Perbill::from_percent(20)], @@ -2546,7 +2549,7 @@ fn dont_slash_if_fraction_is_zero() { on_offence_now( &[OffenceDetails { offender: (11, Staking::eras_stakers(active_era(), 11)), - reporters: vec![], + reporters: Default::default(), }], &[Perbill::from_percent(0)], ); @@ -2567,7 +2570,7 @@ fn only_slash_for_max_in_era() { on_offence_now( &[OffenceDetails { offender: (11, Staking::eras_stakers(active_era(), 11)), - reporters: vec![], + reporters: Default::default(), }], &[Perbill::from_percent(50)], ); @@ -2579,7 +2582,7 @@ fn only_slash_for_max_in_era() { on_offence_now( &[OffenceDetails { offender: (11, Staking::eras_stakers(active_era(), 11)), - reporters: vec![], + reporters: Default::default(), }], &[Perbill::from_percent(25)], ); @@ -2590,7 +2593,7 @@ fn only_slash_for_max_in_era() { on_offence_now( &[OffenceDetails { offender: (11, Staking::eras_stakers(active_era(), 11)), - reporters: vec![], + reporters: Default::default(), }], &[Perbill::from_percent(60)], ); @@ -2612,7 +2615,7 @@ fn garbage_collection_after_slashing() { on_offence_now( &[OffenceDetails { offender: (11, Staking::eras_stakers(active_era(), 11)), - reporters: vec![], + reporters: Default::default(), }], &[Perbill::from_percent(10)], ); @@ -2624,7 +2627,7 @@ fn garbage_collection_after_slashing() { on_offence_now( &[OffenceDetails { offender: (11, Staking::eras_stakers(active_era(), 11)), - reporters: vec![], + reporters: Default::default(), }], &[Perbill::from_percent(100)], ); @@ -2665,7 +2668,10 @@ fn garbage_collection_on_window_pruning() { let nominated_value = exposure.others.iter().find(|o| o.who == 101).unwrap().value; on_offence_now( - &[OffenceDetails { offender: (11, Staking::eras_stakers(now, 11)), reporters: vec![] }], + &[OffenceDetails { + offender: (11, Staking::eras_stakers(now, 11)), + reporters: Default::default(), + }], &[Perbill::from_percent(10)], ); @@ -2708,7 +2714,7 @@ fn slashing_nominators_by_span_max() { on_offence_in_era( &[OffenceDetails { offender: (11, Staking::eras_stakers(active_era(), 11)), - reporters: vec![], + reporters: Default::default(), }], &[Perbill::from_percent(10)], 2, @@ -2734,7 +2740,7 @@ fn slashing_nominators_by_span_max() { on_offence_in_era( &[OffenceDetails { offender: (21, Staking::eras_stakers(active_era(), 21)), - reporters: vec![], + reporters: Default::default(), }], &[Perbill::from_percent(30)], 3, @@ -2755,7 +2761,7 @@ fn slashing_nominators_by_span_max() { on_offence_in_era( &[OffenceDetails { offender: (11, Staking::eras_stakers(active_era(), 11)), - reporters: vec![], + reporters: Default::default(), }], &[Perbill::from_percent(20)], 2, @@ -2789,7 +2795,7 @@ fn slashes_are_summed_across_spans() { on_offence_now( &[OffenceDetails { offender: (21, Staking::eras_stakers(active_era(), 21)), - reporters: vec![], + reporters: Default::default(), }], &[Perbill::from_percent(10)], ); @@ -2812,7 +2818,7 @@ fn slashes_are_summed_across_spans() { on_offence_now( &[OffenceDetails { offender: (21, Staking::eras_stakers(active_era(), 21)), - reporters: vec![], + reporters: Default::default(), }], &[Perbill::from_percent(10)], ); @@ -2842,7 +2848,7 @@ fn deferred_slashes_are_deferred() { on_offence_now( &[OffenceDetails { offender: (11, Staking::eras_stakers(active_era(), 11)), - reporters: vec![], + reporters: Default::default(), }], &[Perbill::from_percent(10)], ); @@ -2881,7 +2887,7 @@ fn remove_deferred() { let nominated_value = exposure.others.iter().find(|o| o.who == 101).unwrap().value; on_offence_now( - &[OffenceDetails { offender: (11, exposure.clone()), reporters: vec![] }], + &[OffenceDetails { offender: (11, exposure.clone()), reporters: Default::default() }], &[Perbill::from_percent(10)], ); @@ -2891,7 +2897,7 @@ fn remove_deferred() { mock::start_active_era(2); on_offence_in_era( - &[OffenceDetails { offender: (11, exposure.clone()), reporters: vec![] }], + &[OffenceDetails { offender: (11, exposure.clone()), reporters: Default::default() }], &[Perbill::from_percent(15)], 1, ); @@ -2946,30 +2952,30 @@ fn remove_multi_deferred() { assert_eq!(Balances::free_balance(101), 2000); on_offence_now( - &[OffenceDetails { offender: (11, exposure.clone()), reporters: vec![] }], + &[OffenceDetails { offender: (11, exposure.clone()), reporters: Default::default() }], &[Perbill::from_percent(10)], ); on_offence_now( &[OffenceDetails { offender: (21, Staking::eras_stakers(active_era(), 21)), - reporters: vec![], + reporters: Default::default(), }], &[Perbill::from_percent(10)], ); on_offence_now( - &[OffenceDetails { offender: (11, exposure.clone()), reporters: vec![] }], + &[OffenceDetails { offender: (11, exposure.clone()), reporters: Default::default() }], &[Perbill::from_percent(25)], ); on_offence_now( - &[OffenceDetails { offender: (42, exposure.clone()), reporters: vec![] }], + &[OffenceDetails { offender: (42, exposure.clone()), reporters: Default::default() }], &[Perbill::from_percent(25)], ); on_offence_now( - &[OffenceDetails { offender: (69, exposure.clone()), reporters: vec![] }], + &[OffenceDetails { offender: (69, exposure.clone()), reporters: Default::default() }], &[Perbill::from_percent(25)], ); @@ -3018,7 +3024,10 @@ fn slash_kicks_validators_not_nominators_and_disables_nominator_for_kicked_valid assert_eq!(exposure_21.total, 1000 + 375); on_offence_now( - &[OffenceDetails { offender: (11, exposure_11.clone()), reporters: vec![] }], + &[OffenceDetails { + offender: (11, exposure_11.clone()), + reporters: Default::default(), + }], &[Perbill::from_percent(10)], ); @@ -3066,13 +3075,19 @@ fn non_slashable_offence_doesnt_disable_validator() { // offence with no slash associated on_offence_now( - &[OffenceDetails { offender: (11, exposure_11.clone()), reporters: vec![] }], + &[OffenceDetails { + offender: (11, exposure_11.clone()), + reporters: Default::default(), + }], &[Perbill::zero()], ); // offence that slashes 25% of the bond on_offence_now( - &[OffenceDetails { offender: (21, exposure_21.clone()), reporters: vec![] }], + &[OffenceDetails { + offender: (21, exposure_21.clone()), + reporters: Default::default(), + }], &[Perbill::from_percent(25)], ); @@ -3105,21 +3120,30 @@ fn offence_threshold_triggers_new_era() { let exposure_31 = Staking::eras_stakers(Staking::active_era().unwrap().index, &31); on_offence_now( - &[OffenceDetails { offender: (11, exposure_11.clone()), reporters: vec![] }], + &[OffenceDetails { + offender: (11, exposure_11.clone()), + reporters: Default::default(), + }], &[Perbill::zero()], ); assert_eq!(ForceEra::::get(), Forcing::NotForcing); on_offence_now( - &[OffenceDetails { offender: (21, exposure_21.clone()), reporters: vec![] }], + &[OffenceDetails { + offender: (21, exposure_21.clone()), + reporters: Default::default(), + }], &[Perbill::zero()], ); assert_eq!(ForceEra::::get(), Forcing::NotForcing); on_offence_now( - &[OffenceDetails { offender: (31, exposure_31.clone()), reporters: vec![] }], + &[OffenceDetails { + offender: (31, exposure_31.clone()), + reporters: Default::default(), + }], &[Perbill::zero()], ); @@ -3141,12 +3165,18 @@ fn disabled_validators_are_kept_disabled_for_whole_era() { let exposure_21 = Staking::eras_stakers(Staking::active_era().unwrap().index, &21); on_offence_now( - &[OffenceDetails { offender: (11, exposure_11.clone()), reporters: vec![] }], + &[OffenceDetails { + offender: (11, exposure_11.clone()), + reporters: Default::default(), + }], &[Perbill::zero()], ); on_offence_now( - &[OffenceDetails { offender: (21, exposure_21.clone()), reporters: vec![] }], + &[OffenceDetails { + offender: (21, exposure_21.clone()), + reporters: Default::default(), + }], &[Perbill::from_percent(25)], ); @@ -3163,7 +3193,10 @@ fn disabled_validators_are_kept_disabled_for_whole_era() { // validator 10 should now get disabled on_offence_now( - &[OffenceDetails { offender: (11, exposure_11.clone()), reporters: vec![] }], + &[OffenceDetails { + offender: (11, exposure_11.clone()), + reporters: Default::default(), + }], &[Perbill::from_percent(25)], ); @@ -3276,7 +3309,7 @@ fn zero_slash_keeps_nominators() { assert_eq!(Balances::free_balance(101), 2000); on_offence_now( - &[OffenceDetails { offender: (11, exposure.clone()), reporters: vec![] }], + &[OffenceDetails { offender: (11, exposure.clone()), reporters: Default::default() }], &[Perbill::from_percent(0)], ); @@ -3769,11 +3802,11 @@ fn offences_weight_calculated_correctly() { let n_offence_unapplied_weight = ::DbWeight::get().reads_writes(4, 1) + ::DbWeight::get().reads_writes(4, 5); - let offenders: Vec::AccountId, pallet_session::historical::IdentificationTuple>> + let offenders: Vec::AccountId, pallet_session::historical::IdentificationTuple, _>> = (1..10).map(|i| OffenceDetails { offender: (i, Staking::eras_stakers(active_era(), i)), - reporters: vec![], + reporters: Default::default(), } ).collect(); assert_eq!(Staking::on_offence(&offenders, &[Perbill::from_percent(50)], 0), n_offence_unapplied_weight); @@ -3782,7 +3815,7 @@ fn offences_weight_calculated_correctly() { let one_offender = [ OffenceDetails { offender: (11, Staking::eras_stakers(active_era(), 11)), - reporters: vec![1], + reporters: WeakBoundedVec::<_, _>::try_from(vec![1]).expect("MaxReportersCount > 0"), }, ]; diff --git a/frame/support/src/traits/staking.rs b/frame/support/src/traits/staking.rs index 7e0e8999b6fb5..6f746cbf23784 100644 --- a/frame/support/src/traits/staking.rs +++ b/frame/support/src/traits/staking.rs @@ -17,7 +17,7 @@ //! Common traits and types that are useful for describing staking -use crate::{traits::Get, WeakBoundedVec}; +use crate::{traits::Get, EqNoBound, PartialEqNoBound, WeakBoundedVec}; use codec::{Decode, Encode, MaxEncodedLen}; use sp_runtime::Perbill; use sp_staking::{ @@ -59,8 +59,8 @@ impl, MaxReportersCount: Get> /// Used to decouple the module that handles offences and /// the one that should punish for those offences. pub trait OnOffenceHandler< - Reporter: MaxEncodedLen, - Offender: MaxEncodedLen, + Reporter: MaxEncodedLen + Eq + sp_std::fmt::Debug, + Offender: MaxEncodedLen + Eq + sp_std::fmt::Debug, Res, MaxReportersCount: Get, > @@ -89,8 +89,8 @@ pub trait OnOffenceHandler< } impl< - Reporter: MaxEncodedLen, - Offender: MaxEncodedLen, + Reporter: MaxEncodedLen + Eq + sp_std::fmt::Debug, + Offender: MaxEncodedLen + Eq + sp_std::fmt::Debug, Res: Default, MaxReportersCount: Get, > OnOffenceHandler for () @@ -108,19 +108,19 @@ impl< /// `MaxReportersCount` bounds weakly the number of reporters #[derive( Clone, - PartialEq, - Eq, + PartialEqNoBound, + EqNoBound, Encode, Decode, MaxEncodedLen, - sp_runtime::RuntimeDebug, + frame_support::RuntimeDebugNoBound, scale_info::TypeInfo, )] #[codec(mel_bound(MaxReportersCount: Get))] #[scale_info(skip_type_params(MaxReportersCount))] pub struct OffenceDetails< - Reporter: MaxEncodedLen, - Offender: MaxEncodedLen, + Reporter: MaxEncodedLen + Eq + sp_std::fmt::Debug, + Offender: MaxEncodedLen + Eq + sp_std::fmt::Debug, MaxReportersCount: Get, > { /// The offending authority id From c32addbafa4c050783343416114e791d847b8699 Mon Sep 17 00:00:00 2001 From: Georges Dib Date: Wed, 27 Oct 2021 06:30:50 +0100 Subject: [PATCH 69/80] Changing `Clone` to `CloneNoBound` --- frame/support/src/traits/staking.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/frame/support/src/traits/staking.rs b/frame/support/src/traits/staking.rs index 6f746cbf23784..10b2e1c19c9e7 100644 --- a/frame/support/src/traits/staking.rs +++ b/frame/support/src/traits/staking.rs @@ -17,7 +17,7 @@ //! Common traits and types that are useful for describing staking -use crate::{traits::Get, EqNoBound, PartialEqNoBound, WeakBoundedVec}; +use crate::{traits::Get, CloneNoBound, EqNoBound, PartialEqNoBound, WeakBoundedVec}; use codec::{Decode, Encode, MaxEncodedLen}; use sp_runtime::Perbill; use sp_staking::{ @@ -59,8 +59,8 @@ impl, MaxReportersCount: Get> /// Used to decouple the module that handles offences and /// the one that should punish for those offences. pub trait OnOffenceHandler< - Reporter: MaxEncodedLen + Eq + sp_std::fmt::Debug, - Offender: MaxEncodedLen + Eq + sp_std::fmt::Debug, + Reporter: MaxEncodedLen + Clone + Eq + sp_std::fmt::Debug, + Offender: MaxEncodedLen + Clone + Eq + sp_std::fmt::Debug, Res, MaxReportersCount: Get, > @@ -89,8 +89,8 @@ pub trait OnOffenceHandler< } impl< - Reporter: MaxEncodedLen + Eq + sp_std::fmt::Debug, - Offender: MaxEncodedLen + Eq + sp_std::fmt::Debug, + Reporter: MaxEncodedLen + Clone + Eq + sp_std::fmt::Debug, + Offender: MaxEncodedLen + Clone + Eq + sp_std::fmt::Debug, Res: Default, MaxReportersCount: Get, > OnOffenceHandler for () @@ -107,7 +107,7 @@ impl< /// A details about an offending authority for a particular kind of offence. /// `MaxReportersCount` bounds weakly the number of reporters #[derive( - Clone, + CloneNoBound, PartialEqNoBound, EqNoBound, Encode, @@ -119,8 +119,8 @@ impl< #[codec(mel_bound(MaxReportersCount: Get))] #[scale_info(skip_type_params(MaxReportersCount))] pub struct OffenceDetails< - Reporter: MaxEncodedLen + Eq + sp_std::fmt::Debug, - Offender: MaxEncodedLen + Eq + sp_std::fmt::Debug, + Reporter: MaxEncodedLen + Clone + Eq + sp_std::fmt::Debug, + Offender: MaxEncodedLen + Clone + Eq + sp_std::fmt::Debug, MaxReportersCount: Get, > { /// The offending authority id From 5910f5fead91568663efd9bc14391b5cdea092b9 Mon Sep 17 00:00:00 2001 From: Georges Dib Date: Wed, 27 Oct 2021 06:33:44 +0100 Subject: [PATCH 70/80] Fixing test after change to `CloneNoBound` --- frame/offences/src/mock.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frame/offences/src/mock.rs b/frame/offences/src/mock.rs index 042d02a733e95..925f72a4c7a34 100644 --- a/frame/offences/src/mock.rs +++ b/frame/offences/src/mock.rs @@ -50,8 +50,8 @@ thread_local! { } impl< - Reporter: MaxEncodedLen + Eq + sp_std::fmt::Debug, - Offender: MaxEncodedLen + Eq + sp_std::fmt::Debug, + Reporter: MaxEncodedLen + Clone + Eq + sp_std::fmt::Debug, + Offender: MaxEncodedLen + Clone + Eq + sp_std::fmt::Debug, > frame_support::traits::OnOffenceHandler for OnOffenceHandler { From daaa48fd02c7c389ed93579b0f71eca97569337c Mon Sep 17 00:00:00 2001 From: Georges Dib Date: Wed, 27 Oct 2021 06:37:17 +0100 Subject: [PATCH 71/80] Adding missing `MaxReportersCount` --- frame/offences/benchmarking/src/mock.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/frame/offences/benchmarking/src/mock.rs b/frame/offences/benchmarking/src/mock.rs index 38719b3ac80e0..018893a4b11fd 100644 --- a/frame/offences/benchmarking/src/mock.rs +++ b/frame/offences/benchmarking/src/mock.rs @@ -213,12 +213,14 @@ impl pallet_im_online::Config for Test { type MaxKeys = MaxValidatorsCount; type MaxPeerInHeartbeats = MaxPeerInHeartbeats; type MaxPeerDataEncodingSize = MaxPeerDataEncodingSize; + type MaxReportersCount = MaxReportersCount; } impl pallet_offences::Config for Test { type Event = Event; type IdentificationTuple = pallet_session::historical::IdentificationTuple; type OnOffenceHandler = Staking; + type MaxReportersCount = MaxReportersCount; } impl frame_system::offchain::SendTransactionTypes for Test From c5a3ac500fe7a9b4ab371eea95868572168182d2 Mon Sep 17 00:00:00 2001 From: Georges Dib Date: Sat, 30 Oct 2021 18:17:54 +0100 Subject: [PATCH 72/80] Changing `BoundedVec` to `WeakBoundedVec` in session pallet. This is done so that it's less restrictive on cumulus when using `SessionManager` Moving implementation of `map_collect` to `WeakBoundedVec` Adding tests for `map_collect` and `map_collect_ref` --- frame/session/src/historical/mod.rs | 12 +++---- frame/session/src/lib.rs | 25 ++++++++------ frame/session/src/mock.rs | 16 +++++---- frame/staking/src/pallet/impls.rs | 34 ++++++++----------- frame/support/src/storage/bounded_vec.rs | 18 ---------- frame/support/src/storage/weak_bounded_vec.rs | 34 +++++++++++++++++++ 6 files changed, 78 insertions(+), 61 deletions(-) diff --git a/frame/session/src/historical/mod.rs b/frame/session/src/historical/mod.rs index ef99ba96b5c32..280c0abb90ed9 100644 --- a/frame/session/src/historical/mod.rs +++ b/frame/session/src/historical/mod.rs @@ -31,7 +31,7 @@ use codec::{Decode, Encode}; use frame_support::{ decl_module, decl_storage, print, traits::{ValidatorSet, ValidatorSetWithIdentification}, - BoundedVec, Parameter, + Parameter, WeakBoundedVec, }; use sp_runtime::{ traits::{Convert, OpaqueKeys}, @@ -136,10 +136,10 @@ pub trait SessionManager: /// full identifications. fn new_session( new_index: SessionIndex, - ) -> Option>; + ) -> Option>; fn new_session_genesis( new_index: SessionIndex, - ) -> Option> { + ) -> Option> { >::new_session(new_index) } fn start_session(start_index: SessionIndex); @@ -158,7 +158,7 @@ impl< fn do_new_session( new_index: SessionIndex, is_genesis: bool, - ) -> Option> { + ) -> Option> { StoredRange::mutate(|range| { range.get_or_insert_with(|| (new_index, new_index)).1 = new_index + 1; }); @@ -199,13 +199,13 @@ where { fn new_session( new_index: SessionIndex, - ) -> Option> { + ) -> Option> { Self::do_new_session(new_index, false) } fn new_session_genesis( new_index: SessionIndex, - ) -> Option> { + ) -> Option> { Self::do_new_session(new_index, true) } diff --git a/frame/session/src/lib.rs b/frame/session/src/lib.rs index eda1665021a6b..e2b2f5ab58470 100644 --- a/frame/session/src/lib.rs +++ b/frame/session/src/lib.rs @@ -123,7 +123,7 @@ use frame_support::{ StorageVersion, ValidatorRegistration, ValidatorSet, }, weights::Weight, - BoundedVec, Parameter, WeakBoundedVec, + Parameter, WeakBoundedVec, }; use sp_runtime::{ traits::{AtLeast32BitUnsigned, Convert, Member, One, OpaqueKeys, Zero}, @@ -238,14 +238,16 @@ pub trait SessionManager { /// /// `new_session(session)` is guaranteed to be called before `end_session(session-1)`. In other /// words, a new session must always be planned before an ongoing one can be finished. - fn new_session(new_index: SessionIndex) -> Option>; + fn new_session( + new_index: SessionIndex, + ) -> Option>; /// Same as `new_session`, but it this should only be called at genesis. /// /// The session manager might decide to treat this in a different way. Default impl is simply /// using [`new_session`](Self::new_session). fn new_session_genesis( new_index: SessionIndex, - ) -> Option> { + ) -> Option> { Self::new_session(new_index) } /// End the session. @@ -260,7 +262,7 @@ pub trait SessionManager { } impl SessionManager for () { - fn new_session(_: SessionIndex) -> Option> { + fn new_session(_: SessionIndex) -> Option> { None } fn start_session(_: SessionIndex) {} @@ -473,7 +475,7 @@ pub mod pallet { "No initial validator provided by `SessionManager`, use \ session config keys to generate initial validator set.", ); - BoundedVec::<_, T::MaxValidatorsCount>::try_from( + WeakBoundedVec::<_, T::MaxValidatorsCount>::try_from( self.keys.iter().map(|x| x.1.clone()).collect::>(), ) .expect("Number of validators provided for session 0 is too big") @@ -507,7 +509,7 @@ pub mod pallet { #[pallet::storage] #[pallet::getter(fn validators)] pub type Validators = - StorageValue<_, BoundedVec, ValueQuery>; + StorageValue<_, WeakBoundedVec, ValueQuery>; /// Current index of the session. #[pallet::storage] @@ -523,8 +525,11 @@ pub mod pallet { /// will be used to determine the validator's session keys. #[pallet::storage] #[pallet::getter(fn queued_keys)] - pub type QueuedKeys = - StorageValue<_, BoundedVec<(T::ValidatorId, T::Keys), T::MaxValidatorsCount>, ValueQuery>; + pub type QueuedKeys = StorageValue< + _, + WeakBoundedVec<(T::ValidatorId, T::Keys), T::MaxValidatorsCount>, + ValueQuery, + >; /// Indices of disabled validators. /// @@ -534,7 +539,7 @@ pub mod pallet { #[pallet::storage] #[pallet::getter(fn disabled_validators)] pub type DisabledValidators = - StorageValue<_, BoundedVec, ValueQuery>; + StorageValue<_, WeakBoundedVec, ValueQuery>; /// The next session keys for a validator. #[pallet::storage] @@ -803,7 +808,7 @@ impl Pallet { }); let _ = >::translate::< - BoundedVec<(T::ValidatorId, Old), T::MaxValidatorsCount>, + WeakBoundedVec<(T::ValidatorId, Old), T::MaxValidatorsCount>, _, >(|k| { k.map(|k| k.map_collect(|(val, old_keys)| (val.clone(), upgrade(val, old_keys)))) diff --git a/frame/session/src/mock.rs b/frame/session/src/mock.rs index da6d47101fc1c..06f4e0a22e509 100644 --- a/frame/session/src/mock.rs +++ b/frame/session/src/mock.rs @@ -100,10 +100,10 @@ frame_support::construct_runtime!( ); thread_local! { - pub static VALIDATORS: RefCell> = - RefCell::new(BoundedVec::try_from(vec![1, 2, 3]).expect("MaxValidatorsCount > 3")); - pub static NEXT_VALIDATORS: RefCell> = - RefCell::new(BoundedVec::try_from(vec![1, 2, 3]).expect("MaxValidatorsCount > 3")); + pub static VALIDATORS: RefCell> = + RefCell::new(WeakBoundedVec::try_from(vec![1, 2, 3]).expect("MaxValidatorsCount > 3")); + pub static NEXT_VALIDATORS: RefCell> = + RefCell::new(WeakBoundedVec::try_from(vec![1, 2, 3]).expect("MaxValidatorsCount > 3")); pub static AUTHORITIES: RefCell> = RefCell::new(vec![UintAuthorityId(1), UintAuthorityId(2), UintAuthorityId(3)]); pub static FORCE_SESSION_END: RefCell = RefCell::new(false); @@ -158,7 +158,7 @@ pub struct TestSessionManager; impl SessionManager for TestSessionManager { fn end_session(_: SessionIndex) {} fn start_session(_: SessionIndex) {} - fn new_session(_: SessionIndex) -> Option> { + fn new_session(_: SessionIndex) -> Option> { if !TEST_SESSION_CHANGED.with(|l| *l.borrow()) { VALIDATORS.with(|v| { let mut v = v.borrow_mut(); @@ -179,7 +179,9 @@ impl SessionManager for TestSessionManager { impl crate::historical::SessionManager for TestSessionManager { fn end_session(_: SessionIndex) {} fn start_session(_: SessionIndex) {} - fn new_session(new_index: SessionIndex) -> Option> { + fn new_session( + new_index: SessionIndex, + ) -> Option> { >::new_session(new_index) .map(|vals| vals.map_collect(|val| (val, val))) } @@ -202,7 +204,7 @@ pub fn session_changed() -> bool { } pub fn set_next_validators(next: Vec) { - let next = BoundedVec::<_, MaxValidatorsCount>::try_from(next) + let next = WeakBoundedVec::<_, MaxValidatorsCount>::try_from(next) .expect("frame_session.set_next_validators: some test parameters need changing"); NEXT_VALIDATORS.with(|v| *v.borrow_mut() = next); } diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index 2136b5980ce07..b6256ea7e1d0c 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -252,7 +252,7 @@ impl Pallet { fn new_session( session_index: SessionIndex, is_genesis: bool, - ) -> Option> { + ) -> Option> { if let Some(current_era) = Self::current_era() { // Initial era has been set. let current_era_start_session_index = Self::eras_start_session_index(current_era) @@ -407,11 +407,11 @@ impl Pallet { /// Returns the new validator set. pub fn trigger_new_era( start_session_index: SessionIndex, - exposures: BoundedVec< + exposures: WeakBoundedVec< (T::AccountId, Exposure, T::MaxIndividualExposures>), T::MaxValidatorsCount, >, - ) -> BoundedVec { + ) -> WeakBoundedVec { // Increment or set current era. let new_planned_era = CurrentEra::::mutate(|s| { *s = Some(s.map(|s| s + 1).unwrap_or(0)); @@ -437,7 +437,7 @@ impl Pallet { pub(crate) fn try_trigger_new_era( start_session_index: SessionIndex, is_genesis: bool, - ) -> Option> { + ) -> Option> { let election_result = if is_genesis { T::GenesisElectionProvider::elect().map_err(|e| { log!(warn, "genesis election provider failed due to {:?}", e); @@ -486,12 +486,12 @@ impl Pallet { /// /// Store staking information for the new planned era pub fn store_stakers_info( - exposures: BoundedVec< + exposures: WeakBoundedVec< (T::AccountId, Exposure, T::MaxIndividualExposures>), T::MaxValidatorsCount, >, new_planned_era: EraIndex, - ) -> BoundedVec { + ) -> WeakBoundedVec { let elected_stashes = exposures.clone().map_collect(|(x, _)| x); // Populate stakers, exposures, and the snapshot of validator prefs. @@ -543,7 +543,7 @@ impl Pallet { /// [`Exposure`]. fn collect_exposures( supports: Supports, - ) -> BoundedVec< + ) -> WeakBoundedVec< (T::AccountId, Exposure, T::MaxIndividualExposures>), T::MaxValidatorsCount, > { @@ -552,7 +552,7 @@ impl Pallet { T::CurrencyToVote::to_currency(e, total_issuance) }; - let exposures = BoundedVec::<_, T::MaxValidatorsCount>::try_from( + WeakBoundedVec::<_, T::MaxValidatorsCount>::force_from( supports .into_iter() .map(|(validator, support)| { @@ -582,14 +582,8 @@ impl Pallet { (validator, exposure) }) .collect::)>>(), - ); - - // This should never happen - if exposures.is_err() { - log!(error, "Too many validators in frame_staking.collect_exposures") - } - - exposures.unwrap_or_default() + Some("Too many validators in frame_staking.collect_exposures"), + ) } /// Remove all associated data of a stash account from the staking system. @@ -1096,14 +1090,14 @@ impl ElectionDataProvider, T::MaxVali impl pallet_session::SessionManager for Pallet { fn new_session( new_index: SessionIndex, - ) -> Option> { + ) -> Option> { log!(trace, "planning new session {}", new_index); CurrentPlannedSession::::put(new_index); Self::new_session(new_index, false) } fn new_session_genesis( new_index: SessionIndex, - ) -> Option> { + ) -> Option> { log!(trace, "planning new session {} at genesis", new_index); CurrentPlannedSession::::put(new_index); Self::new_session(new_index, true) @@ -1128,7 +1122,7 @@ impl fn new_session( new_index: SessionIndex, ) -> Option< - BoundedVec< + WeakBoundedVec< (T::AccountId, Exposure, T::MaxIndividualExposures>), T::MaxValidatorsCount, >, @@ -1148,7 +1142,7 @@ impl fn new_session_genesis( new_index: SessionIndex, ) -> Option< - BoundedVec< + WeakBoundedVec< (T::AccountId, Exposure, T::MaxIndividualExposures>), T::MaxValidatorsCount, >, diff --git a/frame/support/src/storage/bounded_vec.rs b/frame/support/src/storage/bounded_vec.rs index 78d85ba1c2f34..a3cc5edab2014 100644 --- a/frame/support/src/storage/bounded_vec.rs +++ b/frame/support/src/storage/bounded_vec.rs @@ -160,24 +160,6 @@ impl BoundedVec { ) -> Option<&mut >::Output> { self.0.get_mut(index) } - - /// Utility to avoid having to transform `BoundedVec` into an - /// `Iterator` then use `map` and then `collect` to then `try_from` - /// back into a `BoundedVec` - pub fn map_collect(self, f: F) -> BoundedVec - where - F: FnMut(T) -> B, - { - BoundedVec::(self.into_iter().map(f).collect::>(), Default::default()) - } - - /// Same as `map_collect` but taking a reference to `self` - pub fn map_collect_ref(&self, f: F) -> BoundedVec - where - F: FnMut(&T) -> B, - { - BoundedVec::(self.0.iter().map(f).collect::>(), Default::default()) - } } impl> From> for Vec { diff --git a/frame/support/src/storage/weak_bounded_vec.rs b/frame/support/src/storage/weak_bounded_vec.rs index ab2533e1f9afc..9a4303c531fa4 100644 --- a/frame/support/src/storage/weak_bounded_vec.rs +++ b/frame/support/src/storage/weak_bounded_vec.rs @@ -114,6 +114,24 @@ impl WeakBoundedVec { ) -> Option<&mut >::Output> { self.0.get_mut(index) } + + /// Utility to avoid having to transform `WeakBoundedVec` into an + /// `Iterator` then use `map` and then `collect` to then `try_from` + /// back into a `WeakBoundedVec` + pub fn map_collect(self, f: F) -> WeakBoundedVec + where + F: FnMut(T) -> B, + { + WeakBoundedVec::(self.into_iter().map(f).collect::>(), Default::default()) + } + + /// Same as `map_collect` but taking a reference to `self` + pub fn map_collect_ref(&self, f: F) -> WeakBoundedVec + where + F: FnMut(&T) -> B, + { + WeakBoundedVec::(self.0.iter().map(f).collect::>(), Default::default()) + } } impl> WeakBoundedVec { @@ -427,6 +445,22 @@ pub mod test { assert_eq!(*bounded, vec![1, 0, 2, 3]); } + #[test] + fn map_collect_works() { + let first: WeakBoundedVec = vec![1, 2, 3].try_into().unwrap(); + let second = first.map_collect(|x| x * 2); + assert_eq!(*second, vec![2, 4, 6]); + } + + #[test] + fn map_collect_ref_works() { + let first: WeakBoundedVec = vec![1, 2, 3].try_into().unwrap(); + let second = first.map_collect_ref(|x| x * 2); + assert_eq!(*second, vec![2, 4, 6]); + // we borrowed `first` so this compiles and works + assert_eq!(*first, vec![1, 2, 3]); + } + #[test] #[should_panic(expected = "insertion index (is 9) should be <= len (is 3)")] fn try_inert_panics_if_oob() { From be3564a4a9c698c79898fac258d6666010ce135f Mon Sep 17 00:00:00 2001 From: Georges Dib Date: Sat, 30 Oct 2021 18:49:13 +0100 Subject: [PATCH 73/80] Fixing tests after `BoundedVec` change --- frame/beefy-mmr/src/mock.rs | 10 ++++++---- frame/beefy/src/mock.rs | 10 ++++++---- frame/im-online/src/mock.rs | 10 +++++----- frame/im-online/src/tests.rs | 20 ++++++++++---------- 4 files changed, 27 insertions(+), 23 deletions(-) diff --git a/frame/beefy-mmr/src/mock.rs b/frame/beefy-mmr/src/mock.rs index f8b9c418537d5..e7cad02d60a79 100644 --- a/frame/beefy-mmr/src/mock.rs +++ b/frame/beefy-mmr/src/mock.rs @@ -20,7 +20,7 @@ use std::{convert::TryFrom, vec}; use beefy_primitives::mmr::MmrLeafVersion; use frame_support::{ construct_runtime, parameter_types, sp_io::TestExternalities, traits::GenesisBuild, - BasicExternalities, BoundedVec, + BasicExternalities, WeakBoundedVec, }; use sp_core::{Hasher, H256}; use sp_runtime::{ @@ -156,11 +156,13 @@ pub struct MockSessionManager; impl pallet_session::SessionManager for MockSessionManager { fn end_session(_: sp_staking::SessionIndex) {} fn start_session(_: sp_staking::SessionIndex) {} - fn new_session(idx: sp_staking::SessionIndex) -> Option> { + fn new_session( + idx: sp_staking::SessionIndex, + ) -> Option> { if idx == 0 || idx == 1 { - Some(BoundedVec::try_from(vec![1, 2]).expect("MaxValidatorsCount >= 2")) + Some(WeakBoundedVec::try_from(vec![1, 2]).expect("MaxValidatorsCount >= 2")) } else if idx == 2 { - Some(BoundedVec::try_from(vec![3, 4]).expect("MaxValidatorsCount >= 2")) + Some(WeakBoundedVec::try_from(vec![3, 4]).expect("MaxValidatorsCount >= 2")) } else { None } diff --git a/frame/beefy/src/mock.rs b/frame/beefy/src/mock.rs index bb8476e13b076..225c71b8fc4ae 100644 --- a/frame/beefy/src/mock.rs +++ b/frame/beefy/src/mock.rs @@ -19,7 +19,7 @@ use std::{convert::TryFrom, vec}; use frame_support::{ construct_runtime, parameter_types, sp_io::TestExternalities, traits::GenesisBuild, - BasicExternalities, BoundedVec, + BasicExternalities, WeakBoundedVec, }; use sp_core::H256; use sp_runtime::{ @@ -117,11 +117,13 @@ pub struct MockSessionManager; impl pallet_session::SessionManager for MockSessionManager { fn end_session(_: sp_staking::SessionIndex) {} fn start_session(_: sp_staking::SessionIndex) {} - fn new_session(idx: sp_staking::SessionIndex) -> Option> { + fn new_session( + idx: sp_staking::SessionIndex, + ) -> Option> { if idx == 0 || idx == 1 { - Some(BoundedVec::try_from(vec![1, 2]).expect("MaxValidatorsCount >=2")) + Some(WeakBoundedVec::try_from(vec![1, 2]).expect("MaxValidatorsCount >=2")) } else if idx == 2 { - Some(BoundedVec::try_from(vec![3, 4]).expect("MaxValidatorsCount >=2")) + Some(WeakBoundedVec::try_from(vec![3, 4]).expect("MaxValidatorsCount >=2")) } else { None } diff --git a/frame/im-online/src/mock.rs b/frame/im-online/src/mock.rs index 14a6219ad7ade..358a4e98c8ef2 100644 --- a/frame/im-online/src/mock.rs +++ b/frame/im-online/src/mock.rs @@ -21,7 +21,7 @@ use std::cell::RefCell; -use frame_support::{parameter_types, traits::ReportOffence, weights::Weight, BoundedVec}; +use frame_support::{parameter_types, traits::ReportOffence, weights::Weight, WeakBoundedVec}; use pallet_session::historical as pallet_session_historical; use sp_core::H256; use sp_runtime::{ @@ -51,13 +51,13 @@ frame_support::construct_runtime!( ); thread_local! { - pub static VALIDATORS: RefCell>> = - RefCell::new(Some(BoundedVec::try_from(vec![1, 2, 3]).expect("MaxKeys > 3"))); + pub static VALIDATORS: RefCell>> = + RefCell::new(Some(WeakBoundedVec::try_from(vec![1, 2, 3]).expect("MaxKeys > 3"))); } pub struct TestSessionManager; impl pallet_session::SessionManager for TestSessionManager { - fn new_session(_new_index: SessionIndex) -> Option> { + fn new_session(_new_index: SessionIndex) -> Option> { VALIDATORS.with(|l| l.borrow_mut().take()) } fn end_session(_: SessionIndex) {} @@ -65,7 +65,7 @@ impl pallet_session::SessionManager for TestSessionManager { } impl pallet_session::historical::SessionManager for TestSessionManager { - fn new_session(_new_index: SessionIndex) -> Option> { + fn new_session(_new_index: SessionIndex) -> Option> { VALIDATORS .with(|l| l.borrow_mut().take().map(|validators| validators.map_collect(|v| (v, v)))) } diff --git a/frame/im-online/src/tests.rs b/frame/im-online/src/tests.rs index 1ae569bf8065f..e363cfae12918 100644 --- a/frame/im-online/src/tests.rs +++ b/frame/im-online/src/tests.rs @@ -21,7 +21,7 @@ use super::*; use crate::mock::*; -use frame_support::{assert_noop, dispatch, BoundedVec}; +use frame_support::{assert_noop, dispatch, WeakBoundedVec}; use sp_core::{ offchain::{ testing::{TestOffchainExt, TestTransactionPoolExt}, @@ -65,7 +65,7 @@ fn should_report_offline_validators() { // buffer new validators advance_session(); // enact the change and buffer another one - let validators = BoundedVec::try_from(vec![1, 2, 3, 4, 5, 6]).expect("MaxKeys >= 6"); + let validators = WeakBoundedVec::try_from(vec![1, 2, 3, 4, 5, 6]).expect("MaxKeys >= 6"); VALIDATORS.with(|l| *l.borrow_mut() = Some(validators.clone())); advance_session(); @@ -151,7 +151,7 @@ fn should_mark_online_validator_when_heartbeat_is_received() { // given VALIDATORS.with(|l| { *l.borrow_mut() = - Some(BoundedVec::try_from(vec![1, 2, 3, 4, 5, 6]).expect("MaxKeys >= 6")) + Some(WeakBoundedVec::try_from(vec![1, 2, 3, 4, 5, 6]).expect("MaxKeys >= 6")) }); assert_eq!(Session::validators(), Vec::::new()); // enact the change and buffer another one @@ -189,7 +189,7 @@ fn late_heartbeat_and_invalid_keys_len_should_fail() { // given VALIDATORS.with(|l| { *l.borrow_mut() = - Some(BoundedVec::try_from(vec![1, 2, 3, 4, 5, 6]).expect("MaxKeys >= 6")) + Some(WeakBoundedVec::try_from(vec![1, 2, 3, 4, 5, 6]).expect("MaxKeys >= 6")) }); assert_eq!(Session::validators(), Vec::::new()); // enact the change and buffer another one @@ -234,7 +234,7 @@ fn should_generate_heartbeats() { // enact the change and buffer another one VALIDATORS.with(|l| { *l.borrow_mut() = - Some(BoundedVec::try_from(vec![1, 2, 3, 4, 5, 6]).expect("MaxKeys >= 6")) + Some(WeakBoundedVec::try_from(vec![1, 2, 3, 4, 5, 6]).expect("MaxKeys >= 6")) }); Session::rotate_session(); @@ -272,7 +272,7 @@ fn should_cleanup_received_heartbeats_on_session_end() { advance_session(); VALIDATORS.with(|l| { - *l.borrow_mut() = Some(BoundedVec::try_from(vec![1, 2, 3]).expect("MaxKeys >= 3")) + *l.borrow_mut() = Some(WeakBoundedVec::try_from(vec![1, 2, 3]).expect("MaxKeys >= 3")) }); assert_eq!(Session::validators(), Vec::::new()); @@ -306,7 +306,7 @@ fn should_mark_online_validator_when_block_is_authored() { // given VALIDATORS.with(|l| { *l.borrow_mut() = - Some(BoundedVec::try_from(vec![1, 2, 3, 4, 5, 6]).expect("MaxKeys >= 6")) + Some(WeakBoundedVec::try_from(vec![1, 2, 3, 4, 5, 6]).expect("MaxKeys >= 6")) }); assert_eq!(Session::validators(), Vec::::new()); // enact the change and buffer another one @@ -346,7 +346,7 @@ fn should_not_send_a_report_if_already_online() { // given VALIDATORS.with(|l| { *l.borrow_mut() = - Some(BoundedVec::try_from(vec![1, 2, 3, 4, 5, 6]).expect("MaxKeys >= 6")) + Some(WeakBoundedVec::try_from(vec![1, 2, 3, 4, 5, 6]).expect("MaxKeys >= 6")) }); assert_eq!(Session::validators(), Vec::::new()); // enact the change and buffer another one @@ -411,7 +411,7 @@ fn should_handle_missing_progress_estimates() { // enact the change and buffer another one VALIDATORS.with(|l| { - *l.borrow_mut() = Some(BoundedVec::try_from(vec![0, 1, 2]).expect("MaxKeys >= 3")) + *l.borrow_mut() = Some(WeakBoundedVec::try_from(vec![0, 1, 2]).expect("MaxKeys >= 3")) }); Session::rotate_session(); @@ -447,7 +447,7 @@ fn should_handle_non_linear_session_progress() { // mock the session length as being 10 blocks long, // enact the change and buffer another one VALIDATORS.with(|l| { - *l.borrow_mut() = Some(BoundedVec::try_from(vec![0, 1, 2]).expect("MaxKeys >= 3")) + *l.borrow_mut() = Some(WeakBoundedVec::try_from(vec![0, 1, 2]).expect("MaxKeys >= 3")) }); // mock the session length has being 10 which should make us assume the fallback for half From 9b8f704d23c66bea95b066169e68768694452034 Mon Sep 17 00:00:00 2001 From: Georges Dib Date: Mon, 1 Nov 2021 21:33:19 +0000 Subject: [PATCH 74/80] running cargo +nightly fmt --- bin/node/runtime/src/lib.rs | 23 +++++---- frame/aura/src/lib.rs | 4 +- frame/babe/src/equivocation.rs | 6 +-- frame/babe/src/lib.rs | 10 ++-- frame/babe/src/tests.rs | 6 +-- .../election-provider-multi-phase/src/lib.rs | 46 +++++++++--------- .../election-provider-multi-phase/src/mock.rs | 2 +- .../src/unsigned.rs | 47 +++++++++---------- frame/grandpa/src/equivocation.rs | 6 +-- frame/grandpa/src/lib.rs | 14 +++--- frame/grandpa/src/tests.rs | 4 +- frame/im-online/src/lib.rs | 33 +++++++------ frame/im-online/src/tests.rs | 5 +- frame/session/src/historical/mod.rs | 8 ++-- frame/session/src/lib.rs | 12 ++--- frame/session/src/mock.rs | 4 +- frame/staking/fuzzer/src/mock.rs | 10 ++-- frame/staking/src/lib.rs | 2 +- frame/staking/src/mock.rs | 6 +-- frame/staking/src/pallet/impls.rs | 27 +++++------ frame/staking/src/pallet/mod.rs | 33 ++++++------- frame/support/src/lib.rs | 2 +- frame/support/src/storage/bounded_vec.rs | 2 +- .../test/tests/derive_no_bound_ui/ord.rs | 2 +- primitives/core/src/crypto.rs | 30 ++++++------ primitives/runtime/src/traits.rs | 4 +- primitives/staking/src/offence.rs | 2 +- 27 files changed, 172 insertions(+), 178 deletions(-) diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 994628c85fdfe..20827d0d51a3c 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -289,18 +289,17 @@ impl InstanceFilter for ProxyType { ProxyType::Any => true, ProxyType::NonTransfer => !matches!( c, - Call::Balances(..) - | Call::Assets(..) | Call::Uniques(..) - | Call::Vesting(pallet_vesting::Call::vested_transfer { .. }) - | Call::Indices(pallet_indices::Call::transfer { .. }) + Call::Balances(..) | + Call::Assets(..) | Call::Uniques(..) | + Call::Vesting(pallet_vesting::Call::vested_transfer { .. }) | + Call::Indices(pallet_indices::Call::transfer { .. }) ), ProxyType::Governance => matches!( c, - Call::Democracy(..) - | Call::Council(..) | Call::Society(..) - | Call::TechnicalCommittee(..) - | Call::Elections(..) - | Call::Treasury(..) + Call::Democracy(..) | + Call::Council(..) | Call::Society(..) | + Call::TechnicalCommittee(..) | + Call::Elections(..) | Call::Treasury(..) ), ProxyType::Staking => matches!(c, Call::Staking(..)), } @@ -631,10 +630,10 @@ impl frame_support::pallet_prelude::Get { let seed = sp_io::offchain::random_seed(); let random = ::decode(&mut TrailingZeroInput::new(&seed)) - .expect("input is padded with zeroes; qed") - % max.saturating_add(1); + .expect("input is padded with zeroes; qed") % + max.saturating_add(1); random as usize - } + }, }; Some((iters, 0)) diff --git a/frame/aura/src/lib.rs b/frame/aura/src/lib.rs index 0edb247bcae67..cde2ea326a396 100644 --- a/frame/aura/src/lib.rs +++ b/frame/aura/src/lib.rs @@ -174,7 +174,7 @@ impl Pallet { let pre_runtime_digests = digest.logs.iter().filter_map(|d| d.as_pre_runtime()); for (id, mut data) in pre_runtime_digests { if id == AURA_ENGINE_ID { - return Slot::decode(&mut data).ok(); + return Slot::decode(&mut data).ok() } } @@ -241,7 +241,7 @@ impl FindAuthor for Pallet { if id == AURA_ENGINE_ID { let slot = Slot::decode(&mut data).ok()?; let author_index = *slot % Self::authorities().len() as u64; - return Some(author_index as u32); + return Some(author_index as u32) } } diff --git a/frame/babe/src/equivocation.rs b/frame/babe/src/equivocation.rs index 91704638413a1..05b7a7c7089a4 100644 --- a/frame/babe/src/equivocation.rs +++ b/frame/babe/src/equivocation.rs @@ -190,15 +190,15 @@ impl Pallet { if let Call::report_equivocation_unsigned { equivocation_proof, key_owner_proof } = call { // discard equivocation report not coming from the local node match source { - TransactionSource::Local | TransactionSource::InBlock => { /* allowed */ } + TransactionSource::Local | TransactionSource::InBlock => { /* allowed */ }, _ => { log::warn!( target: "runtime::babe", "rejecting unsigned report equivocation transaction because it is not local/in-block.", ); - return InvalidTransaction::Call.into(); - } + return InvalidTransaction::Call.into() + }, } // check report staleness diff --git a/frame/babe/src/lib.rs b/frame/babe/src/lib.rs index 02d3044b479ea..05e6bd8cbc06f 100644 --- a/frame/babe/src/lib.rs +++ b/frame/babe/src/lib.rs @@ -445,11 +445,11 @@ impl FindAuthor for Pallet { for (id, mut data) in digests.into_iter() { if id == BABE_ENGINE_ID { let pre_digest: PreDigest = PreDigest::decode(&mut data).ok()?; - return Some(pre_digest.authority_index()); + return Some(pre_digest.authority_index()) } } - return None; + return None } } @@ -665,7 +665,7 @@ impl Pallet { // => let's ensure that we only modify the storage once per block let initialized = Self::initialized().is_some(); if initialized { - return; + return } let maybe_pre_digest: Option = @@ -794,7 +794,7 @@ impl Pallet { // validate the equivocation proof if !sp_consensus_babe::check_equivocation_proof(equivocation_proof) { - return Err(Error::::InvalidEquivocationProof.into()); + return Err(Error::::InvalidEquivocationProof.into()) } let validator_set_count = key_owner_proof.validator_count(); @@ -806,7 +806,7 @@ impl Pallet { // check that the slot number is consistent with the session index // in the key ownership proof (i.e. slot is for that epoch) if epoch_index != session_index { - return Err(Error::::InvalidKeyOwnershipProof.into()); + return Err(Error::::InvalidKeyOwnershipProof.into()) } // check the membership proof and extract the offender's id diff --git a/frame/babe/src/tests.rs b/frame/babe/src/tests.rs index 33e9a7e4db923..abdf63c8f43d0 100644 --- a/frame/babe/src/tests.rs +++ b/frame/babe/src/tests.rs @@ -219,8 +219,8 @@ fn can_estimate_current_epoch_progress() { ); } else { assert!( - Babe::estimate_current_session_progress(i).0.unwrap() - < Permill::from_percent(100) + Babe::estimate_current_session_progress(i).0.unwrap() < + Permill::from_percent(100) ); } } @@ -462,7 +462,7 @@ fn report_equivocation_current_session_works() { // check that the balances of all other validators are left intact. for validator in &validators.to_vec() { if *validator == offending_validator_id { - continue; + continue } assert_eq!(Balances::total_balance(validator), 10_000_000); diff --git a/frame/election-provider-multi-phase/src/lib.rs b/frame/election-provider-multi-phase/src/lib.rs index aeebf188af5c7..0081132f33834 100644 --- a/frame/election-provider-multi-phase/src/lib.rs +++ b/frame/election-provider-multi-phase/src/lib.rs @@ -741,14 +741,14 @@ pub mod pallet { Ok(_) => { Self::on_initialize_open_signed(); T::WeightInfo::on_initialize_open_signed() - } + }, Err(why) => { // Not much we can do about this at this point. log!(warn, "failed to open signed phase due to {:?}", why); T::WeightInfo::on_initialize_nothing() - } + }, } - } + }, Phase::Signed | Phase::Off if remaining <= unsigned_deadline && remaining > Zero::zero() => { @@ -780,17 +780,17 @@ pub mod pallet { Ok(_) => { Self::on_initialize_open_unsigned(enabled, now); T::WeightInfo::on_initialize_open_unsigned() - } + }, Err(why) => { log!(warn, "failed to open unsigned phase due to {:?}", why); T::WeightInfo::on_initialize_nothing() - } + }, } } else { Self::on_initialize_open_unsigned(enabled, now); T::WeightInfo::on_initialize_open_unsigned() } - } + }, _ => T::WeightInfo::on_initialize_nothing(), } } @@ -810,10 +810,10 @@ pub mod pallet { match lock.try_lock() { Ok(_guard) => { Self::do_synchronized_offchain_worker(now); - } + }, Err(deadline) => { log!(debug, "offchain worker lock not released, deadline is {:?}", deadline); - } + }, }; } @@ -980,8 +980,8 @@ pub mod pallet { // ensure witness data is correct. ensure!( - num_signed_submissions - >= >::decode_len().unwrap_or_default() as u32, + num_signed_submissions >= + >::decode_len().unwrap_or_default() as u32, Error::::SignedInvalidWitness, ); @@ -1096,7 +1096,7 @@ pub mod pallet { if let Call::submit_unsigned { raw_solution, .. } = call { // Discard solution not coming from the local OCW. match source { - TransactionSource::Local | TransactionSource::InBlock => { /* allowed */ } + TransactionSource::Local | TransactionSource::InBlock => { /* allowed */ }, _ => return InvalidTransaction::Call.into(), } @@ -1262,15 +1262,15 @@ impl Pallet { Self::mine_check_save_submit() }); log!(debug, "initial offchain thread output: {:?}", initial_output); - } + }, Phase::Unsigned((true, opened)) if opened < now => { // Try and resubmit the cached solution, and recompute ONLY if it is not // feasible. let resubmit_output = Self::ensure_offchain_repeat_frequency(now) .and_then(|_| Self::restore_or_compute_then_maybe_submit()); log!(debug, "resubmit offchain thread output: {:?}", resubmit_output); - } - _ => {} + }, + _ => {}, } } @@ -1342,7 +1342,7 @@ impl Pallet { // Defensive-only. if targets.len() > target_limit || voters.len() > voter_limit { debug_assert!(false, "Snapshot limit has not been respected."); - return Err(ElectionError::DataProvider("Snapshot too big for submission.")); + return Err(ElectionError::DataProvider("Snapshot too big for submission.")) } Ok((targets, voters, desired_targets)) @@ -1452,7 +1452,7 @@ impl Pallet { // Check that all of the targets are valid based on the snapshot. if assignment.distribution.iter().any(|(d, _)| !targets.contains(d)) { - return Err(FeasibilityError::InvalidVote); + return Err(FeasibilityError::InvalidVote) } Ok(()) }) @@ -1545,12 +1545,12 @@ impl ElectionProvider fo Self::weigh_supports(&supports); Self::rotate_round(); Ok(supports) - } + }, Err(why) => { log!(error, "Entering emergency mode: {:?}", why); >::put(Phase::Emergency); Err(why) - } + }, } } } @@ -2015,7 +2015,9 @@ mod tests { fn snapshot_too_big_failure_onchain_fallback_fail() { // the `MockStaking` is designed such that if it has too many targets, it simply fails. ExtBuilder::default().build_and_execute(|| { - Targets::set((0..(crate::mock::MaxValidatorsCount::get() as u64 + 1)).collect::>()); + Targets::set( + (0..(crate::mock::MaxValidatorsCount::get() as u64 + 1)).collect::>(), + ); // Signed phase failed to open. roll_to(15); @@ -2118,9 +2120,9 @@ mod tests { }; let mut active = 1; - while weight_with(active) - <= ::BlockWeights::get().max_block - || active == all_voters + while weight_with(active) <= + ::BlockWeights::get().max_block || + active == all_voters { active += 1; } diff --git a/frame/election-provider-multi-phase/src/mock.rs b/frame/election-provider-multi-phase/src/mock.rs index 13ce988dc3713..9ec821a933d96 100644 --- a/frame/election-provider-multi-phase/src/mock.rs +++ b/frame/election-provider-multi-phase/src/mock.rs @@ -446,7 +446,7 @@ impl ElectionDataProvider for StakingMock { .map_err(|_| "Targets too big")?; if maybe_max_len.map_or(false, |max_len| targets.len() > max_len) { - return Err("Targets too big"); + return Err("Targets too big") } Ok(targets) diff --git a/frame/election-provider-multi-phase/src/unsigned.rs b/frame/election-provider-multi-phase/src/unsigned.rs index 00eb1c666b89c..23e78300bcddf 100644 --- a/frame/election-provider-multi-phase/src/unsigned.rs +++ b/frame/election-provider-multi-phase/src/unsigned.rs @@ -122,16 +122,15 @@ fn save_solution(call: &Call) -> Result<(), MinerError> { let storage = StorageValueRef::persistent(&OFFCHAIN_CACHED_CALL); match storage.mutate::<_, (), _>(|_| Ok(call.clone())) { Ok(_) => Ok(()), - Err(MutateStorageError::ConcurrentModification(_)) => { - Err(MinerError::FailedToStoreSolution) - } + Err(MutateStorageError::ConcurrentModification(_)) => + Err(MinerError::FailedToStoreSolution), Err(MutateStorageError::ValueFunctionFailed(_)) => { // this branch should be unreachable according to the definition of // `StorageValueRef::mutate`: that function should only ever `Err` if the closure we // pass it returns an error. however, for safety in case the definition changes, we do // not optimize the branch away or panic. Err(MinerError::FailedToStoreSolution) - } + }, } } @@ -194,7 +193,7 @@ impl Pallet { let call = Self::mine_checked_call()?; save_solution(&call)?; Ok(call) - } + }, MinerError::Feasibility(_) => { log!(trace, "wiping infeasible solution."); // kill the infeasible solution, hopefully in the next runs (whenever they @@ -202,11 +201,11 @@ impl Pallet { kill_ocw_solution::(); clear_offchain_repeat_frequency(); Err(error) - } + }, _ => { // nothing to do. Return the error as-is. Err(error) - } + }, } })?; @@ -467,7 +466,7 @@ impl Pallet { // not much we can do if assignments are already empty. if high == low { - return Ok(()); + return Ok(()) } while high - low > 1 { @@ -478,8 +477,8 @@ impl Pallet { high = test; } } - let maximum_allowed_voters = if low < assignments.len() - && encoded_size_of(&assignments[..low + 1])? <= max_allowed_length + let maximum_allowed_voters = if low < assignments.len() && + encoded_size_of(&assignments[..low + 1])? <= max_allowed_length { low + 1 } else { @@ -491,8 +490,8 @@ impl Pallet { encoded_size_of(&assignments[..maximum_allowed_voters]).unwrap() <= max_allowed_length ); debug_assert!(if maximum_allowed_voters < assignments.len() { - encoded_size_of(&assignments[..maximum_allowed_voters + 1]).unwrap() - > max_allowed_length + encoded_size_of(&assignments[..maximum_allowed_voters + 1]).unwrap() > + max_allowed_length } else { true }); @@ -522,7 +521,7 @@ impl Pallet { max_weight: Weight, ) -> u32 { if size.voters < 1 { - return size.voters; + return size.voters } let max_voters = size.voters.max(1); @@ -541,7 +540,7 @@ impl Pallet { Some(voters) if voters < max_voters => Ok(voters), _ => Err(()), } - } + }, Ordering::Greater => voters.checked_sub(step).ok_or(()), Ordering::Equal => Ok(voters), } @@ -556,7 +555,7 @@ impl Pallet { // proceed with the binary search Ok(next) if next != voters => { voters = next; - } + }, // we are out of bounds, break out of the loop. Err(()) => break, // we found the right value - early exit the function. @@ -602,17 +601,16 @@ impl Pallet { |maybe_head: Result, _>| { match maybe_head { Ok(Some(head)) if now < head => Err("fork."), - Ok(Some(head)) if now >= head && now <= head + threshold => { - Err("recently executed.") - } + Ok(Some(head)) if now >= head && now <= head + threshold => + Err("recently executed."), Ok(Some(head)) if now > head + threshold => { // we can run again now. Write the new head. Ok(now) - } + }, _ => { // value doesn't exists. Probably this node just booted up. Write, and run Ok(now) - } + }, } }, ); @@ -621,9 +619,8 @@ impl Pallet { // all good Ok(_) => Ok(()), // failed to write. - Err(MutateStorageError::ConcurrentModification(_)) => { - Err(MinerError::Lock("failed to write to offchain db (concurrent modification).")) - } + Err(MutateStorageError::ConcurrentModification(_)) => + Err(MinerError::Lock("failed to write to offchain db (concurrent modification).")), // fork etc. Err(MutateStorageError::ValueFunctionFailed(why)) => Err(MinerError::Lock(why)), } @@ -647,8 +644,8 @@ impl Pallet { // ensure correct number of winners. ensure!( - Self::desired_targets().unwrap_or_default() - == raw_solution.solution.unique_targets().len() as u32, + Self::desired_targets().unwrap_or_default() == + raw_solution.solution.unique_targets().len() as u32, Error::::PreDispatchWrongWinnerCount, ); diff --git a/frame/grandpa/src/equivocation.rs b/frame/grandpa/src/equivocation.rs index 3409698a794af..f87e21aab70c8 100644 --- a/frame/grandpa/src/equivocation.rs +++ b/frame/grandpa/src/equivocation.rs @@ -211,15 +211,15 @@ impl Pallet { if let Call::report_equivocation_unsigned { equivocation_proof, key_owner_proof } = call { // discard equivocation report not coming from the local node match source { - TransactionSource::Local | TransactionSource::InBlock => { /* allowed */ } + TransactionSource::Local | TransactionSource::InBlock => { /* allowed */ }, _ => { log::warn!( target: "runtime::afg", "rejecting unsigned report equivocation transaction because it is not local/in-block." ); - return InvalidTransaction::Call.into(); - } + return InvalidTransaction::Call.into() + }, } // check report staleness diff --git a/frame/grandpa/src/lib.rs b/frame/grandpa/src/lib.rs index c0509fb9e9e51..0f40800a287e5 100644 --- a/frame/grandpa/src/lib.rs +++ b/frame/grandpa/src/lib.rs @@ -178,7 +178,7 @@ pub mod pallet { >::put(StoredState::Paused); Self::deposit_event(Event::Paused); } - } + }, StoredState::PendingResume { scheduled_at, delay } => { // signal change to resume if block_number == scheduled_at { @@ -190,8 +190,8 @@ pub mod pallet { >::put(StoredState::Live); Self::deposit_event(Event::Resumed); } - } - _ => {} + }, + _ => {}, } } } @@ -554,7 +554,7 @@ impl Pallet { // validate equivocation proof (check votes are different and // signatures are valid). if !sp_finality_grandpa::check_equivocation_proof(equivocation_proof) { - return Err(Error::::InvalidEquivocationProof.into()); + return Err(Error::::InvalidEquivocationProof.into()) } // fetch the current and previous sets last session index. on the @@ -573,12 +573,12 @@ impl Pallet { // check that the session id for the membership proof is within the // bounds of the set id reported in the equivocation. - if session_index > set_id_session_index - || previous_set_id_session_index + if session_index > set_id_session_index || + previous_set_id_session_index .map(|previous_index| session_index <= previous_index) .unwrap_or(false) { - return Err(Error::::InvalidEquivocationProof.into()); + return Err(Error::::InvalidEquivocationProof.into()) } // report to the offences module rewarding the sender. diff --git a/frame/grandpa/src/tests.rs b/frame/grandpa/src/tests.rs index 126cb4694717e..e8203c87d30c2 100644 --- a/frame/grandpa/src/tests.rs +++ b/frame/grandpa/src/tests.rs @@ -373,7 +373,7 @@ fn report_equivocation_current_set_works() { // check that the balances of all other validators are left intact. for validator in &validators.to_vec() { if *validator == equivocation_validator_id { - continue; + continue } assert_eq!(Balances::total_balance(validator), 10_000_000); @@ -452,7 +452,7 @@ fn report_equivocation_old_set_works() { // check that the balances of all other validators are left intact. for validator in &validators.to_vec() { if *validator == equivocation_validator_id { - continue; + continue } assert_eq!(Balances::total_balance(validator), 10_000_000); diff --git a/frame/im-online/src/lib.rs b/frame/im-online/src/lib.rs index c0705c4c7b0f7..05b57c953a33e 100644 --- a/frame/im-online/src/lib.rs +++ b/frame/im-online/src/lib.rs @@ -193,10 +193,10 @@ impl sp_std::fmt::Debug for OffchainErr write!(fmt, "Too early to send heartbeat."), OffchainErr::WaitingForInclusion(ref block) => { write!(fmt, "Heartbeat already sent at {:?}. Waiting for inclusion.", block) - } + }, OffchainErr::AlreadyOnline(auth_idx) => { write!(fmt, "Authority {} is already online", auth_idx) - } + }, OffchainErr::FailedSigning => write!(fmt, "Failed to sign heartbeat"), OffchainErr::FailedToAcquireLock => write!(fmt, "Failed to acquire lock"), OffchainErr::NetworkState => write!(fmt, "Failed to fetch network state"), @@ -559,19 +559,19 @@ pub mod pallet { if let Call::heartbeat { heartbeat, signature } = call { if >::is_online(heartbeat.authority_index) { // we already received a heartbeat for this authority - return InvalidTransaction::Stale.into(); + return InvalidTransaction::Stale.into() } // check if session index from heartbeat is recent let current_session = T::ValidatorSet::session_index(); if heartbeat.session_index != current_session { - return InvalidTransaction::Stale.into(); + return InvalidTransaction::Stale.into() } // verify that the incoming (unverified) pubkey is actually an authority id let keys = Keys::::get(); if keys.len() as u32 != heartbeat.validators_len { - return InvalidTransaction::Custom(INVALID_VALIDATORS_LEN).into(); + return InvalidTransaction::Custom(INVALID_VALIDATORS_LEN).into() } let authority_id = match keys.get(heartbeat.authority_index as usize) { Some(id) => id, @@ -584,7 +584,7 @@ pub mod pallet { }); if !signature_valid { - return InvalidTransaction::BadProof.into(); + return InvalidTransaction::BadProof.into() } ValidTransaction::with_tag_prefix("ImOnline") @@ -628,7 +628,7 @@ impl Pallet { let current_validators = T::ValidatorSet::validators(); if authority_index >= current_validators.len() as u32 { - return false; + return false } let authority = ¤t_validators[authority_index as usize]; @@ -639,8 +639,8 @@ impl Pallet { fn is_online_aux(authority_index: AuthIndex, authority: &ValidatorId) -> bool { let current_session = T::ValidatorSet::session_index(); - ReceivedHeartbeats::::contains_key(¤t_session, &authority_index) - || AuthoredBlocks::::get(¤t_session, authority) != 0 + ReceivedHeartbeats::::contains_key(¤t_session, &authority_index) || + AuthoredBlocks::::get(¤t_session, authority) != 0 } /// Returns `true` if a heartbeat has been received for the authority at `authority_index` in @@ -690,8 +690,8 @@ impl Pallet { // haven't sent an heartbeat yet we'll send one unconditionally. the idea is to prevent // all nodes from sending the heartbeats at the same block and causing a temporary (but // deterministic) spike in transactions. - progress >= START_HEARTBEAT_FINAL_PERIOD - || progress >= START_HEARTBEAT_RANDOM_PERIOD && random_choice(progress) + progress >= START_HEARTBEAT_FINAL_PERIOD || + progress >= START_HEARTBEAT_RANDOM_PERIOD && random_choice(progress) } else { // otherwise we fallback to using the block number calculated at the beginning // of the session that should roughly correspond to the middle of the session @@ -700,7 +700,7 @@ impl Pallet { }; if !should_heartbeat { - return Err(OffchainErr::TooEarly); + return Err(OffchainErr::TooEarly) } let session_index = T::ValidatorSet::session_index(); @@ -742,7 +742,7 @@ impl Pallet { }; if Self::is_online(authority_index) { - return Err(OffchainErr::AlreadyOnline(authority_index)); + return Err(OffchainErr::AlreadyOnline(authority_index)) } // acquire lock for that authority at current heartbeat to make sure we don't @@ -808,16 +808,15 @@ impl Pallet { // we will re-send it. match status { // we are still waiting for inclusion. - Ok(Some(status)) if status.is_recent(session_index, now) => { - Err(OffchainErr::WaitingForInclusion(status.sent_at)) - } + Ok(Some(status)) if status.is_recent(session_index, now) => + Err(OffchainErr::WaitingForInclusion(status.sent_at)), // attempt to set new status _ => Ok(HeartbeatStatus { session_index, sent_at: now }), } }, ); if let Err(MutateStorageError::ValueFunctionFailed(err)) = res { - return Err(err); + return Err(err) } let mut new_status = res.map_err(|_| OffchainErr::FailedToAcquireLock)?; diff --git a/frame/im-online/src/tests.rs b/frame/im-online/src/tests.rs index e363cfae12918..11191cbf3bbb2 100644 --- a/frame/im-online/src/tests.rs +++ b/frame/im-online/src/tests.rs @@ -136,9 +136,8 @@ fn heartbeat( signature: signature.clone(), }) .map_err(|e| match e { - TransactionValidityError::Invalid(InvalidTransaction::Custom(INVALID_VALIDATORS_LEN)) => { - "invalid validators len" - } + TransactionValidityError::Invalid(InvalidTransaction::Custom(INVALID_VALIDATORS_LEN)) => + "invalid validators len", e @ _ => <&'static str>::from(e), })?; ImOnline::heartbeat(Origin::none(), heartbeat, signature) diff --git a/frame/session/src/historical/mod.rs b/frame/session/src/historical/mod.rs index 280c0abb90ed9..c829a970f3b25 100644 --- a/frame/session/src/historical/mod.rs +++ b/frame/session/src/historical/mod.rs @@ -94,7 +94,7 @@ impl Module { let up_to = sp_std::cmp::min(up_to, end); if up_to < start { - return; // out of bounds. harmless. + return // out of bounds. harmless. } (start..up_to).for_each(::HistoricalSessions::remove); @@ -179,7 +179,7 @@ impl< Err(reason) => { print("Failed to generate historical ancestry-inclusion proof."); print(reason); - } + }, }; } else { let previous_index = new_index.saturating_sub(1); @@ -355,7 +355,7 @@ impl> frame_support::traits::KeyOwnerProofSystem<(KeyT let count = >::validators().len() as ValidatorCount; if count != proof.validator_count { - return None; + return None } Some((owner, id)) @@ -365,7 +365,7 @@ impl> frame_support::traits::KeyOwnerProofSystem<(KeyT let (root, count) = >::get(&proof.session)?; if count != proof.validator_count { - return None; + return None } let trie = ProvingTrie::::from_nodes(root, &proof.trie_nodes); diff --git a/frame/session/src/lib.rs b/frame/session/src/lib.rs index e2b2f5ab58470..a99cc706b9b06 100644 --- a/frame/session/src/lib.rs +++ b/frame/session/src/lib.rs @@ -701,7 +701,7 @@ impl Pallet { let mut now_session_keys = session_keys.iter(); let mut check_next_changed = |keys: &T::Keys| { if changed { - return; + return } // since a new validator set always leads to `changed` starting // as true, we can ensure that `now_session_keys` and `next_validators` @@ -709,7 +709,7 @@ impl Pallet { if let Some(&(_, ref old_keys)) = now_session_keys.next() { if old_keys != keys { changed = true; - return; + return } } }; @@ -735,7 +735,7 @@ impl Pallet { /// Disable the validator of index `i`, returns `false` if the validator was already disabled. pub fn disable_index(i: u32) -> bool { if i >= Validators::::decode_len().unwrap_or(0) as u32 { - return false; + return false } >::mutate(|disabled| { @@ -743,10 +743,10 @@ impl Pallet { if disabled.try_insert(index, i).is_err() { // This should never fail log::error!(target: "runtime::session", "disabling validator index {:?}", i); - return false; + return false } T::SessionHandler::on_disabled(i); - return true; + return true } false @@ -860,7 +860,7 @@ impl Pallet { if let Some(old) = old_keys.as_ref().map(|k| k.get_raw(*id)) { if key == old { - continue; + continue } Self::clear_key_owner(*id, old); diff --git a/frame/session/src/mock.rs b/frame/session/src/mock.rs index 06f4e0a22e509..3dd80fd4b0d47 100644 --- a/frame/session/src/mock.rs +++ b/frame/session/src/mock.rs @@ -120,8 +120,8 @@ pub struct TestShouldEndSession; impl ShouldEndSession for TestShouldEndSession { fn should_end_session(now: u64) -> bool { let l = SESSION_LENGTH.with(|l| *l.borrow()); - now % l == 0 - || FORCE_SESSION_END.with(|l| { + now % l == 0 || + FORCE_SESSION_END.with(|l| { let r = *l.borrow(); *l.borrow_mut() = false; r diff --git a/frame/staking/fuzzer/src/mock.rs b/frame/staking/fuzzer/src/mock.rs index 3391946899c44..c84768fca77cc 100644 --- a/frame/staking/fuzzer/src/mock.rs +++ b/frame/staking/fuzzer/src/mock.rs @@ -117,7 +117,8 @@ impl pallet_session::SessionHandler for TestSessionHandler { _: bool, _: &[(AccountId, Ks)], _: &[(AccountId, Ks)], - ) {} + ) { + } fn on_disabled(_: u32) {} } @@ -167,10 +168,9 @@ impl frame_election_provider_support::ElectionProvider type Error = (); type DataProvider = pallet_staking::Module; - fn elect() -> Result< - (sp_npos_elections::Supports, frame_support::weights::Weight), - Self::Error - > { + fn elect( + ) -> Result<(sp_npos_elections::Supports, frame_support::weights::Weight), Self::Error> + { Err(()) } } diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index 2df029ef2c445..dcdfc4cbfb15e 100644 --- a/frame/staking/src/lib.rs +++ b/frame/staking/src/lib.rs @@ -551,7 +551,7 @@ where } if unlocking_balance >= value { - break; + break } } diff --git a/frame/staking/src/mock.rs b/frame/staking/src/mock.rs index d9b40b61c6296..80de57d931295 100644 --- a/frame/staking/src/mock.rs +++ b/frame/staking/src/mock.rs @@ -608,7 +608,7 @@ fn check_nominators() { e.others.iter().filter(|e| e.who == nominator).collect::>(); let len = individual.len(); match len { - 0 => { /* not supporting this validator at all. */ } + 0 => { /* not supporting this validator at all. */ }, 1 => sum += individual[0].value, _ => panic!("nominator cannot back a validator more than once."), }; @@ -793,9 +793,9 @@ pub(crate) fn on_offence_in_era( for &(bonded_era, start_session) in bonded_eras.iter() { if bonded_era == era { let _ = Staking::on_offence(offenders, slash_fraction, start_session); - return; + return } else if bonded_era > era { - break; + break } } diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index b6256ea7e1d0c..6883ec1e5ec56 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -144,7 +144,7 @@ impl Pallet { // Nothing to do if they have no reward points. if validator_reward_points.is_zero() { - return Ok(Some(T::WeightInfo::payout_stakers_alive_staked(0)).into()); + return Ok(Some(T::WeightInfo::payout_stakers_alive_staked(0)).into()) } // This is the fraction of the total reward that the validator and the @@ -241,9 +241,8 @@ impl Pallet { Self::update_ledger(&controller, &l); r }), - RewardDestination::Account(dest_account) => { - Some(T::Currency::deposit_creating(&dest_account, amount)) - } + RewardDestination::Account(dest_account) => + Some(T::Currency::deposit_creating(&dest_account, amount)), RewardDestination::None => None, } } @@ -274,14 +273,14 @@ impl Pallet { _ => { // Either `Forcing::ForceNone`, // or `Forcing::NotForcing if era_length >= T::SessionsPerEra::get()`. - return None; - } + return None + }, } // New era. let maybe_new_era_validators = Self::try_trigger_new_era(session_index, is_genesis); - if maybe_new_era_validators.is_some() - && matches!(ForceEra::::get(), Forcing::ForceNew) + if maybe_new_era_validators.is_some() && + matches!(ForceEra::::get(), Forcing::ForceNew) { ForceEra::::put(Forcing::NotForcing); } @@ -470,12 +469,12 @@ impl Pallet { // TODO: this should be simplified #8911 CurrentEra::::put(0); ErasStartSessionIndex::::insert(&0, &start_session_index); - } + }, _ => (), } Self::deposit_event(Event::StakingElectionFailed); - return None; + return None } Self::deposit_event(Event::StakersElected); @@ -736,7 +735,7 @@ impl Pallet { Some(nominator) => { nominators_seen.saturating_inc(); nominator - } + }, None => break, }; @@ -926,7 +925,7 @@ impl ElectionDataProvider, T::MaxVali // We can't handle this case yet -- return an error. if maybe_max_len.map_or(false, |max_len| target_count > max_len as u32) { - return Err("Target snapshot too big"); + return Err("Target snapshot too big") } Ok(Self::get_npos_targets()) @@ -1234,7 +1233,7 @@ where add_db_reads_writes(1, 0); if active_era.is_none() { // This offence need not be re-submitted. - return consumed_weight; + return consumed_weight } active_era.expect("value checked not to be `None`; qed").index }; @@ -1280,7 +1279,7 @@ where // Skip if the validator is invulnerable. if invulnerables.contains(stash) { - continue; + continue } let unapplied = slashing::compute_slash::(slashing::SlashParams { diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index 629bd8b2a3032..db875331da2ea 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -982,23 +982,24 @@ pub mod pallet { ledger = ledger.consolidate_unlocked(current_era) } - let post_info_weight = - if ledger.unlocking.is_empty() && ledger.active < T::Currency::minimum_balance() { - // This account must have called `unbond()` with some value that caused the active - // portion to fall below existential deposit + will have no more unlocking chunks - // left. We can now safely remove all staking-related information. - Self::kill_stash(&stash, num_slashing_spans)?; - // Remove the lock. - T::Currency::remove_lock(STAKING_ID, &stash); - // This is worst case scenario, so we use the full weight and return None - None - } else { - // This was the consequence of a partial unbond. just update the ledger and move on. - Self::update_ledger(&controller, &ledger); + let post_info_weight = if ledger.unlocking.is_empty() && + ledger.active < T::Currency::minimum_balance() + { + // This account must have called `unbond()` with some value that caused the active + // portion to fall below existential deposit + will have no more unlocking chunks + // left. We can now safely remove all staking-related information. + Self::kill_stash(&stash, num_slashing_spans)?; + // Remove the lock. + T::Currency::remove_lock(STAKING_ID, &stash); + // This is worst case scenario, so we use the full weight and return None + None + } else { + // This was the consequence of a partial unbond. just update the ledger and move on. + Self::update_ledger(&controller, &ledger); - // This is only an update, so we use less overall weight. - Some(T::WeightInfo::withdraw_unbonded_update(num_slashing_spans)) - }; + // This is only an update, so we use less overall weight. + Some(T::WeightInfo::withdraw_unbonded_update(num_slashing_spans)) + }; // `old_total` should never be less than the new total because // `consolidate_unlocked` strictly subtracts balance. diff --git a/frame/support/src/lib.rs b/frame/support/src/lib.rs index a958c1a117641..a711fdbc3a8d8 100644 --- a/frame/support/src/lib.rs +++ b/frame/support/src/lib.rs @@ -741,7 +741,7 @@ pub use frame_support_procedural::crate_to_crate_version; #[macro_export] macro_rules! fail { ( $y:expr ) => {{ - return Err($y.into()); + return Err($y.into()) }}; } diff --git a/frame/support/src/storage/bounded_vec.rs b/frame/support/src/storage/bounded_vec.rs index a3cc5edab2014..8a8d0e346b100 100644 --- a/frame/support/src/storage/bounded_vec.rs +++ b/frame/support/src/storage/bounded_vec.rs @@ -78,7 +78,7 @@ impl> Decode for BoundedVec { fn decode(input: &mut I) -> Result { let inner = Vec::::decode(input)?; if inner.len() > S::get() as usize { - return Err("BoundedVec exceeds its limit".into()); + return Err("BoundedVec exceeds its limit".into()) } Ok(Self(inner, PhantomData)) } diff --git a/frame/support/test/tests/derive_no_bound_ui/ord.rs b/frame/support/test/tests/derive_no_bound_ui/ord.rs index d8b484d82ffdc..7d4e1305f850f 100644 --- a/frame/support/test/tests/derive_no_bound_ui/ord.rs +++ b/frame/support/test/tests/derive_no_bound_ui/ord.rs @@ -9,4 +9,4 @@ struct Foo { c: T::C, } -fn main() {} \ No newline at end of file +fn main() {} diff --git a/primitives/core/src/crypto.rs b/primitives/core/src/crypto.rs index 1b092d01d4b67..78f9029faacd2 100644 --- a/primitives/core/src/crypto.rs +++ b/primitives/core/src/crypto.rs @@ -250,7 +250,7 @@ pub trait Ss58Codec: Sized + AsMut<[u8]> + AsRef<[u8]> + Default { let data = s.from_base58().map_err(|_| PublicError::BadBase58)?; if data.len() < 2 { - return Err(PublicError::BadLength); + return Err(PublicError::BadLength) } let (prefix_len, ident) = match data[0] { 0..=63 => (1, data[0] as u16), @@ -263,22 +263,22 @@ pub trait Ss58Codec: Sized + AsMut<[u8]> + AsRef<[u8]> + Default { let lower = (data[0] << 2) | (data[1] >> 6); let upper = data[1] & 0b00111111; (2, (lower as u16) | ((upper as u16) << 8)) - } + }, _ => return Err(PublicError::UnknownVersion), }; if data.len() != prefix_len + body_len + CHECKSUM_LEN { - return Err(PublicError::BadLength); + return Err(PublicError::BadLength) } let format = ident.into(); if !Self::format_is_allowed(format) { - return Err(PublicError::FormatNotAllowed); + return Err(PublicError::FormatNotAllowed) } let hash = ss58hash(&data[0..body_len + prefix_len]); let checksum = &hash.as_bytes()[0..CHECKSUM_LEN]; if data[body_len + prefix_len..body_len + prefix_len + CHECKSUM_LEN] != *checksum { // Invalid checksum. - return Err(PublicError::InvalidChecksum); + return Err(PublicError::InvalidChecksum) } res.as_mut().copy_from_slice(&data[prefix_len..body_len + prefix_len]); Ok((res, format)) @@ -309,7 +309,7 @@ pub trait Ss58Codec: Sized + AsMut<[u8]> + AsRef<[u8]> + Default { // lower bits of the upper byte in the low pos let second = ((ident >> 8) as u8) | ((ident & 0b0000_0000_0000_0011) as u8) << 6; vec![first | 0b01000000, second] - } + }, _ => unreachable!("masked out the upper two bits; qed"), }; v.extend(self.as_ref()); @@ -402,7 +402,7 @@ impl + AsRef<[u8]> + Default + Derive> Ss58Codec for T { r.as_mut().copy_from_slice(&d); r } else { - return Err(PublicError::BadLength); + return Err(PublicError::BadLength) } } else { Self::from_ss58check(s)? @@ -951,7 +951,7 @@ impl<'a> TryFrom<&'a str> for KeyTypeId { fn try_from(x: &'a str) -> Result { let b = x.as_bytes(); if b.len() != 4 { - return Err(()); + return Err(()) } let mut res = KeyTypeId::default(); res.0.copy_from_slice(&b[0..4]); @@ -976,7 +976,7 @@ impl sp_std::fmt::Display for CryptoTypePublicPair { Ok(id) => id.to_string(), Err(_) => { format!("{:#?}", self.0) - } + }, }; write!(f, "{}-{}", id, HexDisplay::from(&self.1)) } @@ -1106,16 +1106,14 @@ mod tests { password, path: path.into_iter().chain(path_iter).collect(), }, - TestPair::GeneratedFromPhrase { phrase, password } => { - TestPair::Standard { phrase, password, path: path_iter.collect() } - } - x => { + TestPair::GeneratedFromPhrase { phrase, password } => + TestPair::Standard { phrase, password, path: path_iter.collect() }, + x => if path_iter.count() == 0 { x } else { - return Err(()); - } - } + return Err(()) + }, }, None, )) diff --git a/primitives/runtime/src/traits.rs b/primitives/runtime/src/traits.rs index 15e3d7b0644b1..12241487159ea 100644 --- a/primitives/runtime/src/traits.rs +++ b/primitives/runtime/src/traits.rs @@ -1197,7 +1197,7 @@ impl<'a, T: codec::Input> codec::Input for AppendZerosInput<'a, T> { into[i] = b; i += 1; } else { - break; + break } } i @@ -1276,7 +1276,7 @@ impl AccountIdConver fn try_from_sub_account(x: &T) -> Option<(Self, S)> { x.using_encoded(|d| { if &d[0..4] != Id::TYPE_ID { - return None; + return None } let mut cursor = &d[4..]; let result = Decode::decode(&mut cursor).ok()?; diff --git a/primitives/staking/src/offence.rs b/primitives/staking/src/offence.rs index de78f084e9abd..53950e87c5ac3 100644 --- a/primitives/staking/src/offence.rs +++ b/primitives/staking/src/offence.rs @@ -104,7 +104,7 @@ impl sp_runtime::traits::Printable for OffenceError { Self::Other(e) => { "Other".print(); e.print(); - } + }, } } } From ba25494cdf307936e8fdc48e6a003fa00fa7d179 Mon Sep 17 00:00:00 2001 From: Georges Dib Date: Mon, 1 Nov 2021 21:33:46 +0000 Subject: [PATCH 75/80] missed one --- test-utils/runtime/src/lib.rs | 36 +++++++++++++++++------------------ 1 file changed, 17 insertions(+), 19 deletions(-) diff --git a/test-utils/runtime/src/lib.rs b/test-utils/runtime/src/lib.rs index 3008ca5e2d677..ed5e29b09096a 100644 --- a/test-utils/runtime/src/lib.rs +++ b/test-utils/runtime/src/lib.rs @@ -185,7 +185,7 @@ impl BlindCheckable for Extrinsic { fn check(self) -> Result { match self { Extrinsic::AuthoritiesChange(new_auth) => Ok(Extrinsic::AuthoritiesChange(new_auth)), - Extrinsic::Transfer { transfer, signature, exhaust_resources_when_not_first } => { + Extrinsic::Transfer { transfer, signature, exhaust_resources_when_not_first } => if sp_runtime::verify_encoded_lazy(&signature, &transfer, &transfer.from) { Ok(Extrinsic::Transfer { transfer, @@ -194,13 +194,11 @@ impl BlindCheckable for Extrinsic { }) } else { Err(InvalidTransaction::BadProof.into()) - } - } + }, Extrinsic::IncludeData(v) => Ok(Extrinsic::IncludeData(v)), Extrinsic::StorageChange(key, value) => Ok(Extrinsic::StorageChange(key, value)), - Extrinsic::ChangesTrieConfigUpdate(new_config) => { - Ok(Extrinsic::ChangesTrieConfigUpdate(new_config)) - } + Extrinsic::ChangesTrieConfigUpdate(new_config) => + Ok(Extrinsic::ChangesTrieConfigUpdate(new_config)), Extrinsic::OffchainIndexSet(key, value) => Ok(Extrinsic::OffchainIndexSet(key, value)), Extrinsic::OffchainIndexClear(key) => Ok(Extrinsic::OffchainIndexClear(key)), Extrinsic::Store(data) => Ok(Extrinsic::Store(data)), @@ -503,13 +501,13 @@ impl frame_support::traits::PalletInfo for Runtime { fn index() -> Option { let type_id = sp_std::any::TypeId::of::

(); if type_id == sp_std::any::TypeId::of::>() { - return Some(0); + return Some(0) } if type_id == sp_std::any::TypeId::of::>() { - return Some(1); + return Some(1) } if type_id == sp_std::any::TypeId::of::>() { - return Some(2); + return Some(2) } None @@ -517,13 +515,13 @@ impl frame_support::traits::PalletInfo for Runtime { fn name() -> Option<&'static str> { let type_id = sp_std::any::TypeId::of::

(); if type_id == sp_std::any::TypeId::of::>() { - return Some("System"); + return Some("System") } if type_id == sp_std::any::TypeId::of::>() { - return Some("Timestamp"); + return Some("Timestamp") } if type_id == sp_std::any::TypeId::of::>() { - return Some("Babe"); + return Some("Babe") } None @@ -531,13 +529,13 @@ impl frame_support::traits::PalletInfo for Runtime { fn module_name() -> Option<&'static str> { let type_id = sp_std::any::TypeId::of::

(); if type_id == sp_std::any::TypeId::of::>() { - return Some("system"); + return Some("system") } if type_id == sp_std::any::TypeId::of::>() { - return Some("pallet_timestamp"); + return Some("pallet_timestamp") } if type_id == sp_std::any::TypeId::of::>() { - return Some("pallet_babe"); + return Some("pallet_babe") } None @@ -546,13 +544,13 @@ impl frame_support::traits::PalletInfo for Runtime { use frame_support::traits::PalletInfoAccess as _; let type_id = sp_std::any::TypeId::of::

(); if type_id == sp_std::any::TypeId::of::>() { - return Some(system::Pallet::::crate_version()); + return Some(system::Pallet::::crate_version()) } if type_id == sp_std::any::TypeId::of::>() { - return Some(pallet_timestamp::Pallet::::crate_version()); + return Some(pallet_timestamp::Pallet::::crate_version()) } if type_id == sp_std::any::TypeId::of::>() { - return Some(pallet_babe::Pallet::::crate_version()); + return Some(pallet_babe::Pallet::::crate_version()) } None @@ -666,7 +664,7 @@ fn code_using_trie() -> u64 { let key: &[u8] = &v[i].0; let val: &[u8] = &v[i].1; if !t.insert(key, val).is_ok() { - return 101; + return 101 } } t From 77d320f0cada5b3f9e77cd1c1bbc752da02503ed Mon Sep 17 00:00:00 2001 From: Georges Dib Date: Mon, 1 Nov 2021 22:26:38 +0000 Subject: [PATCH 76/80] Fixing benchmarks --- frame/bags-list/remote-tests/src/snapshot.rs | 1 + frame/election-provider-multi-phase/src/benchmarking.rs | 9 ++++++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/frame/bags-list/remote-tests/src/snapshot.rs b/frame/bags-list/remote-tests/src/snapshot.rs index 6e186a65cb2b9..10ba06908b7a1 100644 --- a/frame/bags-list/remote-tests/src/snapshot.rs +++ b/frame/bags-list/remote-tests/src/snapshot.rs @@ -57,6 +57,7 @@ pub async fn execute( let voters = as ElectionDataProvider< Runtime::AccountId, Runtime::BlockNumber, + Runtime::MaxValidatorsCount, >>::voters(voter_limit) .unwrap(); diff --git a/frame/election-provider-multi-phase/src/benchmarking.rs b/frame/election-provider-multi-phase/src/benchmarking.rs index 17dc5c3a4bf64..5c41813ca9d77 100644 --- a/frame/election-provider-multi-phase/src/benchmarking.rs +++ b/frame/election-provider-multi-phase/src/benchmarking.rs @@ -158,7 +158,7 @@ fn set_up_data_provider(v: u32) { info, "setting up with voters = {} [degree = {}], targets = {}", v, - >::MaximumVotesPerVoter::get(), + >::MaximumVotesPerVoter::get(), t ); @@ -171,8 +171,11 @@ fn set_up_data_provider(v: u32) { }) .collect::>(); // we should always have enough voters to fill. - let max_votes = - >::MaximumVotesPerVoter::get() as usize; + let max_votes = >::MaximumVotesPerVoter::get() as usize; assert!(targets.len() > max_votes); targets.truncate(max_votes); From 451d306e52056b0b4fd5cb08b6306b0cf0a39c05 Mon Sep 17 00:00:00 2001 From: Georges Dib Date: Tue, 2 Nov 2021 22:41:51 +0000 Subject: [PATCH 77/80] Fixing benchmarks --- .../src/benchmarking.rs | 50 +++++++++++++------ .../election-provider-multi-phase/src/lib.rs | 18 +++++-- .../election-provider-multi-phase/src/mock.rs | 46 ++++++++++------- frame/election-provider-support/src/lib.rs | 2 +- frame/staking/src/pallet/impls.rs | 2 +- 5 files changed, 80 insertions(+), 38 deletions(-) diff --git a/frame/election-provider-multi-phase/src/benchmarking.rs b/frame/election-provider-multi-phase/src/benchmarking.rs index 5c41813ca9d77..d369922d8f34f 100644 --- a/frame/election-provider-multi-phase/src/benchmarking.rs +++ b/frame/election-provider-multi-phase/src/benchmarking.rs @@ -73,11 +73,14 @@ fn solution_with_size( let active_voters = (0..active_voters_count) .map(|i| { // chose a random subset of winners. - let winner_votes = winners - .as_slice() - .choose_multiple(&mut rng, >::LIMIT) - .cloned() - .collect::>(); + let winner_votes = BoundedVec::try_from( + winners + .as_slice() + .choose_multiple(&mut rng, >::LIMIT) + .cloned() + .collect::>(), + ) + .expect("Benchmarking adjustment may be needed"); let voter = frame_benchmarking::account::("Voter", i, SEED); (voter, stake, winner_votes) }) @@ -91,10 +94,13 @@ fn solution_with_size( .collect::>(); let rest_voters = (active_voters_count..size.voters) .map(|i| { - let votes = (&non_winners) - .choose_multiple(&mut rng, >::LIMIT) - .cloned() - .collect::>(); + let votes = BoundedVec::try_from( + (&non_winners) + .choose_multiple(&mut rng, >::LIMIT) + .cloned() + .collect::>(), + ) + .expect("Benchmarking adjustment may be needed"); let voter = frame_benchmarking::account::("Voter", i, SEED); (voter, stake, votes) }) @@ -113,6 +119,8 @@ fn solution_with_size( targets: targets.len() as u32, }); >::put(desired_targets); + let targets = + BoundedVec::<_, T::MaxTargets>::try_from(targets).expect("Benchmark adjustment needed"); >::put(RoundSnapshot { voters: all_voters.clone(), targets: targets.clone() }); // write the snapshot to staking or whoever is the data provider, in case it is needed further @@ -179,6 +187,17 @@ fn set_up_data_provider(v: u32) { assert!(targets.len() > max_votes); targets.truncate(max_votes); + let targets = + BoundedVec::< + _, + >::MaximumVotesPerVoter, + >::try_from(targets) + .expect("Just truncated"); + // fill voters. (0..v).for_each(|i| { let voter = frame_benchmarking::account::("Voter", i, SEED); @@ -252,11 +271,11 @@ frame_benchmarking::benchmarks! { create_snapshot_internal { // number of votes in snapshot. let v in (T::BenchmarkingConfig::VOTERS[0]) .. T::BenchmarkingConfig::VOTERS[1]; - // number of targets in snapshot. - let t in (T::BenchmarkingConfig::TARGETS[0]) .. T::BenchmarkingConfig::TARGETS[1]; + + let t = T::MaxTargets::get(); // we don't directly need the data-provider to be populated, but it is just easy to use it. - set_up_data_provider::(v, t); + set_up_data_provider::(v); let targets = T::DataProvider::targets(None)?; let voters = T::DataProvider::voters(None)?; let desired_targets = T::DataProvider::desired_targets()?; @@ -296,7 +315,7 @@ frame_benchmarking::benchmarks! { assert!(>::get().is_some()); assert!(>::get().is_some()); }: { - assert_ok!( as ElectionProvider>::elect()); + assert_ok!( as ElectionProvider>::elect()); } verify { assert!(>::queued_solution().is_none()); assert!(>::get().is_none()); @@ -400,7 +419,7 @@ frame_benchmarking::benchmarks! { // number of votes in snapshot. Fixed to maximum. let v = T::BenchmarkingConfig::MINER_MAXIMUM_VOTERS; - set_up_data_provider::(v, t); + set_up_data_provider::(v); let now = frame_system::Pallet::::block_number(); >::put(Phase::Unsigned((true, now))); >::create_snapshot().unwrap(); @@ -419,8 +438,9 @@ frame_benchmarking::benchmarks! { create_snapshot_memory { // number of votes in snapshot. Fixed to maximum. let v = T::BenchmarkingConfig::SNAPSHOT_MAXIMUM_VOTERS; + let t = T::MaxTargets::get(); - set_up_data_provider::(v, t); + set_up_data_provider::(v); assert!(>::snapshot().is_none()); }: { >::create_snapshot().map_err(|_| "could not create snapshot")?; diff --git a/frame/election-provider-multi-phase/src/lib.rs b/frame/election-provider-multi-phase/src/lib.rs index 0081132f33834..8d1544da2a111 100644 --- a/frame/election-provider-multi-phase/src/lib.rs +++ b/frame/election-provider-multi-phase/src/lib.rs @@ -1753,6 +1753,7 @@ mod tests { use frame_election_provider_support::ElectionProvider; use frame_support::{assert_noop, assert_ok}; use sp_npos_elections::Support; + use std::convert::TryFrom; #[test] fn phase_rotation_works() { @@ -1994,7 +1995,12 @@ mod tests { fn snapshot_too_big_failure_onchain_fallback() { // the `MockStaking` is designed such that if it has too many targets, it simply fails. ExtBuilder::default().build_and_execute(|| { - Targets::set((0..(TargetIndex::max_value() as AccountId) + 1).collect::>()); + Targets::set( + BoundedVec::try_from( + (0..(TargetIndex::max_value() as AccountId) + 1).collect::>(), + ) + .expect("Testing configuration needs changing"), + ); // Signed phase failed to open. roll_to(15); @@ -2016,7 +2022,10 @@ mod tests { // the `MockStaking` is designed such that if it has too many targets, it simply fails. ExtBuilder::default().build_and_execute(|| { Targets::set( - (0..(crate::mock::MaxValidatorsCount::get() as u64 + 1)).collect::>(), + BoundedVec::try_from( + (0..(TargetIndex::max_value() as AccountId) + 1).collect::>(), + ) + .expect("Testing configuration needs changing"), ); // Signed phase failed to open. @@ -2040,7 +2049,10 @@ mod tests { // and if the backup mode is nothing, we go into the emergency mode.. ExtBuilder::default().onchain_fallback(false).build_and_execute(|| { crate::mock::Targets::set( - (0..(TargetIndex::max_value() as AccountId) + 1).collect::>(), + BoundedVec::try_from( + (0..(TargetIndex::max_value() as AccountId) + 1).collect::>(), + ) + .expect("Testing configuration needs changing"), ); // Signed phase failed to open. diff --git a/frame/election-provider-multi-phase/src/mock.rs b/frame/election-provider-multi-phase/src/mock.rs index 9ec821a933d96..35866be272edc 100644 --- a/frame/election-provider-multi-phase/src/mock.rs +++ b/frame/election-provider-multi-phase/src/mock.rs @@ -254,17 +254,18 @@ impl pallet_balances::Config for Runtime { } parameter_types! { - pub static Targets: Vec = vec![10, 20, 30, 40]; - pub static Voters: Vec<(AccountId, VoteWeight, Vec)> = vec![ - (1, 10, vec![10, 20]), - (2, 10, vec![30, 40]), - (3, 10, vec![40]), - (4, 10, vec![10, 20, 30, 40]), + pub static Targets: BoundedVec = BoundedVec::try_from( + vec![10, 20, 30, 40]).expect("LIMIT >= 4"); + pub static Voters: Vec<(AccountId, VoteWeight, BoundedVec::LIMIT as u32 }>>)> = vec![ + (1, 10, BoundedVec::try_from(vec![10, 20]).expect("LIMIT >= 2")), + (2, 10, BoundedVec::try_from(vec![30, 40]).expect("LIMIT >= 2")), + (3, 10, BoundedVec::try_from(vec![40]).expect("LIMIT >= 1")), + (4, 10, BoundedVec::try_from(vec![10, 20, 30, 40]).expect("LIMIT >= 4")), // self votes. - (10, 10, vec![10]), - (20, 20, vec![20]), - (30, 30, vec![30]), - (40, 40, vec![40]), + (10, 10, BoundedVec::try_from(vec![10]).expect("LIMIT >= 1")), + (20, 20, BoundedVec::try_from(vec![20]).expect("LIMIT >= 1")), + (30, 30, BoundedVec::try_from(vec![30]).expect("LIMIT >= 1")), + (40, 40, BoundedVec::try_from(vec![40]).expect("LIMIT >= 1")), ]; pub static DesiredTargets: u32 = 2; @@ -442,8 +443,7 @@ impl ElectionDataProvider for StakingMock { fn targets( maybe_max_len: Option, ) -> data_provider::Result> { - let targets = BoundedVec::<_, MaxValidatorsCount>::try_from(Targets::get()) - .map_err(|_| "Targets too big")?; + let targets = Targets::get(); if maybe_max_len.map_or(false, |max_len| targets.len() > max_len) { return Err("Targets too big") @@ -487,8 +487,8 @@ impl ElectionDataProvider for StakingMock { #[cfg(feature = "runtime-benchmarks")] fn put_snapshot( - voters: Vec<(AccountId, VoteWeight, Vec)>, - targets: Vec, + voters: Vec<(AccountId, VoteWeight, BoundedVec)>, + targets: BoundedVec, _target_stake: Option, ) { Targets::set(targets); @@ -497,12 +497,16 @@ impl ElectionDataProvider for StakingMock { #[cfg(feature = "runtime-benchmarks")] fn clear() { - Targets::set(vec![]); + Targets::set(BoundedVec::default()); Voters::set(vec![]); } #[cfg(feature = "runtime-benchmarks")] - fn add_voter(voter: AccountId, weight: VoteWeight, targets: Vec) { + fn add_voter( + voter: AccountId, + weight: VoteWeight, + targets: BoundedVec, + ) { let mut current = Voters::get(); current.push((voter, weight, targets)); Voters::set(current); @@ -511,13 +515,17 @@ impl ElectionDataProvider for StakingMock { #[cfg(feature = "runtime-benchmarks")] fn add_target(target: AccountId) { let mut current = Targets::get(); - current.push(target); + current.try_push(target).expect("Benchamrk configuration needs adjustment"); Targets::set(current); // to be on-par with staking, we add a self vote as well. the stake is really not that // important. let mut current = Voters::get(); - current.push((target, ExistentialDeposit::get() as u64, vec![target])); + current.push(( + target, + ExistentialDeposit::get() as u64, + BoundedVec::try_from(vec![target]).expect("MaxValidatorsCount >= 1"), + )); Voters::set(current); } } @@ -553,6 +561,8 @@ impl ExtBuilder { self } pub fn add_voter(self, who: AccountId, stake: Balance, targets: Vec) -> Self { + let targets = + BoundedVec::try_from(targets).expect("Benchmark configuration may need changing"); VOTERS.with(|v| v.borrow_mut().push((who, stake, targets))); self } diff --git a/frame/election-provider-support/src/lib.rs b/frame/election-provider-support/src/lib.rs index a5448ce6d9819..daca9c59e01dd 100644 --- a/frame/election-provider-support/src/lib.rs +++ b/frame/election-provider-support/src/lib.rs @@ -232,7 +232,7 @@ pub trait ElectionDataProvider { #[cfg(any(feature = "runtime-benchmarks", test))] fn put_snapshot( _voters: Vec<(AccountId, VoteWeight, BoundedVec)>, - _targets: BoundedVec, + _targets: BoundedVec, _target_stake: Option, ) { } diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index bc97286683e6d..1ecdb8d43384f 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -1042,7 +1042,7 @@ impl ElectionDataProvider, T::MaxVali VoteWeight, BoundedVec, )>, - targets: BoundedVec, + targets: BoundedVec, target_stake: Option, ) { targets.into_iter().for_each(|v| { From 423b99c949cbc6e9d62c817f0e5e19317b468e50 Mon Sep 17 00:00:00 2001 From: Georges Dib Date: Tue, 2 Nov 2021 23:02:20 +0000 Subject: [PATCH 78/80] removing unneeded import --- frame/offences/src/tests.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/frame/offences/src/tests.rs b/frame/offences/src/tests.rs index bf1e3d6216116..b79909318aa49 100644 --- a/frame/offences/src/tests.rs +++ b/frame/offences/src/tests.rs @@ -19,8 +19,6 @@ #![cfg(test)] -use std::rc::Weak; - use super::*; use crate::mock::{ new_test_ext, offence_reports, report_id, with_on_offence_fractions, Event, Offence, Offences, From 04aed173cfea55b2ec3b805137112f7580b7021c Mon Sep 17 00:00:00 2001 From: Georges Dib Date: Thu, 11 Nov 2021 22:10:02 +0000 Subject: [PATCH 79/80] cargo fmt --- frame/support/procedural/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frame/support/procedural/src/lib.rs b/frame/support/procedural/src/lib.rs index fd026a85fb05a..7fedd64043ea7 100644 --- a/frame/support/procedural/src/lib.rs +++ b/frame/support/procedural/src/lib.rs @@ -26,8 +26,8 @@ mod debug_no_bound; mod default_no_bound; mod dummy_part_checker; mod key_prefix; -mod ord_no_bound; mod match_and_insert; +mod ord_no_bound; mod pallet; mod partial_eq_no_bound; mod storage; From d24c5fca0789aed9e142f7e049e157af8f707c87 Mon Sep 17 00:00:00 2001 From: Georges Dib Date: Thu, 11 Nov 2021 22:23:03 +0000 Subject: [PATCH 80/80] Add `max-encoded-len` feature to `sp-arithmetic` --- primitives/arithmetic/Cargo.toml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/primitives/arithmetic/Cargo.toml b/primitives/arithmetic/Cargo.toml index 139a04180828c..ce11823eea4af 100644 --- a/primitives/arithmetic/Cargo.toml +++ b/primitives/arithmetic/Cargo.toml @@ -17,8 +17,11 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = [ "derive", + "max-encoded-len", +] } +scale-info = { version = "1.0", default-features = false, features = [ + "derive", ] } -scale-info = { version = "1.0", default-features = false, features = ["derive"] } integer-sqrt = "0.1.2" static_assertions = "1.1.0" num-traits = { version = "0.2.8", default-features = false }