From acab2d103219f3d1a84371800fba7b06b6ef745f Mon Sep 17 00:00:00 2001 From: Ankan Date: Wed, 4 Jan 2023 03:52:48 +0100 Subject: [PATCH 001/162] paged exposure skeleton --- frame/staking/src/lib.rs | 5 +++-- frame/staking/src/pallet/impls.rs | 37 +++++++++++++++++++++++-------- frame/staking/src/pallet/mod.rs | 31 ++++++++++++++++++++++++-- primitives/staking/src/lib.rs | 3 +++ 4 files changed, 63 insertions(+), 13 deletions(-) diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index 3672056534b75..9884184273295 100644 --- a/frame/staking/src/lib.rs +++ b/frame/staking/src/lib.rs @@ -319,6 +319,7 @@ use sp_std::{collections::btree_map::BTreeMap, prelude::*}; pub use weights::WeightInfo; pub use pallet::{pallet::*, *}; +use sp_core::ConstU32; pub(crate) const LOG_TARGET: &str = "runtime::staking"; @@ -955,6 +956,6 @@ pub struct TestBenchmarkingConfig; #[cfg(feature = "std")] impl BenchmarkingConfig for TestBenchmarkingConfig { - type MaxValidators = frame_support::traits::ConstU32<100>; - type MaxNominators = frame_support::traits::ConstU32<100>; + type MaxValidators = ConstU32<100>; + type MaxNominators = ConstU32<100>; } diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index db9aeba6fb58e..3ee703984cc75 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -561,20 +561,27 @@ impl Pallet { >, new_planned_era: EraIndex, ) -> BoundedVec> { - let elected_stashes: BoundedVec<_, MaxWinnersOf> = exposures - .iter() - .cloned() - .map(|(x, _)| x) - .collect::>() - .try_into() - .expect("since we only map through exposures, size of elected_stashes is always same as exposures; qed"); - - // Populate stakers, exposures, and the snapshot of validator prefs. + // Populate elected stash, stakers, exposures, and the snapshot of validator prefs. let mut total_stake: BalanceOf = Zero::zero(); + let mut elected_stashes = Vec::with_capacity(exposures.len()); exposures.into_iter().for_each(|(stash, exposure)| { + // build elected stash + elected_stashes.push(stash); + total_stake = total_stake.saturating_add(exposure.total); >::insert(new_planned_era, &stash, &exposure); + // split exposure into T::ExposurePageSize chunks + let paged_exposure: BoundedVec< + Exposure>, + T::ExposureMaxPages, + > = Self::get_paged_exposure(exposure); + + paged_exposure.iter().enumerate().for_each(|page, exposure| { + >::insert((new_planned_era, &stash, page), &exposure); + }); + + // fixme: get rid of clipped exposure someday let mut exposure_clipped = exposure; let clipped_max_len = T::MaxNominatorRewardedPerValidator::get() as usize; if exposure_clipped.others.len() > clipped_max_len { @@ -584,6 +591,10 @@ impl Pallet { >::insert(&new_planned_era, &stash, exposure_clipped); }); + let elected_stashes: BoundedVec<_, MaxWinnersOf> = elected_stashes + .try_into() + .expect("elected_stashes.len() always equal to exposures.len(); qed"); + // Insert current era staking information >::insert(&new_planned_era, total_stake); @@ -605,6 +616,14 @@ impl Pallet { elected_stashes } + fn get_paged_exposure( + exposure: Exposure>, + ) -> BoundedVec>, T::ExposureMaxPages> { + let page_size = T::ExposurePageSize::get(); + let max_pages = T::ExposureMaxPages::get(); + + todo!() + } /// Consume a set of [`BoundedSupports`] from [`sp_npos_elections`] and collect them into a /// [`Exposure`]. fn collect_exposures( diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index 92502949ef1a0..644f766989a79 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -36,7 +36,7 @@ use sp_runtime::{ traits::{CheckedSub, SaturatedConversion, StaticLookup, Zero}, ArithmeticError, Perbill, Percent, }; -use sp_staking::{EraIndex, SessionIndex}; +use sp_staking::{EraIndex, PageIndex, SessionIndex}; use sp_std::prelude::*; mod impls; @@ -210,6 +210,12 @@ pub mod pallet { #[pallet::constant] type MaxNominatorRewardedPerValidator: Get; + #[pallet::constant] + type ExposurePageSize: Get; + + #[pallet::constant] + type ExposureMaxPages: 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; @@ -416,7 +422,7 @@ pub mod pallet { /// /// This is keyed fist by the era index to allow bulk deletion and then the stash account. /// - /// Is it removed after `HISTORY_DEPTH` eras. + /// It is removed after `HISTORY_DEPTH` eras. /// If stakers hasn't been set or has been removed then empty exposure is returned. #[pallet::storage] #[pallet::unbounded] @@ -431,6 +437,27 @@ pub mod pallet { ValueQuery, >; + /// Paginated exposure of a validator at given era. + /// + /// This is keyed first by the era index to allow bulk deletion, then the stash account and + /// finally the page. + /// + /// It is removed after `HISTORY_DEPTH` eras. + /// If stakers hasn't been set or has been removed then empty exposure is returned. + #[pallet::storage] + #[pallet::getter(fn paged_eras_stakers)] + #[pallet::unbounded] + pub type PagedErasStakers = StorageNMap< + _, + ( + NMapKey, + NMapKey, + NMapKey, + ), + Exposure>, + ValueQuery, + >; + /// Similar to `ErasStakers`, this holds the preferences of validators. /// /// This is keyed first by the era index to allow bulk deletion and then the stash account. diff --git a/primitives/staking/src/lib.rs b/primitives/staking/src/lib.rs index 9eb4a4890cdf8..ff15a9fc751c2 100644 --- a/primitives/staking/src/lib.rs +++ b/primitives/staking/src/lib.rs @@ -31,6 +31,9 @@ pub type SessionIndex = u32; /// Counter for the number of eras that have passed. pub type EraIndex = u32; +/// Counter for paged storage items. +pub type PageIndex = u32; + /// Trait describing something that implements a hook for any operations to perform when a staker is /// slashed. pub trait OnStakerSlash { From 256ca4c5762e13c9910d0df76980a12ef21f0650 Mon Sep 17 00:00:00 2001 From: Ankan Date: Wed, 4 Jan 2023 05:23:44 +0100 Subject: [PATCH 002/162] insignificant changes --- frame/staking/src/pallet/impls.rs | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index 3ee703984cc75..4dbcdc6d95bac 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -571,13 +571,8 @@ impl Pallet { total_stake = total_stake.saturating_add(exposure.total); >::insert(new_planned_era, &stash, &exposure); - // split exposure into T::ExposurePageSize chunks - let paged_exposure: BoundedVec< - Exposure>, - T::ExposureMaxPages, - > = Self::get_paged_exposure(exposure); - - paged_exposure.iter().enumerate().for_each(|page, exposure| { + // store paged exposure + Self::get_paged_exposure(exposure).iter().enumerate().for_each(|page, exposure| { >::insert((new_planned_era, &stash, page), &exposure); }); @@ -616,10 +611,12 @@ impl Pallet { elected_stashes } + fn get_paged_exposure( exposure: Exposure>, ) -> BoundedVec>, T::ExposureMaxPages> { let page_size = T::ExposurePageSize::get(); + // clip exposure if exceeds max_pages let max_pages = T::ExposureMaxPages::get(); todo!() From 0cabf5573a8bff7582b290bc5f70e2611a2926ea Mon Sep 17 00:00:00 2001 From: Ankan Date: Fri, 6 Jan 2023 15:01:55 +0100 Subject: [PATCH 003/162] add note on usage of twox hash --- frame/fast-unstake/src/lib.rs | 2 ++ frame/nomination-pools/src/lib.rs | 2 ++ frame/staking/src/pallet/mod.rs | 8 ++++++++ 3 files changed, 12 insertions(+) diff --git a/frame/fast-unstake/src/lib.rs b/frame/fast-unstake/src/lib.rs index f2faeebc13478..c0bffc4427a11 100644 --- a/frame/fast-unstake/src/lib.rs +++ b/frame/fast-unstake/src/lib.rs @@ -147,6 +147,8 @@ pub mod pallet { /// The map of all accounts wishing to be unstaked. /// /// Keeps track of `AccountId` wishing to unstake and it's corresponding deposit. + /// + /// TWOX-NOTE: SAFE since `AccountId` is a secure hash. #[pallet::storage] pub type Queue = CountedStorageMap<_, Twox64Concat, T::AccountId, BalanceOf>; diff --git a/frame/nomination-pools/src/lib.rs b/frame/nomination-pools/src/lib.rs index 99bfc8b8c36a5..3cb8abedda2fb 100644 --- a/frame/nomination-pools/src/lib.rs +++ b/frame/nomination-pools/src/lib.rs @@ -1277,6 +1277,8 @@ pub mod pallet { pub type MaxPoolMembersPerPool = StorageValue<_, u32, OptionQuery>; /// Active members. + /// + /// TWOX-NOTE: SAFE since `AccountId` is a secure hash. #[pallet::storage] pub type PoolMembers = CountedStorageMap<_, Twox64Concat, T::AccountId, PoolMember>; diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index 92502949ef1a0..ce4f2494621b4 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -292,6 +292,8 @@ pub mod pallet { pub type Invulnerables = StorageValue<_, Vec, ValueQuery>; /// Map from all locked "stash" accounts to the controller account. + /// + /// TWOX-NOTE: SAFE since `AccountId` is a secure hash. #[pallet::storage] #[pallet::getter(fn bonded)] pub type Bonded = StorageMap<_, Twox64Concat, T::AccountId, T::AccountId>; @@ -320,12 +322,16 @@ pub mod pallet { pub type Ledger = StorageMap<_, Blake2_128Concat, T::AccountId, StakingLedger>; /// Where the reward payment should be made. Keyed by stash. + /// + /// TWOX-NOTE: SAFE since `AccountId` is a secure hash. #[pallet::storage] #[pallet::getter(fn payee)] pub type Payee = StorageMap<_, Twox64Concat, T::AccountId, RewardDestination, ValueQuery>; /// The map from (wannabe) validator stash key to the preferences of that validator. + /// + /// TWOX-NOTE: SAFE since `AccountId` is a secure hash. #[pallet::storage] #[pallet::getter(fn validators)] pub type Validators = @@ -353,6 +359,8 @@ pub mod pallet { /// /// Lastly, if any of the nominators become non-decodable, they can be chilled immediately via /// [`Call::chill_other`] dispatchable by anyone. + /// + /// TWOX-NOTE: SAFE since `AccountId` is a secure hash. #[pallet::storage] #[pallet::getter(fn nominators)] pub type Nominators = From f65d7b683d435db5451505c4f5a75bd946f329e6 Mon Sep 17 00:00:00 2001 From: Ankan Date: Fri, 6 Jan 2023 18:51:27 +0100 Subject: [PATCH 004/162] impl paged exposure --- frame/staking/src/lib.rs | 2 +- frame/staking/src/pallet/impls.rs | 47 +++++++++++++++++++++++-------- frame/staking/src/pallet/mod.rs | 3 -- 3 files changed, 36 insertions(+), 16 deletions(-) diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index 9884184273295..88ecca54bad69 100644 --- a/frame/staking/src/lib.rs +++ b/frame/staking/src/lib.rs @@ -319,7 +319,7 @@ use sp_std::{collections::btree_map::BTreeMap, prelude::*}; pub use weights::WeightInfo; pub use pallet::{pallet::*, *}; -use sp_core::ConstU32; +use frame_support::traits::ConstU32; pub(crate) const LOG_TARGET: &str = "runtime::staking"; diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index 4dbcdc6d95bac..7c06a7e144e5d 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -30,6 +30,7 @@ use frame_support::{ }, weights::Weight, }; +use frame_support::traits::Len; use frame_system::{pallet_prelude::BlockNumberFor, RawOrigin}; use pallet_session::historical; use sp_runtime::{ @@ -566,17 +567,22 @@ impl Pallet { let mut elected_stashes = Vec::with_capacity(exposures.len()); exposures.into_iter().for_each(|(stash, exposure)| { // build elected stash - elected_stashes.push(stash); + elected_stashes.push(stash.clone()); total_stake = total_stake.saturating_add(exposure.total); >::insert(new_planned_era, &stash, &exposure); // store paged exposure - Self::get_paged_exposure(exposure).iter().enumerate().for_each(|page, exposure| { - >::insert((new_planned_era, &stash, page), &exposure); - }); + Self::get_paged_exposure(&exposure, T::ExposurePageSize::get() as usize).iter().enumerate().for_each( + |(page, paged_exposure)| { + >::insert( + (new_planned_era, &stash, page as u32), + &paged_exposure, + ); + }, + ); - // fixme: get rid of clipped exposure someday + // fixme: get rid of clipped exposure let mut exposure_clipped = exposure; let clipped_max_len = T::MaxNominatorRewardedPerValidator::get() as usize; if exposure_clipped.others.len() > clipped_max_len { @@ -611,16 +617,33 @@ impl Pallet { elected_stashes } + /// Takes a full set of exposure and splits it into `page_size` individual exposures. + fn get_paged_exposure( + exposure: &Exposure>, + page_size: usize, + ) -> Vec>> { + let individual_chunks = exposure.others.chunks(page_size); + let mut paged_exposure: Vec>> = Vec::with_capacity(Len::len(&individual_chunks)); - fn get_paged_exposure( - exposure: Exposure>, - ) -> BoundedVec>, T::ExposureMaxPages> { - let page_size = T::ExposurePageSize::get(); - // clip exposure if exceeds max_pages - let max_pages = T::ExposureMaxPages::get(); + // own balance that has not been accounted for in the paged exposure + let mut own_left = exposure.own; - todo!() + for chunk in individual_chunks { + let own = own_left; + let mut total: BalanceOf = own; + for individual in chunk.iter() { + total = total.saturating_add(individual.value); + } + + paged_exposure.push(Exposure { total, own, others: chunk.into() }); + + // subtract own that has been accounted + own_left = own_left.saturating_sub(own); + } + + paged_exposure } + /// Consume a set of [`BoundedSupports`] from [`sp_npos_elections`] and collect them into a /// [`Exposure`]. fn collect_exposures( diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index 5d09d9867f78d..3bad81e7c1168 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -213,9 +213,6 @@ pub mod pallet { #[pallet::constant] type ExposurePageSize: Get; - #[pallet::constant] - type ExposureMaxPages: 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; From e7f299c27529fc1b00f2fceeb26d03fd64b53c51 Mon Sep 17 00:00:00 2001 From: Ankan Date: Fri, 6 Jan 2023 21:14:08 +0100 Subject: [PATCH 005/162] paged as exposure function --- frame/staking/src/lib.rs | 25 ++++++++++++ frame/staking/src/mock.rs | 1 + frame/staking/src/pallet/impls.rs | 67 ++++++++++++++++--------------- 3 files changed, 61 insertions(+), 32 deletions(-) diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index 88ecca54bad69..a0512ab2492b8 100644 --- a/frame/staking/src/lib.rs +++ b/frame/staking/src/lib.rs @@ -733,6 +733,31 @@ impl Default for Exposure Exposure { + fn paged(&self, page_size: usize) -> Vec { + let individual_chunks = self.others.chunks(page_size); + let mut paged_exposure: Vec = Vec::with_capacity(individual_chunks.len()); + + // own balance that has not been accounted for in the paged exposure + let mut own_left = self.own; + + for chunk in individual_chunks { + let own = own_left; + let mut total = own; + for individual in chunk.iter() { + total = total.saturating_add(individual.value); + } + + paged_exposure.push(Exposure { total, own, others: chunk.iter().map(|c| IndividualExposure { who: c.who.clone(), value: c.value}).collect() }); + + // subtract own that has been accounted + own_left = own_left.saturating_sub(own); + } + + paged_exposure + } +} + /// A pending slash record. The value of the slash has been computed but not applied yet, /// rather deferred for several eras. #[derive(Encode, Decode, RuntimeDebug, TypeInfo)] diff --git a/frame/staking/src/mock.rs b/frame/staking/src/mock.rs index 843e452125a6e..264f2ce58a5ae 100644 --- a/frame/staking/src/mock.rs +++ b/frame/staking/src/mock.rs @@ -299,6 +299,7 @@ impl crate::pallet::pallet::Config for Test { type EraPayout = ConvertCurve; type NextNewSession = Session; type MaxNominatorRewardedPerValidator = ConstU32<64>; + type ExposurePageSize = ConstU32<10>; type OffendingValidatorsThreshold = OffendingValidatorsThreshold; type ElectionProvider = onchain::OnChainExecution; type GenesisElectionProvider = Self::ElectionProvider; diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index 7c06a7e144e5d..99d0ed08879e8 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -26,11 +26,10 @@ use frame_support::{ pallet_prelude::*, traits::{ Currency, CurrencyToVote, Defensive, DefensiveResult, EstimateNextNewSession, Get, - Imbalance, LockableCurrency, OnUnbalanced, TryCollect, UnixTime, WithdrawReasons, + Imbalance, Len, LockableCurrency, OnUnbalanced, TryCollect, UnixTime, WithdrawReasons, }, weights::Weight, }; -use frame_support::traits::Len; use frame_system::{pallet_prelude::BlockNumberFor, RawOrigin}; use pallet_session::historical; use sp_runtime::{ @@ -573,14 +572,16 @@ impl Pallet { >::insert(new_planned_era, &stash, &exposure); // store paged exposure - Self::get_paged_exposure(&exposure, T::ExposurePageSize::get() as usize).iter().enumerate().for_each( - |(page, paged_exposure)| { + exposure + .paged(T::ExposurePageSize::get() as usize) + .iter() + .enumerate() + .for_each(|(page, paged_exposure)| { >::insert( (new_planned_era, &stash, page as u32), &paged_exposure, ); - }, - ); + }); // fixme: get rid of clipped exposure let mut exposure_clipped = exposure; @@ -617,32 +618,34 @@ impl Pallet { elected_stashes } - /// Takes a full set of exposure and splits it into `page_size` individual exposures. - fn get_paged_exposure( - exposure: &Exposure>, - page_size: usize, - ) -> Vec>> { - let individual_chunks = exposure.others.chunks(page_size); - let mut paged_exposure: Vec>> = Vec::with_capacity(Len::len(&individual_chunks)); - - // own balance that has not been accounted for in the paged exposure - let mut own_left = exposure.own; - - for chunk in individual_chunks { - let own = own_left; - let mut total: BalanceOf = own; - for individual in chunk.iter() { - total = total.saturating_add(individual.value); - } - - paged_exposure.push(Exposure { total, own, others: chunk.into() }); - - // subtract own that has been accounted - own_left = own_left.saturating_sub(own); - } - - paged_exposure - } + // fixme : remove this + // /// Takes a full set of exposure and splits it into `page_size` individual exposures. + // fn get_paged_exposure( + // exposure: &Exposure>, + // page_size: usize, + // ) -> Vec>> { + // let individual_chunks = exposure.others.chunks(page_size); + // let mut paged_exposure: Vec>> = + // Vec::with_capacity(Len::len(&individual_chunks)); + // + // // own balance that has not been accounted for in the paged exposure + // let mut own_left = exposure.own; + // + // for chunk in individual_chunks { + // let own = own_left; + // let mut total: BalanceOf = own; + // for individual in chunk.iter() { + // total = total.saturating_add(individual.value); + // } + // + // paged_exposure.push(Exposure { total, own, others: chunk.into() }); + // + // // subtract own that has been accounted + // own_left = own_left.saturating_sub(own); + // } + // + // paged_exposure + // } /// Consume a set of [`BoundedSupports`] from [`sp_npos_elections`] and collect them into a /// [`Exposure`]. From b3f58d629cc96f6a32583ddb02d460d7b078e6ba Mon Sep 17 00:00:00 2001 From: Ankan Date: Sat, 7 Jan 2023 00:28:41 +0100 Subject: [PATCH 006/162] add test for paging exposure --- frame/staking/src/lib.rs | 2 +- frame/staking/src/pallet/impls.rs | 2 +- frame/staking/src/tests.rs | 34 +++++++++++++++++++++++++++++++ 3 files changed, 36 insertions(+), 2 deletions(-) diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index a0512ab2492b8..fcea4e33955ea 100644 --- a/frame/staking/src/lib.rs +++ b/frame/staking/src/lib.rs @@ -734,7 +734,7 @@ impl Default for Exposure Exposure { - fn paged(&self, page_size: usize) -> Vec { + fn in_chunks_of(&self, page_size: usize) -> Vec { let individual_chunks = self.others.chunks(page_size); let mut paged_exposure: Vec = Vec::with_capacity(individual_chunks.len()); diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index 99d0ed08879e8..32aaae89f95b8 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -573,7 +573,7 @@ impl Pallet { // store paged exposure exposure - .paged(T::ExposurePageSize::get() as usize) + .in_chunks_of(T::ExposurePageSize::get() as usize) .iter() .enumerate() .for_each(|(page, paged_exposure)| { diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index 46c3c97441938..f69e810e3f1ac 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -5766,6 +5766,40 @@ fn set_min_commission_works_with_admin_origin() { }) } +#[test] +fn can_page_exposure() { + let mut others: Vec> = vec![]; + let mut total_stake: Balance = 0; + // 19 nominators + for i in 1..20 { + let individual_stake: Balance = 100 * i as Balance; + others.push(IndividualExposure { who: i, value: individual_stake }); + total_stake += individual_stake; + } + let own_stake: Balance = 500; + total_stake += own_stake; + assert_eq!(total_stake, 19_500); + // build full exposure set + let exposure: Exposure = + Exposure { total: total_stake, own: own_stake, others }; + + // when + let paged_exposures: Vec> = exposure.clone().in_chunks_of(3); + + // then + assert_eq!(paged_exposures.len(), (19 / 3) + 1); + // first page stake = 500 (own) + 100 + 200 + 300 + assert!(matches!(paged_exposures[0], Exposure { total: 1100, own: 500, .. })); + // second page stake = 0 + 400 + 500 + 600 + assert!(matches!(paged_exposures[1], Exposure { total: 1500, own: 0, .. })); + // verify total stake is same as in the original exposure. + assert_eq!(paged_exposures.iter().map(|a| a.total).reduce(|a, b| a + b).unwrap(), 19_500); + // verify own stake is same as in the original exposure. + assert_eq!(paged_exposures.iter().map(|a| a.own).reduce(|a, b| a + b).unwrap(), 500); + // verify number of nominators are same as in the original exposure. + assert_eq!(paged_exposures.iter().map(|a| a.others.len()).reduce(|a, b| a + b).unwrap(), 19); +} + mod staking_interface { use frame_support::storage::with_storage_layer; use sp_staking::StakingInterface; From 661fab091ff4e42df422f9bedb5c6707e0eda863 Mon Sep 17 00:00:00 2001 From: Ankan Date: Sat, 7 Jan 2023 01:03:58 +0100 Subject: [PATCH 007/162] remove commented fn --- frame/staking/src/pallet/impls.rs | 31 +------------------------------ 1 file changed, 1 insertion(+), 30 deletions(-) diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index 32aaae89f95b8..3eb1c2ef9eae8 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -617,36 +617,7 @@ impl Pallet { elected_stashes } - - // fixme : remove this - // /// Takes a full set of exposure and splits it into `page_size` individual exposures. - // fn get_paged_exposure( - // exposure: &Exposure>, - // page_size: usize, - // ) -> Vec>> { - // let individual_chunks = exposure.others.chunks(page_size); - // let mut paged_exposure: Vec>> = - // Vec::with_capacity(Len::len(&individual_chunks)); - // - // // own balance that has not been accounted for in the paged exposure - // let mut own_left = exposure.own; - // - // for chunk in individual_chunks { - // let own = own_left; - // let mut total: BalanceOf = own; - // for individual in chunk.iter() { - // total = total.saturating_add(individual.value); - // } - // - // paged_exposure.push(Exposure { total, own, others: chunk.into() }); - // - // // subtract own that has been accounted - // own_left = own_left.saturating_sub(own); - // } - // - // paged_exposure - // } - + /// Consume a set of [`BoundedSupports`] from [`sp_npos_elections`] and collect them into a /// [`Exposure`]. fn collect_exposures( From 06d83fba28db964a19ada93da01ed5b74473e9f6 Mon Sep 17 00:00:00 2001 From: Ankan Date: Sat, 7 Jan 2023 01:04:50 +0100 Subject: [PATCH 008/162] cargo fmt --- frame/staking/src/lib.rs | 17 ++++++++++++++--- frame/staking/src/pallet/impls.rs | 2 +- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index fcea4e33955ea..a91011839f5a1 100644 --- a/frame/staking/src/lib.rs +++ b/frame/staking/src/lib.rs @@ -318,8 +318,8 @@ use sp_staking::{ use sp_std::{collections::btree_map::BTreeMap, prelude::*}; pub use weights::WeightInfo; -pub use pallet::{pallet::*, *}; use frame_support::traits::ConstU32; +pub use pallet::{pallet::*, *}; pub(crate) const LOG_TARGET: &str = "runtime::staking"; @@ -733,7 +733,11 @@ impl Default for Exposure Exposure { +impl< + AccountId: Clone, + Balance: Default + HasCompact + sp_runtime::traits::AtLeast32BitUnsigned + Copy, + > Exposure +{ fn in_chunks_of(&self, page_size: usize) -> Vec { let individual_chunks = self.others.chunks(page_size); let mut paged_exposure: Vec = Vec::with_capacity(individual_chunks.len()); @@ -748,7 +752,14 @@ impl Pallet { elected_stashes } - + /// Consume a set of [`BoundedSupports`] from [`sp_npos_elections`] and collect them into a /// [`Exposure`]. fn collect_exposures( From 02e3ffc4ac43b0592e8a2c5803292595f34bb385 Mon Sep 17 00:00:00 2001 From: Ankan Date: Sat, 7 Jan 2023 01:06:37 +0100 Subject: [PATCH 009/162] more fmt --- frame/staking/src/lib.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index a91011839f5a1..aa43d554640d8 100644 --- a/frame/staking/src/lib.rs +++ b/frame/staking/src/lib.rs @@ -733,10 +733,8 @@ impl Default for Exposure Exposure +impl + Exposure { fn in_chunks_of(&self, page_size: usize) -> Vec { let individual_chunks = self.others.chunks(page_size); From c924bfcabc8bfa7bac8169e468610f7ded56936a Mon Sep 17 00:00:00 2001 From: Ankan Date: Sat, 7 Jan 2023 01:08:46 +0100 Subject: [PATCH 010/162] remove unnecessary bound --- frame/staking/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index aa43d554640d8..b35f82aa658b8 100644 --- a/frame/staking/src/lib.rs +++ b/frame/staking/src/lib.rs @@ -733,7 +733,7 @@ impl Default for Exposure +impl Exposure { fn in_chunks_of(&self, page_size: usize) -> Vec { From 108cd16a304f7920f5fdcce22282c13b7707c8f1 Mon Sep 17 00:00:00 2001 From: Ankan Date: Sun, 8 Jan 2023 21:09:04 +0100 Subject: [PATCH 011/162] add wrapper struct and refactor --- frame/staking/src/pallet/impls.rs | 31 +++---------- frame/staking/src/pallet/mod.rs | 76 ++++++++++++++++++++++++++++++- 2 files changed, 80 insertions(+), 27 deletions(-) diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index 462339a235d28..f7655ba497a40 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -33,6 +33,7 @@ use frame_support::{ use frame_system::{pallet_prelude::BlockNumberFor, RawOrigin}; use pallet_session::historical; use sp_runtime::{ + generic::Era, traits::{Bounded, Convert, One, SaturatedConversion, Saturating, StaticLookup, Zero}, Perbill, }; @@ -564,41 +565,21 @@ impl Pallet { // Populate elected stash, stakers, exposures, and the snapshot of validator prefs. let mut total_stake: BalanceOf = Zero::zero(); let mut elected_stashes = Vec::with_capacity(exposures.len()); + exposures.into_iter().for_each(|(stash, exposure)| { // build elected stash elected_stashes.push(stash.clone()); - + // accumulate total stake total_stake = total_stake.saturating_add(exposure.total); - >::insert(new_planned_era, &stash, &exposure); - - // store paged exposure - exposure - .in_chunks_of(T::ExposurePageSize::get() as usize) - .iter() - .enumerate() - .for_each(|(page, paged_exposure)| { - >::insert( - (new_planned_era, &stash, page as u32), - &paged_exposure, - ); - }); - - // fixme: get rid of clipped exposure - let mut exposure_clipped = exposure; - 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); - } - >::insert(&new_planned_era, &stash, exposure_clipped); + // store staker exposure for this era + EraInfo::::set_validator_exposure(new_planned_era, &stash, exposure); }); let elected_stashes: BoundedVec<_, MaxWinnersOf> = elected_stashes .try_into() .expect("elected_stashes.len() always equal to exposures.len(); qed"); - // Insert current era staking information - >::insert(&new_planned_era, total_stake); + EraInfo::::set_total_stake(new_planned_era, total_stake); // Collect the pref of all winners. for stash in &elected_stashes { diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index 3bad81e7c1168..b874946532464 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -450,9 +450,9 @@ pub mod pallet { /// It is removed after `HISTORY_DEPTH` eras. /// If stakers hasn't been set or has been removed then empty exposure is returned. #[pallet::storage] - #[pallet::getter(fn paged_eras_stakers)] + #[pallet::getter(fn eras_stakers_paged)] #[pallet::unbounded] - pub type PagedErasStakers = StorageNMap< + pub type ErasStakersPaged = StorageNMap< _, ( NMapKey, @@ -463,6 +463,26 @@ pub mod pallet { ValueQuery, >; + /// History of rewards claimed by validator by era and page. + /// + /// This is keyed by era and validator stash which maps to the set of page indexes which have + /// been claimed. + /// + /// It is removed after `HISTORY_DEPTH` eras. + #[pallet::storage] + #[pallet::getter(fn claimed_rewards)] + #[pallet::unbounded] + pub type ClaimedRewards = StorageDoubleMap< + _, + Twox64Concat, + EraIndex, + Twox64Concat, + // Validator stash + T::AccountId, + Vec, + ValueQuery, + >; + /// Similar to `ErasStakers`, this holds the preferences of validators. /// /// This is keyed first by the era index to allow bulk deletion and then the stash account. @@ -583,6 +603,58 @@ pub mod pallet { #[pallet::getter(fn current_planned_session)] pub type CurrentPlannedSession = StorageValue<_, SessionIndex, ValueQuery>; + /// Wrapper struct for `ErasRewards`, `ClaimedRewards`, `ErasRewardsClipped`, + /// `ErasRewardsPaged`, `ErasTotalStake`. + pub(crate) struct EraInfo(sp_std::marker::PhantomData); + impl EraInfo { + pub(crate) fn is_rewards_claimed( + era: EraIndex, + validator: T::AccountId, + page: PageIndex, + ) -> bool { + ClaimedRewards::::get(era, validator).iter().find(|&&p| page == p).is_some() + } + + pub(crate) fn set_rewards_as_claimed( + era: EraIndex, + validator: T::AccountId, + page: PageIndex, + ) { + ClaimedRewards::::mutate(era, validator, |pages| { + pages.push(page); + }) + } + + pub(crate) fn set_validator_exposure( + era: EraIndex, + validator: &T::AccountId, + exposure: Exposure>, + ) { + >::insert(era, &validator, &exposure); + + exposure + .in_chunks_of(T::ExposurePageSize::get() as usize) + .iter() + .enumerate() + .for_each(|(page, paged_exposure)| { + >::insert((era, &validator, page as u32), &paged_exposure); + }); + + // FIXME: get rid of clipped exposure + let mut exposure_clipped = exposure; + 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); + } + >::insert(era, &validator, exposure_clipped); + } + + pub(crate) fn set_total_stake(era: EraIndex, total_stake: BalanceOf) { + >::insert(era, total_stake); + } + } + /// Indices of validators that have offended in the active era and whether they are currently /// disabled. /// From e14eab3dfa3c5d37888056d42b9a15b7bb36739c Mon Sep 17 00:00:00 2001 From: Ankan Date: Sun, 8 Jan 2023 21:41:58 +0100 Subject: [PATCH 012/162] create temp fn that checks both ledger and new claimed_rewards --- frame/staking/src/pallet/impls.rs | 38 +++++++++++++++++++------------ frame/staking/src/pallet/mod.rs | 15 +++++++++--- 2 files changed, 35 insertions(+), 18 deletions(-) diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index f7655ba497a40..b059d9ece6da4 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -160,29 +160,35 @@ impl Pallet { })?; let mut ledger = >::get(&controller).ok_or(Error::::NotController)?; + // clean up older claimed rewards ledger .claimed_rewards .retain(|&x| x >= current_era.saturating_sub(history_depth)); + >::insert(&controller, &ledger); - match ledger.claimed_rewards.binary_search(&era) { - Ok(_) => - return Err(Error::::AlreadyClaimed - .with_weight(T::WeightInfo::payout_stakers_alive_staked(0))), - Err(pos) => ledger - .claimed_rewards - .try_insert(pos, era) - // Since we retain era entries in `claimed_rewards` only upto - // `HistoryDepth`, following bound is always expected to be - // satisfied. - .defensive_map_err(|_| Error::::BoundNotMet)?, + // todo(ank4n): remove + // match ledger.claimed_rewards.binary_search(&era) { + // Ok(_) => + // return Err(Error::::AlreadyClaimed + // .with_weight(T::WeightInfo::payout_stakers_alive_staked(0))), + // Err(pos) => ledger + // .claimed_rewards + // .try_insert(pos, era) + // // Since we retain era entries in `claimed_rewards` only upto + // // `HistoryDepth`, following bound is always expected to be + // // satisfied. + // .defensive_map_err(|_| Error::::BoundNotMet)?, + // } + + if EraInfo::::temp_is_rewards_claimed(era, &ledger, &ledger.stash, 0) { + return Err(Error::::AlreadyClaimed + .with_weight(T::WeightInfo::payout_stakers_alive_staked(0))) + } else { + EraInfo::::set_rewards_as_claimed(era, &ledger.stash, 0); } - let exposure = >::get(&era, &ledger.stash); - // Input data seems good, no errors allowed after this point - >::insert(&controller, &ledger); - // Get Era reward points. It has TOTAL and INDIVIDUAL // Find the fraction of the era reward that belongs to the validator // Take that fraction of the eras rewards to split to nominator and validator @@ -190,6 +196,8 @@ impl Pallet { // Then look at the validator, figure out the proportion of their reward // which goes to them and each of their nominators. + let exposure = >::get(&era, &ledger.stash); + let era_reward_points = >::get(&era); let total_reward_points = era_reward_points.total; let validator_reward_points = era_reward_points diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index b874946532464..38508d98c2ddd 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -607,17 +607,26 @@ pub mod pallet { /// `ErasRewardsPaged`, `ErasTotalStake`. pub(crate) struct EraInfo(sp_std::marker::PhantomData); impl EraInfo { - pub(crate) fn is_rewards_claimed( + + // TODO: Clean up in 84 eras + // looks at ledger for older non paged rewards, and `ClaimedRewards` for newer paged rewards. + pub(crate) fn temp_is_rewards_claimed( era: EraIndex, - validator: T::AccountId, + ledger: &StakingLedger, + validator: &T::AccountId, page: PageIndex, ) -> bool { + ledger.claimed_rewards.binary_search(&era).is_ok() && + Self::is_rewards_claimed(era, validator, page) + } + + fn is_rewards_claimed(era: EraIndex, validator: &T::AccountId, page: PageIndex) -> bool { ClaimedRewards::::get(era, validator).iter().find(|&&p| page == p).is_some() } pub(crate) fn set_rewards_as_claimed( era: EraIndex, - validator: T::AccountId, + validator: &T::AccountId, page: PageIndex, ) { ClaimedRewards::::mutate(era, validator, |pages| { From 70b8c7f424e0e8d5c4e569cbccb25d9093bec76b Mon Sep 17 00:00:00 2001 From: Ankan Date: Sun, 8 Jan 2023 22:24:00 +0100 Subject: [PATCH 013/162] incomplete, paged extrinisic to pay stakers --- frame/staking/src/pallet/impls.rs | 13 ++++++------- frame/staking/src/pallet/mod.rs | 29 +++++++++++++++++++++++------ 2 files changed, 29 insertions(+), 13 deletions(-) diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index b059d9ece6da4..43086616bebfa 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -37,10 +37,7 @@ use sp_runtime::{ traits::{Bounded, Convert, One, SaturatedConversion, Saturating, StaticLookup, Zero}, Perbill, }; -use sp_staking::{ - offence::{DisableStrategy, OffenceDetails, OnOffenceHandler}, - EraIndex, SessionIndex, Stake, StakingInterface, -}; +use sp_staking::{offence::{DisableStrategy, OffenceDetails, OnOffenceHandler}, EraIndex, SessionIndex, Stake, StakingInterface, PageIndex}; use sp_std::prelude::*; use crate::{ @@ -135,6 +132,7 @@ impl Pallet { pub(super) fn do_payout_stakers( validator_stash: T::AccountId, era: EraIndex, + page: PageIndex, ) -> DispatchResultWithPostInfo { // Validate input data let current_era = CurrentEra::::get().ok_or_else(|| { @@ -180,11 +178,11 @@ impl Pallet { // .defensive_map_err(|_| Error::::BoundNotMet)?, // } - if EraInfo::::temp_is_rewards_claimed(era, &ledger, &ledger.stash, 0) { + if EraInfo::::temp_is_rewards_claimed(era, &ledger, &ledger.stash, page) { return Err(Error::::AlreadyClaimed .with_weight(T::WeightInfo::payout_stakers_alive_staked(0))) } else { - EraInfo::::set_rewards_as_claimed(era, &ledger.stash, 0); + EraInfo::::set_rewards_as_claimed(era, &ledger.stash, page); } // Input data seems good, no errors allowed after this point @@ -196,7 +194,8 @@ impl Pallet { // Then look at the validator, figure out the proportion of their reward // which goes to them and each of their nominators. - let exposure = >::get(&era, &ledger.stash); + let exposure = EraInfo::::get_validator_exposure(era, &ledger.stash, page); + // let exposure = EraInfo::::get_validator_exposure(&era, &ledger.stash, page); let era_reward_points = >::get(&era); let total_reward_points = era_reward_points.total; diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index 38508d98c2ddd..1d4c012e7761b 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -59,6 +59,7 @@ pub(crate) const SPECULATIVE_NUM_SPANS: u32 = 32; #[frame_support::pallet] pub mod pallet { use frame_election_provider_support::ElectionDataProvider; + use frame_support::metadata::StorageEntryModifier::Default; use crate::BenchmarkingConfig; @@ -460,7 +461,7 @@ pub mod pallet { NMapKey, ), Exposure>, - ValueQuery, + OptionQuery, >; /// History of rewards claimed by validator by era and page. @@ -607,9 +608,9 @@ pub mod pallet { /// `ErasRewardsPaged`, `ErasTotalStake`. pub(crate) struct EraInfo(sp_std::marker::PhantomData); impl EraInfo { - - // TODO: Clean up in 84 eras - // looks at ledger for older non paged rewards, and `ClaimedRewards` for newer paged rewards. + // TODO(ank4n): doc and clean up in 84 eras + // looks at ledger for older non paged rewards, and `ClaimedRewards` for newer paged + // rewards. pub(crate) fn temp_is_rewards_claimed( era: EraIndex, ledger: &StakingLedger, @@ -624,6 +625,19 @@ pub mod pallet { ClaimedRewards::::get(era, validator).iter().find(|&&p| page == p).is_some() } + pub(crate) fn get_validator_exposure( + era: EraIndex, + validator: &T::AccountId, + page: PageIndex, + ) -> Exposure> { + return match >::get((era, validator, page)) { + Some(paged_exposure) => paged_exposure, + // only return clipped exposure if page zero and no paged exposure entry + None if page == 0 => >::get(&era, &ledger.stash), + _ => Default::Default(), + } + } + pub(crate) fn set_rewards_as_claimed( era: EraIndex, validator: &T::AccountId, @@ -649,7 +663,7 @@ pub mod pallet { >::insert((era, &validator, page as u32), &paged_exposure); }); - // FIXME: get rid of clipped exposure + // fixme(ank4n): no need to keep storing new clipped exposure let mut exposure_clipped = exposure; let clipped_max_len = T::MaxNominatorRewardedPerValidator::get() as usize; if exposure_clipped.others.len() > clipped_max_len { @@ -1612,6 +1626,8 @@ pub mod pallet { /// NOTE: weights are assuming that payouts are made to alive stash account (Staked). /// Paying even a dead controller is cheaper weight-wise. We don't do any refunds here. /// # + // todo(ank4n): fix weights and breaking change. But leaving it will add to confusion and + // missed rewards. #[pallet::call_index(18)] #[pallet::weight(T::WeightInfo::payout_stakers_alive_staked( T::MaxNominatorRewardedPerValidator::get() @@ -1620,9 +1636,10 @@ pub mod pallet { origin: OriginFor, validator_stash: T::AccountId, era: EraIndex, + page: PageIndex, ) -> DispatchResultWithPostInfo { ensure_signed(origin)?; - Self::do_payout_stakers(validator_stash, era) + Self::do_payout_stakers(validator_stash, era, page) } /// Rebond a portion of the stash scheduled to be unlocked. From eac23e0d8976023dcc89f3cea635aa3e323a3dcb Mon Sep 17 00:00:00 2001 From: Ankan Date: Tue, 10 Jan 2023 21:56:48 +0100 Subject: [PATCH 014/162] fix names --- frame/staking/src/pallet/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index 1d4c012e7761b..6c2a2e2505622 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -604,8 +604,8 @@ pub mod pallet { #[pallet::getter(fn current_planned_session)] pub type CurrentPlannedSession = StorageValue<_, SessionIndex, ValueQuery>; - /// Wrapper struct for `ErasRewards`, `ClaimedRewards`, `ErasRewardsClipped`, - /// `ErasRewardsPaged`, `ErasTotalStake`. + /// Wrapper struct for `ErasStakers`, `ClaimedRewards`, `ErasStakersClipped`, + /// `ErasStakersPaged`, `ErasTotalStake`. pub(crate) struct EraInfo(sp_std::marker::PhantomData); impl EraInfo { // TODO(ank4n): doc and clean up in 84 eras From 1cd79ff0fe2ff011e97b2d2729d441a188b2eb94 Mon Sep 17 00:00:00 2001 From: Ankan Date: Sat, 14 Jan 2023 21:03:11 +0100 Subject: [PATCH 015/162] add page as 0 for payout stakers, tests failing currently. --- frame/staking/src/benchmarking.rs | 3 +- frame/staking/src/mock.rs | 2 +- frame/staking/src/pallet/impls.rs | 25 +++------ frame/staking/src/pallet/mod.rs | 21 ++------ frame/staking/src/tests.rs | 85 +++++++++++++++++++------------ 5 files changed, 67 insertions(+), 69 deletions(-) diff --git a/frame/staking/src/benchmarking.rs b/frame/staking/src/benchmarking.rs index b3d32b26ec1f7..0665bac4aff31 100644 --- a/frame/staking/src/benchmarking.rs +++ b/frame/staking/src/benchmarking.rs @@ -990,7 +990,8 @@ mod tests { assert_ok!(Staking::payout_stakers( RuntimeOrigin::signed(1337), validator_stash, - current_era + current_era, + 0 )); let new_free_balance = Balances::free_balance(&validator_stash); diff --git a/frame/staking/src/mock.rs b/frame/staking/src/mock.rs index 6716b0a702e5f..4265d60fd1b26 100644 --- a/frame/staking/src/mock.rs +++ b/frame/staking/src/mock.rs @@ -760,7 +760,7 @@ pub(crate) fn make_all_reward_payment(era: EraIndex) { // reward validators for validator_controller in validators_with_reward.iter().filter_map(Staking::bonded) { let ledger = >::get(&validator_controller).unwrap(); - assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), ledger.stash, era)); + assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), ledger.stash, era, 0)); } } diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index 43086616bebfa..b1fc791a84065 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -25,19 +25,21 @@ use frame_support::{ dispatch::WithPostDispatchInfo, pallet_prelude::*, traits::{ - Currency, CurrencyToVote, Defensive, DefensiveResult, EstimateNextNewSession, Get, - Imbalance, Len, LockableCurrency, OnUnbalanced, TryCollect, UnixTime, WithdrawReasons, + Currency, CurrencyToVote, Defensive, EstimateNextNewSession, Get, Imbalance, Len, + LockableCurrency, OnUnbalanced, TryCollect, UnixTime, WithdrawReasons, }, weights::Weight, }; use frame_system::{pallet_prelude::BlockNumberFor, RawOrigin}; use pallet_session::historical; use sp_runtime::{ - generic::Era, traits::{Bounded, Convert, One, SaturatedConversion, Saturating, StaticLookup, Zero}, Perbill, }; -use sp_staking::{offence::{DisableStrategy, OffenceDetails, OnOffenceHandler}, EraIndex, SessionIndex, Stake, StakingInterface, PageIndex}; +use sp_staking::{ + offence::{DisableStrategy, OffenceDetails, OnOffenceHandler}, + EraIndex, PageIndex, SessionIndex, Stake, StakingInterface, +}; use sp_std::prelude::*; use crate::{ @@ -139,6 +141,7 @@ impl Pallet { Error::::InvalidEraToReward .with_weight(T::WeightInfo::payout_stakers_alive_staked(0)) })?; + let history_depth = T::HistoryDepth::get(); ensure!( era <= current_era && era >= current_era.saturating_sub(history_depth), @@ -164,20 +167,6 @@ impl Pallet { .retain(|&x| x >= current_era.saturating_sub(history_depth)); >::insert(&controller, &ledger); - // todo(ank4n): remove - // match ledger.claimed_rewards.binary_search(&era) { - // Ok(_) => - // return Err(Error::::AlreadyClaimed - // .with_weight(T::WeightInfo::payout_stakers_alive_staked(0))), - // Err(pos) => ledger - // .claimed_rewards - // .try_insert(pos, era) - // // Since we retain era entries in `claimed_rewards` only upto - // // `HistoryDepth`, following bound is always expected to be - // // satisfied. - // .defensive_map_err(|_| Error::::BoundNotMet)?, - // } - if EraInfo::::temp_is_rewards_claimed(era, &ledger, &ledger.stash, page) { return Err(Error::::AlreadyClaimed .with_weight(T::WeightInfo::payout_stakers_alive_staked(0))) diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index 6c2a2e2505622..afa7e299a5857 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -59,7 +59,6 @@ pub(crate) const SPECULATIVE_NUM_SPANS: u32 = 32; #[frame_support::pallet] pub mod pallet { use frame_election_provider_support::ElectionDataProvider; - use frame_support::metadata::StorageEntryModifier::Default; use crate::BenchmarkingConfig; @@ -609,8 +608,8 @@ pub mod pallet { pub(crate) struct EraInfo(sp_std::marker::PhantomData); impl EraInfo { // TODO(ank4n): doc and clean up in 84 eras - // looks at ledger for older non paged rewards, and `ClaimedRewards` for newer paged - // rewards. + // looks at `T::StakingLedger` for older non paged rewards, and `T::ClaimedRewards` for + // newer paged rewards. pub(crate) fn temp_is_rewards_claimed( era: EraIndex, ledger: &StakingLedger, @@ -633,8 +632,8 @@ pub mod pallet { return match >::get((era, validator, page)) { Some(paged_exposure) => paged_exposure, // only return clipped exposure if page zero and no paged exposure entry - None if page == 0 => >::get(&era, &ledger.stash), - _ => Default::Default(), + None if page == 0 => >::get(&era, validator), + _ => Default::default(), } } @@ -662,15 +661,6 @@ pub mod pallet { .for_each(|(page, paged_exposure)| { >::insert((era, &validator, page as u32), &paged_exposure); }); - - // fixme(ank4n): no need to keep storing new clipped exposure - let mut exposure_clipped = exposure; - 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); - } - >::insert(era, &validator, exposure_clipped); } pub(crate) fn set_total_stake(era: EraIndex, total_stake: BalanceOf) { @@ -1626,8 +1616,7 @@ pub mod pallet { /// NOTE: weights are assuming that payouts are made to alive stash account (Staked). /// Paying even a dead controller is cheaper weight-wise. We don't do any refunds here. /// # - // todo(ank4n): fix weights and breaking change. But leaving it will add to confusion and - // missed rewards. + // todo(ank4n): fix weights. #[pallet::call_index(18)] #[pallet::weight(T::WeightInfo::payout_stakers_alive_staked( T::MaxNominatorRewardedPerValidator::get() diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index f69e810e3f1ac..fb6bf09b66d72 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -2194,7 +2194,7 @@ fn reward_validator_slashing_validator_does_not_overflow() { ErasStakers::::insert(0, 11, &exposure); ErasStakersClipped::::insert(0, 11, exposure); ErasValidatorReward::::insert(0, stake); - assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, 0)); + assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, 0, 0)); assert_eq!(Balances::total_balance(&11), stake * 2); // Set staker @@ -3560,19 +3560,19 @@ fn claim_reward_at_the_last_era_and_no_double_claim_and_invalid_claim() { // Last kept is 1: assert!(current_era - HistoryDepth::get() == 1); assert_noop!( - Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, 0), + Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, 0, 0), // Fail: Era out of history Error::::InvalidEraToReward.with_weight(err_weight) ); - assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, 1)); - assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, 2)); + assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, 1, 0)); + assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, 2, 0)); assert_noop!( - Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, 2), + Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, 2, 0), // Fail: Double claim Error::::AlreadyClaimed.with_weight(err_weight) ); assert_noop!( - Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, active_era), + Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, active_era, 0), // Fail: Era not finished yet Error::::InvalidEraToReward.with_weight(err_weight) ); @@ -3750,7 +3750,7 @@ fn test_payout_stakers() { let pre_payout_total_issuance = Balances::total_issuance(); RewardOnUnbalanceWasCalled::set(false); - assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, 1)); + assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, 1, 0)); assert_eq_error_rate!( Balances::total_issuance(), pre_payout_total_issuance + actual_paid_out, @@ -3791,7 +3791,7 @@ fn test_payout_stakers() { mock::start_active_era(i); RewardOnUnbalanceWasCalled::set(false); - assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, i - 1)); + assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, i - 1, 0)); assert_eq_error_rate!( Balances::total_issuance(), pre_payout_total_issuance + actual_paid_out, @@ -3827,12 +3827,14 @@ fn test_payout_stakers() { assert_ok!(Staking::payout_stakers( RuntimeOrigin::signed(1337), 11, - expected_start_reward_era + expected_start_reward_era, + 0 )); assert_ok!(Staking::payout_stakers( RuntimeOrigin::signed(1337), 11, - expected_last_reward_era + expected_last_reward_era, + 0 )); assert_eq!( Staking::ledger(&10), @@ -3846,9 +3848,9 @@ fn test_payout_stakers() { ); // Out of order claims works. - assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, 69)); - assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, 23)); - assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, 42)); + assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, 69, 0)); + assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, 23, 0)); + assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, 42, 0)); assert_eq!( Staking::ledger(&10), Some(StakingLedger { @@ -3894,12 +3896,12 @@ fn payout_stakers_handles_basic_errors() { // Wrong Era, too big assert_noop!( - Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, 2), + Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, 2, 0), Error::::InvalidEraToReward.with_weight(err_weight) ); // Wrong Staker assert_noop!( - Staking::payout_stakers(RuntimeOrigin::signed(1337), 10, 1), + Staking::payout_stakers(RuntimeOrigin::signed(1337), 10, 1, 0), Error::::NotStash.with_weight(err_weight) ); @@ -3919,31 +3921,43 @@ fn payout_stakers_handles_basic_errors() { // to payout era starting from expected_start_reward_era=19 through // expected_last_reward_era=98 (80 total eras), but not 18 or 99. assert_noop!( - Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, expected_start_reward_era - 1), + Staking::payout_stakers( + RuntimeOrigin::signed(1337), + 11, + expected_start_reward_era - 1, + 0 + ), Error::::InvalidEraToReward.with_weight(err_weight) ); assert_noop!( - Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, expected_last_reward_era + 1), + Staking::payout_stakers( + RuntimeOrigin::signed(1337), + 11, + expected_last_reward_era + 1, + 0 + ), Error::::InvalidEraToReward.with_weight(err_weight) ); assert_ok!(Staking::payout_stakers( RuntimeOrigin::signed(1337), 11, - expected_start_reward_era + expected_start_reward_era, + 0 )); assert_ok!(Staking::payout_stakers( RuntimeOrigin::signed(1337), 11, - expected_last_reward_era + expected_last_reward_era, + 0 )); // Can't claim again assert_noop!( - Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, expected_start_reward_era), + Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, expected_start_reward_era, 0), Error::::AlreadyClaimed.with_weight(err_weight) ); assert_noop!( - Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, expected_last_reward_era), + Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, expected_last_reward_era, 0), Error::::AlreadyClaimed.with_weight(err_weight) ); }); @@ -3991,7 +4005,8 @@ fn payout_stakers_handles_weight_refund() { start_active_era(2); // Collect payouts when there are no nominators - let call = TestCall::Staking(StakingCall::payout_stakers { validator_stash: 11, era: 1 }); + let call = + TestCall::Staking(StakingCall::payout_stakers { validator_stash: 11, era: 1, page: 0 }); let info = call.get_dispatch_info(); let result = call.dispatch(RuntimeOrigin::signed(20)); assert_ok!(result); @@ -4004,7 +4019,8 @@ fn payout_stakers_handles_weight_refund() { start_active_era(3); // Collect payouts for an era where the validator did not receive any points. - let call = TestCall::Staking(StakingCall::payout_stakers { validator_stash: 11, era: 2 }); + let call = + TestCall::Staking(StakingCall::payout_stakers { validator_stash: 11, era: 2, page: 0 }); let info = call.get_dispatch_info(); let result = call.dispatch(RuntimeOrigin::signed(20)); assert_ok!(result); @@ -4017,7 +4033,8 @@ fn payout_stakers_handles_weight_refund() { start_active_era(4); // Collect payouts when the validator has `half_max_nom_rewarded` nominators. - let call = TestCall::Staking(StakingCall::payout_stakers { validator_stash: 11, era: 3 }); + let call = + TestCall::Staking(StakingCall::payout_stakers { validator_stash: 11, era: 3, page: 0 }); let info = call.get_dispatch_info(); let result = call.dispatch(RuntimeOrigin::signed(20)); assert_ok!(result); @@ -4040,14 +4057,16 @@ fn payout_stakers_handles_weight_refund() { start_active_era(6); // Collect payouts when the validator had `half_max_nom_rewarded` nominators. - let call = TestCall::Staking(StakingCall::payout_stakers { validator_stash: 11, era: 5 }); + let call = + TestCall::Staking(StakingCall::payout_stakers { validator_stash: 11, era: 5, page: 0 }); let info = call.get_dispatch_info(); let result = call.dispatch(RuntimeOrigin::signed(20)); assert_ok!(result); assert_eq!(extract_actual_weight(&result, &info), max_nom_rewarded_weight); // Try and collect payouts for an era that has already been collected. - let call = TestCall::Staking(StakingCall::payout_stakers { validator_stash: 11, era: 5 }); + let call = + TestCall::Staking(StakingCall::payout_stakers { validator_stash: 11, era: 5, page: 0 }); let info = call.get_dispatch_info(); let result = call.dispatch(RuntimeOrigin::signed(20)); assert!(result.is_err()); @@ -4193,7 +4212,7 @@ fn payout_creates_controller() { // compute and ensure the reward amount is greater than zero. let _ = current_total_payout_for_duration(reward_time_per_era()); mock::start_active_era(2); - assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, 1)); + assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, 1, 0)); // Controller is created assert!(Balances::free_balance(1337) > 0); @@ -4221,7 +4240,7 @@ fn payout_to_any_account_works() { // compute and ensure the reward amount is greater than zero. let _ = current_total_payout_for_duration(reward_time_per_era()); mock::start_active_era(2); - assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, 1)); + assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, 1, 0)); // Payment is successful assert!(Balances::free_balance(42) > 0); @@ -5515,14 +5534,14 @@ fn pre_bonding_era_cannot_be_claimed() { mock::start_active_era(current_era); // claiming reward for last era in which validator was active works - assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(4), 3, current_era - 1)); + assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(4), 3, current_era - 1, 0)); // consumed weight for all payout_stakers dispatches that fail let err_weight = ::WeightInfo::payout_stakers_alive_staked(0); // cannot claim rewards for an era before bonding occured as it is // already marked as claimed. assert_noop!( - Staking::payout_stakers(RuntimeOrigin::signed(4), 3, current_era - 2), + Staking::payout_stakers(RuntimeOrigin::signed(4), 3, current_era - 2, 0), Error::::AlreadyClaimed.with_weight(err_weight) ); @@ -5532,7 +5551,7 @@ fn pre_bonding_era_cannot_be_claimed() { // make sure stakers still cannot claim rewards that they are not meant to assert_noop!( - Staking::payout_stakers(RuntimeOrigin::signed(4), 3, current_era - 2), + Staking::payout_stakers(RuntimeOrigin::signed(4), 3, current_era - 2, 0), Error::::NotController ); @@ -5581,7 +5600,7 @@ fn reducing_history_depth_abrupt() { mock::start_active_era(current_era); // claiming reward for last era in which validator was active works - assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(4), 3, current_era - 1)); + assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(4), 3, current_era - 1, 0)); // next era current_era = current_era + 1; @@ -5592,7 +5611,7 @@ fn reducing_history_depth_abrupt() { HistoryDepth::set(history_depth); // claiming reward does not work anymore assert_noop!( - Staking::payout_stakers(RuntimeOrigin::signed(4), 3, current_era - 1), + Staking::payout_stakers(RuntimeOrigin::signed(4), 3, current_era - 1, 0), Error::::NotController ); From 4fdc2df10efe5089b07785dc3990b6298dbe6691 Mon Sep 17 00:00:00 2001 From: Ankan Date: Sat, 14 Jan 2023 21:53:25 +0100 Subject: [PATCH 016/162] fix double claim --- frame/staking/src/pallet/mod.rs | 2 +- frame/staking/src/tests.rs | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index afa7e299a5857..df7bc8019b4e9 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -616,7 +616,7 @@ pub mod pallet { validator: &T::AccountId, page: PageIndex, ) -> bool { - ledger.claimed_rewards.binary_search(&era).is_ok() && + ledger.claimed_rewards.binary_search(&era).is_ok() || Self::is_rewards_claimed(era, validator, page) } diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index fb6bf09b66d72..c3a6b91b2188c 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -3534,8 +3534,9 @@ fn claim_reward_at_the_last_era_and_no_double_claim_and_invalid_claim() { mock::start_active_era(1); Pallet::::reward_by_ids(vec![(11, 1)]); - // Change total issuance in order to modify total payout + // Increase total token issuance to affect the total payout. let _ = Balances::deposit_creating(&999, 1_000_000_000); + // Compute total payout now for whole duration as other parameter won't change let total_payout_1 = current_total_payout_for_duration(reward_time_per_era()); assert!(total_payout_1 != total_payout_0); @@ -3543,7 +3544,7 @@ fn claim_reward_at_the_last_era_and_no_double_claim_and_invalid_claim() { mock::start_active_era(2); Pallet::::reward_by_ids(vec![(11, 1)]); - // Change total issuance in order to modify total payout + // Increase total token issuance to affect the total payout. let _ = Balances::deposit_creating(&999, 1_000_000_000); // Compute total payout now for whole duration as other parameter won't change let total_payout_2 = current_total_payout_for_duration(reward_time_per_era()); From c339ca5b6f6262879d499e4315653554086be784 Mon Sep 17 00:00:00 2001 From: Ankan Date: Sat, 14 Jan 2023 21:59:43 +0100 Subject: [PATCH 017/162] don't store claimed rewards for previous eras in the ledger --- frame/staking/src/pallet/mod.rs | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index df7bc8019b4e9..0af6f37e2f264 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -988,10 +988,6 @@ pub mod pallet { >::insert(&stash, &controller); >::insert(&stash, payee); - let current_era = CurrentEra::::get().unwrap_or(0); - let history_depth = T::HistoryDepth::get(); - let last_reward_era = current_era.saturating_sub(history_depth); - let stash_balance = T::Currency::free_balance(&stash); let value = value.min(stash_balance); Self::deposit_event(Event::::Bonded { stash: stash.clone(), amount: value }); @@ -1000,12 +996,7 @@ pub mod pallet { total: value, active: value, unlocking: Default::default(), - claimed_rewards: (last_reward_era..current_era) - .try_collect() - // Since last_reward_era is calculated as `current_era - - // HistoryDepth`, following bound is always expected to be - // satisfied. - .defensive_map_err(|_| Error::::BoundNotMet)?, + claimed_rewards: Default::default(), }; Self::update_ledger(&controller, &item); Ok(()) From 773d91ca8e0f4c60c225ab57560aac3a1e509cf3 Mon Sep 17 00:00:00 2001 From: Ankan Date: Sat, 14 Jan 2023 22:04:06 +0100 Subject: [PATCH 018/162] mark claimed_rewards in Staking ledger as legacy --- frame/staking/src/benchmarking.rs | 2 +- frame/staking/src/lib.rs | 6 +- frame/staking/src/pallet/impls.rs | 12 +-- frame/staking/src/pallet/mod.rs | 9 +-- frame/staking/src/tests.rs | 120 +++++++++++++++--------------- 5 files changed, 74 insertions(+), 75 deletions(-) diff --git a/frame/staking/src/benchmarking.rs b/frame/staking/src/benchmarking.rs index 0665bac4aff31..f97c29b61ba75 100644 --- a/frame/staking/src/benchmarking.rs +++ b/frame/staking/src/benchmarking.rs @@ -681,7 +681,7 @@ benchmarks! { active: T::Currency::minimum_balance() - One::one(), total: T::Currency::minimum_balance() - One::one(), unlocking: Default::default(), - claimed_rewards: Default::default(), + legacy_claimed_rewards: Default::default(), }; Ledger::::insert(&controller, l); diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index b35f82aa658b8..7118fce93e84b 100644 --- a/frame/staking/src/lib.rs +++ b/frame/staking/src/lib.rs @@ -468,7 +468,7 @@ pub struct StakingLedger { pub unlocking: BoundedVec>, T::MaxUnlockingChunks>, /// List of eras for which the stakers behind a validator have claimed rewards. Only updated /// for validators. - pub claimed_rewards: BoundedVec, + pub legacy_claimed_rewards: BoundedVec, } impl StakingLedger { @@ -479,7 +479,7 @@ impl StakingLedger { total: Zero::zero(), active: Zero::zero(), unlocking: Default::default(), - claimed_rewards: Default::default(), + legacy_claimed_rewards: Default::default(), } } @@ -509,7 +509,7 @@ impl StakingLedger { total, active: self.active, unlocking, - claimed_rewards: self.claimed_rewards, + legacy_claimed_rewards: self.legacy_claimed_rewards, } } diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index b1fc791a84065..60339887dbabc 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -150,7 +150,7 @@ impl Pallet { ); // Note: if era has no reward to be claimed, era may be future. better not to update - // `ledger.claimed_rewards` in this case. + // `ledger.legacy_claimed_rewards` in this case. let era_payout = >::get(&era).ok_or_else(|| { Error::::InvalidEraToReward .with_weight(T::WeightInfo::payout_stakers_alive_staked(0)) @@ -163,7 +163,7 @@ impl Pallet { // clean up older claimed rewards ledger - .claimed_rewards + .legacy_claimed_rewards .retain(|&x| x >= current_era.saturating_sub(history_depth)); >::insert(&controller, &ledger); @@ -1034,7 +1034,7 @@ impl ElectionDataProvider for Pallet { active: stake, total: stake, unlocking: Default::default(), - claimed_rewards: Default::default(), + legacy_claimed_rewards: Default::default(), }, ); @@ -1052,7 +1052,7 @@ impl ElectionDataProvider for Pallet { active: stake, total: stake, unlocking: Default::default(), - claimed_rewards: Default::default(), + legacy_claimed_rewards: Default::default(), }, ); Self::do_add_validator( @@ -1093,7 +1093,7 @@ impl ElectionDataProvider for Pallet { active: stake, total: stake, unlocking: Default::default(), - claimed_rewards: Default::default(), + legacy_claimed_rewards: Default::default(), }, ); Self::do_add_validator( @@ -1114,7 +1114,7 @@ impl ElectionDataProvider for Pallet { active: stake, total: stake, unlocking: Default::default(), - claimed_rewards: Default::default(), + legacy_claimed_rewards: Default::default(), }, ); Self::do_add_nominator( diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index 0af6f37e2f264..a39a4b34b59f7 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -139,8 +139,7 @@ pub mod pallet { /// Following information is kept for eras in `[current_era - /// HistoryDepth, current_era]`: `ErasStakers`, `ErasStakersClipped`, /// `ErasValidatorPrefs`, `ErasValidatorReward`, `ErasRewardPoints`, - /// `ErasTotalStake`, `ErasStartSessionIndex`, - /// `StakingLedger.claimed_rewards`. + /// `ErasTotalStake`, `ErasStartSessionIndex`, `ClaimedRewards`. /// /// Must be more than the number of eras delayed by session. /// I.e. active era must always be in history. I.e. `active_era > @@ -150,7 +149,7 @@ pub mod pallet { /// this should be set to same value or greater as in storage. /// /// Note: `HistoryDepth` is used as the upper bound for the `BoundedVec` - /// item `StakingLedger.claimed_rewards`. Setting this value lower than + /// item `StakingLedger.legacy_claimed_rewards`. Setting this value lower than /// the existing value can lead to inconsistencies in the /// `StakingLedger` and will need to be handled properly in a migration. /// The test `reducing_history_depth_abrupt` shows this effect. @@ -616,7 +615,7 @@ pub mod pallet { validator: &T::AccountId, page: PageIndex, ) -> bool { - ledger.claimed_rewards.binary_search(&era).is_ok() || + ledger.legacy_claimed_rewards.binary_search(&era).is_ok() || Self::is_rewards_claimed(era, validator, page) } @@ -996,7 +995,7 @@ pub mod pallet { total: value, active: value, unlocking: Default::default(), - claimed_rewards: Default::default(), + legacy_claimed_rewards: Default::default(), }; Self::update_ledger(&controller, &item); Ok(()) diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index c3a6b91b2188c..62f0a05815ef1 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -154,7 +154,7 @@ fn basic_setup_works() { total: 1000, active: 1000, unlocking: Default::default(), - claimed_rewards: bounded_vec![], + legacy_claimed_rewards: bounded_vec![], } ); // Account 20 controls the stash from account 21, which is 200 * balance_factor units @@ -165,7 +165,7 @@ fn basic_setup_works() { total: 1000, active: 1000, unlocking: Default::default(), - claimed_rewards: bounded_vec![], + legacy_claimed_rewards: bounded_vec![], }) ); // Account 1 does not control any stash @@ -188,7 +188,7 @@ fn basic_setup_works() { total: 500, active: 500, unlocking: Default::default(), - claimed_rewards: bounded_vec![], + legacy_claimed_rewards: bounded_vec![], }) ); assert_eq!(Staking::nominators(101).unwrap().targets, vec![11, 21]); @@ -441,7 +441,7 @@ fn staking_should_work() { total: 1500, active: 1500, unlocking: Default::default(), - claimed_rewards: bounded_vec![0], + legacy_claimed_rewards: bounded_vec![0], }) ); // e.g. it cannot reserve more than 500 that it has free from the total 2000 @@ -1030,7 +1030,7 @@ fn reward_destination_works() { total: 1000, active: 1000, unlocking: Default::default(), - claimed_rewards: bounded_vec![], + legacy_claimed_rewards: bounded_vec![], }) ); @@ -1053,7 +1053,7 @@ fn reward_destination_works() { total: 1000 + total_payout_0, active: 1000 + total_payout_0, unlocking: Default::default(), - claimed_rewards: bounded_vec![0], + legacy_claimed_rewards: bounded_vec![0], }) ); @@ -1081,7 +1081,7 @@ fn reward_destination_works() { total: 1000 + total_payout_0, active: 1000 + total_payout_0, unlocking: Default::default(), - claimed_rewards: bounded_vec![0, 1], + legacy_claimed_rewards: bounded_vec![0, 1], }) ); @@ -1110,7 +1110,7 @@ fn reward_destination_works() { total: 1000 + total_payout_0, active: 1000 + total_payout_0, unlocking: Default::default(), - claimed_rewards: bounded_vec![0, 1, 2], + legacy_claimed_rewards: bounded_vec![0, 1, 2], }) ); // Check that amount in staked account is NOT increased. @@ -1172,7 +1172,7 @@ fn bond_extra_works() { total: 1000, active: 1000, unlocking: Default::default(), - claimed_rewards: bounded_vec![], + legacy_claimed_rewards: bounded_vec![], }) ); @@ -1189,7 +1189,7 @@ fn bond_extra_works() { total: 1000 + 100, active: 1000 + 100, unlocking: Default::default(), - claimed_rewards: bounded_vec![], + legacy_claimed_rewards: bounded_vec![], }) ); @@ -1203,7 +1203,7 @@ fn bond_extra_works() { total: 1000000, active: 1000000, unlocking: Default::default(), - claimed_rewards: bounded_vec![], + legacy_claimed_rewards: bounded_vec![], }) ); }); @@ -1241,7 +1241,7 @@ fn bond_extra_and_withdraw_unbonded_works() { total: 1000, active: 1000, unlocking: Default::default(), - claimed_rewards: bounded_vec![], + legacy_claimed_rewards: bounded_vec![], }) ); assert_eq!( @@ -1259,7 +1259,7 @@ fn bond_extra_and_withdraw_unbonded_works() { total: 1000 + 100, active: 1000 + 100, unlocking: Default::default(), - claimed_rewards: bounded_vec![], + legacy_claimed_rewards: bounded_vec![], }) ); // Exposure is a snapshot! only updated after the next era update. @@ -1280,7 +1280,7 @@ fn bond_extra_and_withdraw_unbonded_works() { total: 1000 + 100, active: 1000 + 100, unlocking: Default::default(), - claimed_rewards: bounded_vec![], + legacy_claimed_rewards: bounded_vec![], }) ); // Exposure is now updated. @@ -1298,7 +1298,7 @@ fn bond_extra_and_withdraw_unbonded_works() { total: 1000 + 100, active: 100, unlocking: bounded_vec![UnlockChunk { value: 1000, era: 2 + 3 }], - claimed_rewards: bounded_vec![], + legacy_claimed_rewards: bounded_vec![], }), ); @@ -1311,7 +1311,7 @@ fn bond_extra_and_withdraw_unbonded_works() { total: 1000 + 100, active: 100, unlocking: bounded_vec![UnlockChunk { value: 1000, era: 2 + 3 }], - claimed_rewards: bounded_vec![], + legacy_claimed_rewards: bounded_vec![], }), ); @@ -1327,7 +1327,7 @@ fn bond_extra_and_withdraw_unbonded_works() { total: 1000 + 100, active: 100, unlocking: bounded_vec![UnlockChunk { value: 1000, era: 2 + 3 }], - claimed_rewards: bounded_vec![], + legacy_claimed_rewards: bounded_vec![], }), ); @@ -1343,7 +1343,7 @@ fn bond_extra_and_withdraw_unbonded_works() { total: 100, active: 100, unlocking: Default::default(), - claimed_rewards: bounded_vec![], + legacy_claimed_rewards: bounded_vec![], }), ); }) @@ -1446,7 +1446,7 @@ fn rebond_works() { total: 1000, active: 1000, unlocking: Default::default(), - claimed_rewards: bounded_vec![], + legacy_claimed_rewards: bounded_vec![], }) ); @@ -1465,7 +1465,7 @@ fn rebond_works() { total: 1000, active: 100, unlocking: bounded_vec![UnlockChunk { value: 900, era: 2 + 3 }], - claimed_rewards: bounded_vec![], + legacy_claimed_rewards: bounded_vec![], }) ); @@ -1478,7 +1478,7 @@ fn rebond_works() { total: 1000, active: 1000, unlocking: Default::default(), - claimed_rewards: bounded_vec![], + legacy_claimed_rewards: bounded_vec![], }) ); @@ -1491,7 +1491,7 @@ fn rebond_works() { total: 1000, active: 100, unlocking: bounded_vec![UnlockChunk { value: 900, era: 5 }], - claimed_rewards: bounded_vec![], + legacy_claimed_rewards: bounded_vec![], }) ); @@ -1504,7 +1504,7 @@ fn rebond_works() { total: 1000, active: 600, unlocking: bounded_vec![UnlockChunk { value: 400, era: 5 }], - claimed_rewards: bounded_vec![], + legacy_claimed_rewards: bounded_vec![], }) ); @@ -1517,7 +1517,7 @@ fn rebond_works() { total: 1000, active: 1000, unlocking: Default::default(), - claimed_rewards: bounded_vec![], + legacy_claimed_rewards: bounded_vec![], }) ); @@ -1532,7 +1532,7 @@ fn rebond_works() { total: 1000, active: 100, unlocking: bounded_vec![UnlockChunk { value: 900, era: 5 }], - claimed_rewards: bounded_vec![], + legacy_claimed_rewards: bounded_vec![], }) ); @@ -1545,7 +1545,7 @@ fn rebond_works() { total: 1000, active: 600, unlocking: bounded_vec![UnlockChunk { value: 400, era: 5 }], - claimed_rewards: bounded_vec![], + legacy_claimed_rewards: bounded_vec![], }) ); }) @@ -1572,7 +1572,7 @@ fn rebond_is_fifo() { total: 1000, active: 1000, unlocking: Default::default(), - claimed_rewards: bounded_vec![], + legacy_claimed_rewards: bounded_vec![], }) ); @@ -1587,7 +1587,7 @@ fn rebond_is_fifo() { total: 1000, active: 600, unlocking: bounded_vec![UnlockChunk { value: 400, era: 2 + 3 }], - claimed_rewards: bounded_vec![], + legacy_claimed_rewards: bounded_vec![], }) ); @@ -1605,7 +1605,7 @@ fn rebond_is_fifo() { UnlockChunk { value: 400, era: 2 + 3 }, UnlockChunk { value: 300, era: 3 + 3 }, ], - claimed_rewards: bounded_vec![], + legacy_claimed_rewards: bounded_vec![], }) ); @@ -1624,7 +1624,7 @@ fn rebond_is_fifo() { UnlockChunk { value: 300, era: 3 + 3 }, UnlockChunk { value: 200, era: 4 + 3 }, ], - claimed_rewards: bounded_vec![], + legacy_claimed_rewards: bounded_vec![], }) ); @@ -1640,7 +1640,7 @@ fn rebond_is_fifo() { UnlockChunk { value: 400, era: 2 + 3 }, UnlockChunk { value: 100, era: 3 + 3 }, ], - claimed_rewards: bounded_vec![], + legacy_claimed_rewards: bounded_vec![], }) ); }) @@ -1669,7 +1669,7 @@ fn rebond_emits_right_value_in_event() { total: 1000, active: 100, unlocking: bounded_vec![UnlockChunk { value: 900, era: 1 + 3 }], - claimed_rewards: bounded_vec![], + legacy_claimed_rewards: bounded_vec![], }) ); @@ -1682,7 +1682,7 @@ fn rebond_emits_right_value_in_event() { total: 1000, active: 200, unlocking: bounded_vec![UnlockChunk { value: 800, era: 1 + 3 }], - claimed_rewards: bounded_vec![], + legacy_claimed_rewards: bounded_vec![], }) ); // Event emitted should be correct @@ -1697,7 +1697,7 @@ fn rebond_emits_right_value_in_event() { total: 1000, active: 1000, unlocking: Default::default(), - claimed_rewards: bounded_vec![], + legacy_claimed_rewards: bounded_vec![], }) ); // Event emitted should be correct, only 800 @@ -1733,7 +1733,7 @@ fn reward_to_stake_works() { total: 69, active: 69, unlocking: Default::default(), - claimed_rewards: bounded_vec![], + legacy_claimed_rewards: bounded_vec![], }, ); @@ -1797,7 +1797,7 @@ fn reap_stash_works() { total: 5, active: 5, unlocking: Default::default(), - claimed_rewards: bounded_vec![], + legacy_claimed_rewards: bounded_vec![], }, ); @@ -1932,7 +1932,7 @@ fn bond_with_no_staked_value() { active: 0, total: 5, unlocking: bounded_vec![UnlockChunk { value: 5, era: 3 }], - claimed_rewards: bounded_vec![], + legacy_claimed_rewards: bounded_vec![], }) ); @@ -3036,7 +3036,7 @@ fn staker_cannot_bail_deferred_slash() { active: 0, total: 500, stash: 101, - claimed_rewards: bounded_vec![], + legacy_claimed_rewards: bounded_vec![], unlocking: bounded_vec![UnlockChunk { era: 4u32, value: 500 }], } ); @@ -3770,7 +3770,7 @@ fn test_payout_stakers() { assert_eq!(Balances::free_balance(&(100 + i)), balance + i as Balance); } - // We track rewards in `claimed_rewards` vec + // We track rewards in `legacy_claimed_rewards` vec assert_eq!( Staking::ledger(&10), Some(StakingLedger { @@ -3778,7 +3778,7 @@ fn test_payout_stakers() { total: 1000, active: 1000, unlocking: Default::default(), - claimed_rewards: bounded_vec![1] + legacy_claimed_rewards: bounded_vec![1] }) ); @@ -3809,7 +3809,7 @@ fn test_payout_stakers() { total: 1000, active: 1000, unlocking: Default::default(), - claimed_rewards: (1..=14).collect::>().try_into().unwrap() + legacy_claimed_rewards: (1..=14).collect::>().try_into().unwrap() }) ); @@ -3844,7 +3844,7 @@ fn test_payout_stakers() { total: 1000, active: 1000, unlocking: Default::default(), - claimed_rewards: bounded_vec![expected_start_reward_era, expected_last_reward_era] + legacy_claimed_rewards: bounded_vec![expected_start_reward_era, expected_last_reward_era] }) ); @@ -3859,7 +3859,7 @@ fn test_payout_stakers() { total: 1000, active: 1000, unlocking: Default::default(), - claimed_rewards: bounded_vec![ + legacy_claimed_rewards: bounded_vec![ expected_start_reward_era, 23, 42, @@ -4088,7 +4088,7 @@ fn bond_during_era_correctly_populates_claimed_rewards() { total: 1000, active: 1000, unlocking: Default::default(), - claimed_rewards: bounded_vec![], + legacy_claimed_rewards: bounded_vec![], }) ); mock::start_active_era(5); @@ -4100,7 +4100,7 @@ fn bond_during_era_correctly_populates_claimed_rewards() { total: 1000, active: 1000, unlocking: Default::default(), - claimed_rewards: (0..5).collect::>().try_into().unwrap(), + legacy_claimed_rewards: (0..5).collect::>().try_into().unwrap(), }) ); @@ -4116,7 +4116,7 @@ fn bond_during_era_correctly_populates_claimed_rewards() { total: 1000, active: 1000, unlocking: Default::default(), - claimed_rewards: (last_reward_era..current_era) + legacy_claimed_rewards: (last_reward_era..current_era) .collect::>() .try_into() .unwrap(), @@ -4364,7 +4364,7 @@ fn cannot_rebond_to_lower_than_ed() { total: 10 * 1000, active: 10 * 1000, unlocking: Default::default(), - claimed_rewards: bounded_vec![], + legacy_claimed_rewards: bounded_vec![], } ); @@ -4378,7 +4378,7 @@ fn cannot_rebond_to_lower_than_ed() { total: 10 * 1000, active: 0, unlocking: bounded_vec![UnlockChunk { value: 10 * 1000, era: 3 }], - claimed_rewards: bounded_vec![], + legacy_claimed_rewards: bounded_vec![], } ); @@ -4404,7 +4404,7 @@ fn cannot_bond_extra_to_lower_than_ed() { total: 10 * 1000, active: 10 * 1000, unlocking: Default::default(), - claimed_rewards: bounded_vec![], + legacy_claimed_rewards: bounded_vec![], } ); @@ -4418,7 +4418,7 @@ fn cannot_bond_extra_to_lower_than_ed() { total: 10 * 1000, active: 0, unlocking: bounded_vec![UnlockChunk { value: 10 * 1000, era: 3 }], - claimed_rewards: bounded_vec![], + legacy_claimed_rewards: bounded_vec![], } ); @@ -4445,7 +4445,7 @@ fn do_not_die_when_active_is_ed() { total: 1000 * ed, active: 1000 * ed, unlocking: Default::default(), - claimed_rewards: bounded_vec![], + legacy_claimed_rewards: bounded_vec![], } ); @@ -4462,7 +4462,7 @@ fn do_not_die_when_active_is_ed() { total: ed, active: ed, unlocking: Default::default(), - claimed_rewards: bounded_vec![], + legacy_claimed_rewards: bounded_vec![], } ); }) @@ -5262,7 +5262,7 @@ fn proportional_slash_stop_slashing_if_remaining_zero() { active: 20, // we have some chunks, but they are not affected. unlocking: bounded_vec![c(1, 10), c(2, 10)], - claimed_rewards: bounded_vec![], + legacy_claimed_rewards: bounded_vec![], }; assert_eq!(BondingDuration::get(), 3); @@ -5280,7 +5280,7 @@ fn proportional_ledger_slash_works() { total: 10, active: 10, unlocking: bounded_vec![], - claimed_rewards: bounded_vec![], + legacy_claimed_rewards: bounded_vec![], }; assert_eq!(BondingDuration::get(), 3); @@ -5517,7 +5517,7 @@ fn pre_bonding_era_cannot_be_claimed() { // add a new candidate for being a validator. account 3 controlled by 4. assert_ok!(Staking::bond(RuntimeOrigin::signed(3), 4, 1500, RewardDestination::Controller)); - let claimed_rewards: BoundedVec<_, _> = + let legacy_claimed_rewards: BoundedVec<_, _> = (start_reward_era..=last_reward_era).collect::>().try_into().unwrap(); assert_eq!( Staking::ledger(&4).unwrap(), @@ -5526,7 +5526,7 @@ fn pre_bonding_era_cannot_be_claimed() { total: 1500, active: 1500, unlocking: Default::default(), - claimed_rewards, + legacy_claimed_rewards: legacy_claimed_rewards, } ); @@ -5583,7 +5583,7 @@ fn reducing_history_depth_abrupt() { // all previous era before the bonding action should be marked as // claimed. - let claimed_rewards: BoundedVec<_, _> = + let legacy_claimed_rewards: BoundedVec<_, _> = (start_reward_era..=last_reward_era).collect::>().try_into().unwrap(); assert_eq!( Staking::ledger(&4).unwrap(), @@ -5592,7 +5592,7 @@ fn reducing_history_depth_abrupt() { total: 1500, active: 1500, unlocking: Default::default(), - claimed_rewards, + legacy_claimed_rewards: legacy_claimed_rewards, } ); @@ -5622,7 +5622,7 @@ fn reducing_history_depth_abrupt() { // new staking ledgers created will be bounded by the current history depth let last_reward_era = current_era - 1; let start_reward_era = current_era - history_depth; - let claimed_rewards: BoundedVec<_, _> = + let legacy_claimed_rewards: BoundedVec<_, _> = (start_reward_era..=last_reward_era).collect::>().try_into().unwrap(); assert_eq!( Staking::ledger(&6).unwrap(), @@ -5631,7 +5631,7 @@ fn reducing_history_depth_abrupt() { total: 1200, active: 1200, unlocking: Default::default(), - claimed_rewards, + legacy_claimed_rewards: legacy_claimed_rewards, } ); From f50ee1125f14eebc102fbccde307eed2f51d2f48 Mon Sep 17 00:00:00 2001 From: Ankan Date: Sat, 14 Jan 2023 22:07:57 +0100 Subject: [PATCH 019/162] test for not populating legacy claimed rewards anymore --- frame/staking/src/tests.rs | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index 62f0a05815ef1..dd881a9b7f055 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -4077,7 +4077,7 @@ fn payout_stakers_handles_weight_refund() { } #[test] -fn bond_during_era_correctly_populates_claimed_rewards() { +fn bond_during_era_does_not_populate_legacy_claimed_rewards() { ExtBuilder::default().has_stakers(false).build_and_execute(|| { // Era = None bond_validator(9, 8, 1000); @@ -4100,13 +4100,12 @@ fn bond_during_era_correctly_populates_claimed_rewards() { total: 1000, active: 1000, unlocking: Default::default(), - legacy_claimed_rewards: (0..5).collect::>().try_into().unwrap(), + legacy_claimed_rewards: bounded_vec![], }) ); // make sure only era upto history depth is stored let current_era = 99; - let last_reward_era = 99 - HistoryDepth::get(); mock::start_active_era(current_era); bond_validator(13, 12, 1000); assert_eq!( @@ -4116,10 +4115,7 @@ fn bond_during_era_correctly_populates_claimed_rewards() { total: 1000, active: 1000, unlocking: Default::default(), - legacy_claimed_rewards: (last_reward_era..current_era) - .collect::>() - .try_into() - .unwrap(), + legacy_claimed_rewards: Default::default(), }) ); }); From 309c737f076ecff2b30ecfe52ca0a2483c36a4b7 Mon Sep 17 00:00:00 2001 From: Ankan Date: Sat, 14 Jan 2023 22:08:47 +0100 Subject: [PATCH 020/162] test is not accurate since for prebonded era, there cannot be any reward points to claim --- frame/staking/src/tests.rs | 143 ------------------------------------- 1 file changed, 143 deletions(-) diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index dd881a9b7f055..2cf695ac3dacb 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -5493,149 +5493,6 @@ fn proportional_ledger_slash_works() { ); } -#[test] -fn pre_bonding_era_cannot_be_claimed() { - // Verifies initial conditions of mock - ExtBuilder::default().nominate(false).build_and_execute(|| { - let history_depth = HistoryDepth::get(); - // jump to some era above history_depth - let mut current_era = history_depth + 10; - let last_reward_era = current_era - 1; - let start_reward_era = current_era - history_depth; - - // put some money in stash=3 and controller=4. - for i in 3..5 { - let _ = Balances::make_free_balance_be(&i, 2000); - } - - mock::start_active_era(current_era); - - // add a new candidate for being a validator. account 3 controlled by 4. - assert_ok!(Staking::bond(RuntimeOrigin::signed(3), 4, 1500, RewardDestination::Controller)); - - let legacy_claimed_rewards: BoundedVec<_, _> = - (start_reward_era..=last_reward_era).collect::>().try_into().unwrap(); - assert_eq!( - Staking::ledger(&4).unwrap(), - StakingLedger { - stash: 3, - total: 1500, - active: 1500, - unlocking: Default::default(), - legacy_claimed_rewards: legacy_claimed_rewards, - } - ); - - // start next era - current_era = current_era + 1; - mock::start_active_era(current_era); - - // claiming reward for last era in which validator was active works - assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(4), 3, current_era - 1, 0)); - - // consumed weight for all payout_stakers dispatches that fail - let err_weight = ::WeightInfo::payout_stakers_alive_staked(0); - // cannot claim rewards for an era before bonding occured as it is - // already marked as claimed. - assert_noop!( - Staking::payout_stakers(RuntimeOrigin::signed(4), 3, current_era - 2, 0), - Error::::AlreadyClaimed.with_weight(err_weight) - ); - - // decoding will fail now since Staking Ledger is in corrupt state - HistoryDepth::set(history_depth - 1); - assert_eq!(Staking::ledger(&4), None); - - // make sure stakers still cannot claim rewards that they are not meant to - assert_noop!( - Staking::payout_stakers(RuntimeOrigin::signed(4), 3, current_era - 2, 0), - Error::::NotController - ); - - // fix the corrupted state for post conditions check - HistoryDepth::set(history_depth); - }); -} - -#[test] -fn reducing_history_depth_abrupt() { - // Verifies initial conditions of mock - ExtBuilder::default().nominate(false).build_and_execute(|| { - let original_history_depth = HistoryDepth::get(); - let mut current_era = original_history_depth + 10; - let last_reward_era = current_era - 1; - let start_reward_era = current_era - original_history_depth; - - // put some money in (stash, controller)=(3,4),(5,6). - for i in 3..7 { - let _ = Balances::make_free_balance_be(&i, 2000); - } - - // start current era - mock::start_active_era(current_era); - - // add a new candidate for being a staker. account 3 controlled by 4. - assert_ok!(Staking::bond(RuntimeOrigin::signed(3), 4, 1500, RewardDestination::Controller)); - - // all previous era before the bonding action should be marked as - // claimed. - let legacy_claimed_rewards: BoundedVec<_, _> = - (start_reward_era..=last_reward_era).collect::>().try_into().unwrap(); - assert_eq!( - Staking::ledger(&4).unwrap(), - StakingLedger { - stash: 3, - total: 1500, - active: 1500, - unlocking: Default::default(), - legacy_claimed_rewards: legacy_claimed_rewards, - } - ); - - // next era - current_era = current_era + 1; - mock::start_active_era(current_era); - - // claiming reward for last era in which validator was active works - assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(4), 3, current_era - 1, 0)); - - // next era - current_era = current_era + 1; - mock::start_active_era(current_era); - - // history_depth reduced without migration - let history_depth = original_history_depth - 1; - HistoryDepth::set(history_depth); - // claiming reward does not work anymore - assert_noop!( - Staking::payout_stakers(RuntimeOrigin::signed(4), 3, current_era - 1, 0), - Error::::NotController - ); - - // new stakers can still bond - assert_ok!(Staking::bond(RuntimeOrigin::signed(5), 6, 1200, RewardDestination::Controller)); - - // new staking ledgers created will be bounded by the current history depth - let last_reward_era = current_era - 1; - let start_reward_era = current_era - history_depth; - let legacy_claimed_rewards: BoundedVec<_, _> = - (start_reward_era..=last_reward_era).collect::>().try_into().unwrap(); - assert_eq!( - Staking::ledger(&6).unwrap(), - StakingLedger { - stash: 5, - total: 1200, - active: 1200, - unlocking: Default::default(), - legacy_claimed_rewards: legacy_claimed_rewards, - } - ); - - // fix the corrupted state for post conditions check - HistoryDepth::set(original_history_depth); - }); -} - #[test] fn reducing_max_unlocking_chunks_abrupt() { // Concern is on validators only From 4f4466ce4563c3ce6f6d12a3470e6d77fce1546d Mon Sep 17 00:00:00 2001 From: Ankan Date: Sat, 14 Jan 2023 22:14:29 +0100 Subject: [PATCH 021/162] fmt --- frame/staking/src/pallet/mod.rs | 5 ++--- frame/staking/src/tests.rs | 5 ++++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index a39a4b34b59f7..54b3d9acaa90c 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -24,9 +24,8 @@ use frame_support::{ dispatch::Codec, pallet_prelude::*, traits::{ - Currency, CurrencyToVote, Defensive, DefensiveResult, DefensiveSaturating, EnsureOrigin, - EstimateNextNewSession, Get, LockIdentifier, LockableCurrency, OnUnbalanced, TryCollect, - UnixTime, + Currency, CurrencyToVote, Defensive, DefensiveSaturating, EnsureOrigin, + EstimateNextNewSession, Get, LockIdentifier, LockableCurrency, OnUnbalanced, UnixTime, }, weights::Weight, BoundedVec, diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index 2cf695ac3dacb..640924dbe1db4 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -3844,7 +3844,10 @@ fn test_payout_stakers() { total: 1000, active: 1000, unlocking: Default::default(), - legacy_claimed_rewards: bounded_vec![expected_start_reward_era, expected_last_reward_era] + legacy_claimed_rewards: bounded_vec![ + expected_start_reward_era, + expected_last_reward_era + ] }) ); From 7f4aa5b2a4d344b8e221efd63689e790aa4fc80b Mon Sep 17 00:00:00 2001 From: Ankan Date: Sat, 14 Jan 2023 22:34:51 +0100 Subject: [PATCH 022/162] assert claimed rewards is populated --- frame/staking/src/mock.rs | 1 + frame/staking/src/pallet/impls.rs | 1 - frame/staking/src/tests.rs | 16 +++++++++++++--- 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/frame/staking/src/mock.rs b/frame/staking/src/mock.rs index 4265d60fd1b26..697197ee417d4 100644 --- a/frame/staking/src/mock.rs +++ b/frame/staking/src/mock.rs @@ -750,6 +750,7 @@ pub(crate) fn add_slash(who: &AccountId) { } /// Make all validator and nominator request their payment +// TODO(ank4n) pay out all the paged nominators. pub(crate) fn make_all_reward_payment(era: EraIndex) { let validators_with_reward = ErasRewardPoints::::get(era) .individual diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index 60339887dbabc..7990b7f1d5a36 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -184,7 +184,6 @@ impl Pallet { // which goes to them and each of their nominators. let exposure = EraInfo::::get_validator_exposure(era, &ledger.stash, page); - // let exposure = EraInfo::::get_validator_exposure(&era, &ledger.stash, page); let era_reward_points = >::get(&era); let total_reward_points = era_reward_points.total; diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index 640924dbe1db4..f0f2deff9ae35 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -1053,10 +1053,13 @@ fn reward_destination_works() { total: 1000 + total_payout_0, active: 1000 + total_payout_0, unlocking: Default::default(), - legacy_claimed_rewards: bounded_vec![0], + legacy_claimed_rewards: bounded_vec![], }) ); + // (era 0, page 0) is claimed + assert_eq!(Staking::claimed_rewards(0, &11), vec![0]); + // Change RewardDestination to Stash >::insert(&11, RewardDestination::Stash); @@ -1081,10 +1084,13 @@ fn reward_destination_works() { total: 1000 + total_payout_0, active: 1000 + total_payout_0, unlocking: Default::default(), - legacy_claimed_rewards: bounded_vec![0, 1], + legacy_claimed_rewards: bounded_vec![], }) ); + // (era 1, page 0) is claimed + assert_eq!(Staking::claimed_rewards(1, &11), vec![0]); + // Change RewardDestination to Controller >::insert(&11, RewardDestination::Controller); @@ -1110,9 +1116,13 @@ fn reward_destination_works() { total: 1000 + total_payout_0, active: 1000 + total_payout_0, unlocking: Default::default(), - legacy_claimed_rewards: bounded_vec![0, 1, 2], + legacy_claimed_rewards: bounded_vec![], }) ); + + // (era 2, page 0) is claimed + assert_eq!(Staking::claimed_rewards(2, &11), vec![0]); + // Check that amount in staked account is NOT increased. assert_eq!(Balances::free_balance(11), recorded_stash_balance); }); From d64d28e93b5bc4dc30336fa20642bc3bfff4a444 Mon Sep 17 00:00:00 2001 From: Ankan Date: Sun, 15 Jan 2023 02:54:55 +0100 Subject: [PATCH 023/162] introduce struct ExposurePage --- frame/staking/src/lib.rs | 48 +++++++++++++++++++++++++++---- frame/staking/src/mock.rs | 2 +- frame/staking/src/pallet/impls.rs | 2 +- frame/staking/src/pallet/mod.rs | 10 +++---- frame/staking/src/tests.rs | 17 +++++++---- 5 files changed, 60 insertions(+), 19 deletions(-) diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index 7118fce93e84b..75fe261fac7d7 100644 --- a/frame/staking/src/lib.rs +++ b/frame/staking/src/lib.rs @@ -736,22 +736,24 @@ impl Default for Exposure Exposure { - fn in_chunks_of(&self, page_size: usize) -> Vec { + fn as_pages(&self, page_size: usize) -> Vec> { let individual_chunks = self.others.chunks(page_size); - let mut paged_exposure: Vec = Vec::with_capacity(individual_chunks.len()); + let mut paged_exposure: Vec> = + Vec::with_capacity(individual_chunks.len()); // own balance that has not been accounted for in the paged exposure let mut own_left = self.own; for chunk in individual_chunks { let own = own_left; - let mut total = own; + let mut page_total = own; for individual in chunk.iter() { - total = total.saturating_add(individual.value); + page_total = page_total.saturating_add(individual.value); } - paged_exposure.push(Exposure { - total, + paged_exposure.push(ExposurePage { + total: self.total, + page_total, own, others: chunk .iter() @@ -767,6 +769,40 @@ impl } } +/// A snapshot of the stake backing a single validator in the system. +#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Encode, Decode, RuntimeDebug, TypeInfo)] +pub struct ExposurePage { + /// The total balance backing this validator. + #[codec(compact)] + pub total: Balance, + /// The total balance of this chunk/page. + #[codec(compact)] + pub page_total: Balance, + /// The validator's own stash that is exposed. + #[codec(compact)] + pub own: Balance, + /// The portions of nominators stashes that are exposed. + pub others: Vec>, +} + +impl Default for ExposurePage { + fn default() -> Self { + Self { total: Default::default(), page_total: Default::default(), own: Default::default(), others: vec![] } + } +} + +impl + From> for ExposurePage +{ + fn from(exposure: Exposure) -> Self { + Self { + total: exposure.total, + page_total: exposure.total, + own: exposure.own, + others: exposure.others, + } + } +} /// A pending slash record. The value of the slash has been computed but not applied yet, /// rather deferred for several eras. #[derive(Encode, Decode, RuntimeDebug, TypeInfo)] diff --git a/frame/staking/src/mock.rs b/frame/staking/src/mock.rs index 697197ee417d4..754dde0165549 100644 --- a/frame/staking/src/mock.rs +++ b/frame/staking/src/mock.rs @@ -295,7 +295,7 @@ impl crate::pallet::pallet::Config for Test { type EraPayout = ConvertCurve; type NextNewSession = Session; type MaxNominatorRewardedPerValidator = ConstU32<64>; - type ExposurePageSize = ConstU32<10>; + type ExposurePageSize = ConstU32<64>; type OffendingValidatorsThreshold = OffendingValidatorsThreshold; type ElectionProvider = onchain::OnChainExecution; type GenesisElectionProvider = Self::ElectionProvider; diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index 7990b7f1d5a36..ff771a29c2a44 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -184,7 +184,7 @@ impl Pallet { // which goes to them and each of their nominators. let exposure = EraInfo::::get_validator_exposure(era, &ledger.stash, page); - + println!("exposure: {:?}", exposure); let era_reward_points = >::get(&era); let total_reward_points = era_reward_points.total; let validator_reward_points = era_reward_points diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index 54b3d9acaa90c..8e9e2436533e9 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -44,7 +44,7 @@ pub use impls::*; use crate::{ slashing, weights::WeightInfo, AccountIdLookupOf, ActiveEraInfo, BalanceOf, EraPayout, - EraRewardPoints, Exposure, Forcing, NegativeImbalanceOf, Nominations, PositiveImbalanceOf, + EraRewardPoints, Exposure, ExposurePage, Forcing, NegativeImbalanceOf, Nominations, PositiveImbalanceOf, RewardDestination, SessionInterface, StakingLedger, UnappliedSlash, UnlockChunk, ValidatorPrefs, }; @@ -457,7 +457,7 @@ pub mod pallet { NMapKey, NMapKey, ), - Exposure>, + ExposurePage>, OptionQuery, >; @@ -626,11 +626,11 @@ pub mod pallet { era: EraIndex, validator: &T::AccountId, page: PageIndex, - ) -> Exposure> { + ) -> ExposurePage> { return match >::get((era, validator, page)) { Some(paged_exposure) => paged_exposure, // only return clipped exposure if page zero and no paged exposure entry - None if page == 0 => >::get(&era, validator), + None if page == 0 => >::get(&era, validator).into(), _ => Default::default(), } } @@ -653,7 +653,7 @@ pub mod pallet { >::insert(era, &validator, &exposure); exposure - .in_chunks_of(T::ExposurePageSize::get() as usize) + .as_pages(T::ExposurePageSize::get() as usize) .iter() .enumerate() .for_each(|(page, paged_exposure)| { diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index f0f2deff9ae35..2ac54540bad8c 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -441,7 +441,7 @@ fn staking_should_work() { total: 1500, active: 1500, unlocking: Default::default(), - legacy_claimed_rewards: bounded_vec![0], + legacy_claimed_rewards: bounded_vec![], }) ); // e.g. it cannot reserve more than 500 that it has free from the total 2000 @@ -2194,6 +2194,7 @@ fn reward_validator_slashing_validator_does_not_overflow() { let _ = Balances::make_free_balance_be(&11, stake); let exposure = Exposure:: { total: stake, own: stake, others: vec![] }; + let exposure_page: ExposurePage = exposure.clone().into(); let reward = EraRewardPoints:: { total: 1, individual: vec![(11, 1)].into_iter().collect(), @@ -2202,7 +2203,7 @@ fn reward_validator_slashing_validator_does_not_overflow() { // Check reward ErasRewardPoints::::insert(0, reward); ErasStakers::::insert(0, 11, &exposure); - ErasStakersClipped::::insert(0, 11, exposure); + ErasStakersPaged::::insert((0, 11, 0,), exposure_page); ErasValidatorReward::::insert(0, stake); assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, 0, 0)); assert_eq!(Balances::total_balance(&11), stake * 2); @@ -3762,6 +3763,7 @@ fn test_payout_stakers() { let pre_payout_total_issuance = Balances::total_issuance(); RewardOnUnbalanceWasCalled::set(false); assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, 1, 0)); + // FIXME(ank4n): this won't work since the exposure page is not sorted anymore. assert_eq_error_rate!( Balances::total_issuance(), pre_payout_total_issuance + actual_paid_out, @@ -5670,16 +5672,19 @@ fn can_page_exposure() { Exposure { total: total_stake, own: own_stake, others }; // when - let paged_exposures: Vec> = exposure.clone().in_chunks_of(3); + let paged_exposures: Vec> = exposure.clone().as_pages(3); // then + // 7 pages of nominators. assert_eq!(paged_exposures.len(), (19 / 3) + 1); // first page stake = 500 (own) + 100 + 200 + 300 - assert!(matches!(paged_exposures[0], Exposure { total: 1100, own: 500, .. })); + assert!(matches!(paged_exposures[0], ExposurePage { total: 19_500, page_total: 1100, own: 500, .. })); // second page stake = 0 + 400 + 500 + 600 - assert!(matches!(paged_exposures[1], Exposure { total: 1500, own: 0, .. })); + assert!(matches!(paged_exposures[1], ExposurePage { total: 19_500, page_total: 1500, own: 0, .. })); + // verify total is always the total stake backing a validator for all the pages. + assert_eq!(paged_exposures.iter().filter(|a| a.total == 19_500).count(), 7); // verify total stake is same as in the original exposure. - assert_eq!(paged_exposures.iter().map(|a| a.total).reduce(|a, b| a + b).unwrap(), 19_500); + assert_eq!(paged_exposures.iter().map(|a| a.page_total).reduce(|a, b| a + b).unwrap(), 19_500); // verify own stake is same as in the original exposure. assert_eq!(paged_exposures.iter().map(|a| a.own).reduce(|a, b| a + b).unwrap(), 500); // verify number of nominators are same as in the original exposure. From da53a273afa7e74d00d306fdcada3912f9f96b04 Mon Sep 17 00:00:00 2001 From: Ankan Date: Sun, 15 Jan 2023 02:55:57 +0100 Subject: [PATCH 024/162] fmt --- frame/staking/src/lib.rs | 7 ++++++- frame/staking/src/pallet/impls.rs | 1 - frame/staking/src/pallet/mod.rs | 6 +++--- frame/staking/src/tests.rs | 12 +++++++++--- 4 files changed, 18 insertions(+), 8 deletions(-) diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index 75fe261fac7d7..61ffebe5d1315 100644 --- a/frame/staking/src/lib.rs +++ b/frame/staking/src/lib.rs @@ -787,7 +787,12 @@ pub struct ExposurePage { impl Default for ExposurePage { fn default() -> Self { - Self { total: Default::default(), page_total: Default::default(), own: Default::default(), others: vec![] } + Self { + total: Default::default(), + page_total: Default::default(), + own: Default::default(), + others: vec![], + } } } diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index ff771a29c2a44..0c95685f55f44 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -184,7 +184,6 @@ impl Pallet { // which goes to them and each of their nominators. let exposure = EraInfo::::get_validator_exposure(era, &ledger.stash, page); - println!("exposure: {:?}", exposure); let era_reward_points = >::get(&era); let total_reward_points = era_reward_points.total; let validator_reward_points = era_reward_points diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index 8e9e2436533e9..fee68e5c1cc1f 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -44,9 +44,9 @@ pub use impls::*; use crate::{ slashing, weights::WeightInfo, AccountIdLookupOf, ActiveEraInfo, BalanceOf, EraPayout, - EraRewardPoints, Exposure, ExposurePage, Forcing, NegativeImbalanceOf, Nominations, PositiveImbalanceOf, - RewardDestination, SessionInterface, StakingLedger, UnappliedSlash, UnlockChunk, - ValidatorPrefs, + EraRewardPoints, Exposure, ExposurePage, Forcing, NegativeImbalanceOf, Nominations, + PositiveImbalanceOf, RewardDestination, SessionInterface, StakingLedger, UnappliedSlash, + UnlockChunk, ValidatorPrefs, }; const STAKING_ID: LockIdentifier = *b"staking "; diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index 2ac54540bad8c..67839c69952c0 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -2203,7 +2203,7 @@ fn reward_validator_slashing_validator_does_not_overflow() { // Check reward ErasRewardPoints::::insert(0, reward); ErasStakers::::insert(0, 11, &exposure); - ErasStakersPaged::::insert((0, 11, 0,), exposure_page); + ErasStakersPaged::::insert((0, 11, 0), exposure_page); ErasValidatorReward::::insert(0, stake); assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, 0, 0)); assert_eq!(Balances::total_balance(&11), stake * 2); @@ -5678,9 +5678,15 @@ fn can_page_exposure() { // 7 pages of nominators. assert_eq!(paged_exposures.len(), (19 / 3) + 1); // first page stake = 500 (own) + 100 + 200 + 300 - assert!(matches!(paged_exposures[0], ExposurePage { total: 19_500, page_total: 1100, own: 500, .. })); + assert!(matches!( + paged_exposures[0], + ExposurePage { total: 19_500, page_total: 1100, own: 500, .. } + )); // second page stake = 0 + 400 + 500 + 600 - assert!(matches!(paged_exposures[1], ExposurePage { total: 19_500, page_total: 1500, own: 0, .. })); + assert!(matches!( + paged_exposures[1], + ExposurePage { total: 19_500, page_total: 1500, own: 0, .. } + )); // verify total is always the total stake backing a validator for all the pages. assert_eq!(paged_exposures.iter().filter(|a| a.total == 19_500).count(), 7); // verify total stake is same as in the original exposure. From dd60ba7b62d2fd816bae551a7152f7a5df72ce77 Mon Sep 17 00:00:00 2001 From: Ankan Date: Sun, 15 Jan 2023 15:15:53 +0100 Subject: [PATCH 025/162] some docs --- frame/staking/src/pallet/impls.rs | 2 +- frame/staking/src/pallet/mod.rs | 28 ++++++++++++++++++++-------- frame/staking/src/tests.rs | 3 ++- 3 files changed, 23 insertions(+), 10 deletions(-) diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index 0c95685f55f44..d761e1bbab8f6 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -167,7 +167,7 @@ impl Pallet { .retain(|&x| x >= current_era.saturating_sub(history_depth)); >::insert(&controller, &ledger); - if EraInfo::::temp_is_rewards_claimed(era, &ledger, &ledger.stash, page) { + if EraInfo::::is_rewards_claimed_temp(era, &ledger, &ledger.stash, page) { return Err(Error::::AlreadyClaimed .with_weight(T::WeightInfo::payout_stakers_alive_staked(0))) } else { diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index fee68e5c1cc1f..c6578da8cdc86 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -601,14 +601,18 @@ pub mod pallet { #[pallet::getter(fn current_planned_session)] pub type CurrentPlannedSession = StorageValue<_, SessionIndex, ValueQuery>; - /// Wrapper struct for `ErasStakers`, `ClaimedRewards`, `ErasStakersClipped`, - /// `ErasStakersPaged`, `ErasTotalStake`. + /// Wrapper struct for Era related information. It is not a pure encapsulation as these storage + /// items can be accessed directly but nevertheless recommended to use `EraInfo` for accesing + /// the following: (1) `ErasStakers`, (2) `ClaimedRewards`, (3) `ErasStakersClipped`, + /// (4) `ErasStakersPaged`, (5) `ErasTotalStake`. + // TODO(ank4n): docs, tests and add more methods to `EraInfo` for the supported storage items. pub(crate) struct EraInfo(sp_std::marker::PhantomData); impl EraInfo { - // TODO(ank4n): doc and clean up in 84 eras - // looks at `T::StakingLedger` for older non paged rewards, and `T::ClaimedRewards` for - // newer paged rewards. - pub(crate) fn temp_is_rewards_claimed( + /// Temporary function which looks at both (1) `T::StakingLedger` for legacy non-paged + /// rewards, and (2) `T::ClaimedRewards` for paged rewards. This can be removed once + /// `$HistoryDepth` eras have passed and none of the older non-paged rewards are claimable. + // TODO: Cleanup tracking issue: #13034 + pub(crate) fn is_rewards_claimed_temp( era: EraIndex, ledger: &StakingLedger, validator: &T::AccountId, @@ -618,6 +622,10 @@ pub mod pallet { Self::is_rewards_claimed(era, validator, page) } + /// Check if the rewards for the given era and page index have been claimed. + /// + /// This is only used for paged rewards. Once older non-paged rewards are no longer + /// relevant, `is_rewards_claimed_temp` can be removed and this function can be made public. fn is_rewards_claimed(era: EraIndex, validator: &T::AccountId, page: PageIndex) -> bool { ClaimedRewards::::get(era, validator).iter().find(|&&p| page == p).is_some() } @@ -1584,7 +1592,7 @@ pub mod pallet { Ok(()) } - /// Pay out all the stakers behind a single validator for a single era. + /// Pay out all the stakers behind a single validator for a single era and page. /// /// - `validator_stash` is the stash account of the validator. Their nominators, up to /// `T::MaxNominatorRewardedPerValidator`, will also receive their rewards. @@ -1593,8 +1601,12 @@ pub mod pallet { /// The origin of this call must be _Signed_. Any account can call this function, even if /// it is not one of the stakers. /// + /// The list of nominators is paged, each page being capped at `T::ExposurePageSize`. For + /// rewarding all the nominators, the call needs to be called for each page. If rewards are + /// not claimed in `${HistoryDepth}` eras, they are lost. + /// /// # - /// - Time complexity: at most O(MaxNominatorRewardedPerValidator). + /// - Time complexity: at most O(ExposurePageSize). /// - Contains a limited number of reads and writes. /// ----------- /// N is the Number of payouts for the validator (including the validator) diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index 67839c69952c0..eec91264743ec 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -3763,7 +3763,8 @@ fn test_payout_stakers() { let pre_payout_total_issuance = Balances::total_issuance(); RewardOnUnbalanceWasCalled::set(false); assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, 1, 0)); - // FIXME(ank4n): this won't work since the exposure page is not sorted anymore. + // FIXME(ank4n): this won't work since the exposure page is not sorted anymore. Instead fix + // it with multi block reward payout expectation. assert_eq_error_rate!( Balances::total_issuance(), pre_payout_total_issuance + actual_paid_out, From b19193a27c3e2d41e89c87c2ff9ee4dfeeff3f7e Mon Sep 17 00:00:00 2001 From: Ankan Date: Mon, 16 Jan 2023 16:39:43 +0100 Subject: [PATCH 026/162] rename to into_pages --- frame/staking/src/lib.rs | 2 +- frame/staking/src/pallet/impls.rs | 2 ++ frame/staking/src/pallet/mod.rs | 2 +- frame/staking/src/tests.rs | 2 +- 4 files changed, 5 insertions(+), 3 deletions(-) diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index 61ffebe5d1315..25da7e0196aef 100644 --- a/frame/staking/src/lib.rs +++ b/frame/staking/src/lib.rs @@ -736,7 +736,7 @@ impl Default for Exposure Exposure { - fn as_pages(&self, page_size: usize) -> Vec> { + fn into_pages(&self, page_size: usize) -> Vec> { let individual_chunks = self.others.chunks(page_size); let mut paged_exposure: Vec> = Vec::with_capacity(individual_chunks.len()); diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index d761e1bbab8f6..3f86b8dc566c7 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -662,6 +662,8 @@ impl Pallet { >::remove_prefix(era_index, None); #[allow(deprecated)] >::remove_prefix(era_index, None); + #[allow(deprecated)] + >::remove_prefix(era_index, None); >::remove(era_index); >::remove(era_index); >::remove(era_index); diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index c6578da8cdc86..0ee7481601aba 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -661,7 +661,7 @@ pub mod pallet { >::insert(era, &validator, &exposure); exposure - .as_pages(T::ExposurePageSize::get() as usize) + .into_pages(T::ExposurePageSize::get() as usize) .iter() .enumerate() .for_each(|(page, paged_exposure)| { diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index eec91264743ec..e91b9695aca5c 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -5673,7 +5673,7 @@ fn can_page_exposure() { Exposure { total: total_stake, own: own_stake, others }; // when - let paged_exposures: Vec> = exposure.clone().as_pages(3); + let paged_exposures: Vec> = exposure.clone().into_pages(3); // then // 7 pages of nominators. From e3569bf624f27ab639b0bfc827245e30e29135d5 Mon Sep 17 00:00:00 2001 From: Ankan Date: Mon, 16 Jan 2023 17:29:59 +0100 Subject: [PATCH 027/162] verify claimed rewards and era stakers is cleared --- frame/staking/src/pallet/impls.rs | 3 +++ frame/staking/src/pallet/mod.rs | 18 +++++++-------- frame/staking/src/tests.rs | 37 ++++++++++++++++++++++++++++++- 3 files changed, 47 insertions(+), 11 deletions(-) diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index 3f86b8dc566c7..f7f76dfc61401 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -664,6 +664,9 @@ impl Pallet { >::remove_prefix(era_index, None); #[allow(deprecated)] >::remove_prefix(era_index, None); + #[allow(deprecated)] + >::remove_prefix(era_index, None); + >::remove(era_index); >::remove(era_index); >::remove(era_index); diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index 0ee7481601aba..28214afce5126 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -450,18 +450,17 @@ pub mod pallet { #[pallet::storage] #[pallet::getter(fn eras_stakers_paged)] #[pallet::unbounded] - pub type ErasStakersPaged = StorageNMap< + pub type ErasStakersPaged = StorageDoubleMap< _, - ( - NMapKey, - NMapKey, - NMapKey, - ), + Twox64Concat, + EraIndex, + Twox64Concat, + (T::AccountId, PageIndex), ExposurePage>, OptionQuery, >; - /// History of rewards claimed by validator by era and page. + /// History of claimed paged rewards by era and validator. /// /// This is keyed by era and validator stash which maps to the set of page indexes which have /// been claimed. @@ -475,7 +474,6 @@ pub mod pallet { Twox64Concat, EraIndex, Twox64Concat, - // Validator stash T::AccountId, Vec, ValueQuery, @@ -635,7 +633,7 @@ pub mod pallet { validator: &T::AccountId, page: PageIndex, ) -> ExposurePage> { - return match >::get((era, validator, page)) { + return match >::get(era, (validator, page)) { Some(paged_exposure) => paged_exposure, // only return clipped exposure if page zero and no paged exposure entry None if page == 0 => >::get(&era, validator).into(), @@ -665,7 +663,7 @@ pub mod pallet { .iter() .enumerate() .for_each(|(page, paged_exposure)| { - >::insert((era, &validator, page as u32), &paged_exposure); + >::insert(era, (&validator, page as u32), &paged_exposure); }); } diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index e91b9695aca5c..e84bc9a7553a1 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -2203,7 +2203,7 @@ fn reward_validator_slashing_validator_does_not_overflow() { // Check reward ErasRewardPoints::::insert(0, reward); ErasStakers::::insert(0, 11, &exposure); - ErasStakersPaged::::insert((0, 11, 0), exposure_page); + ErasStakersPaged::::insert(0, (11, 0), exposure_page); ErasValidatorReward::::insert(0, stake); assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, 0, 0)); assert_eq!(Balances::total_balance(&11), stake * 2); @@ -5698,6 +5698,41 @@ fn can_page_exposure() { assert_eq!(paged_exposures.iter().map(|a| a.others.len()).reduce(|a, b| a + b).unwrap(), 19); } +#[test] +fn should_retain_era_info_only_upto_history_depth() { + ExtBuilder::default().build_and_execute(|| { + // remove existing exposure + Pallet::::clear_era_information(0); + let validator_stash = 10; + + for era in 0..4 { + ClaimedRewards::::insert(era, &validator_stash, vec![0, 1, 2]); + for page in 0..3 { + ErasStakersPaged::::insert( + era, (&validator_stash, page), + ExposurePage { total: 100, page_total: 100, own: 100, others: vec![] }, + ); + } + } + + for i in 0..4 { + // Count of entries remaining in ClaimedRewards = total - cleared_count + assert_eq!(ClaimedRewards::::iter().count(), (4 - i)); + // 1 claimed_rewards entry for each era + assert_eq!(ClaimedRewards::::iter_prefix(i as EraIndex).count(), 1); + // 3 entries (pages) for each era + assert_eq!(ErasStakersPaged::::iter_prefix(i as EraIndex).count(), 3); + + // when clear era info + Pallet::::clear_era_information(i as EraIndex); + + // then all era entries are cleared + assert_eq!(ClaimedRewards::::iter_prefix(i as EraIndex).count(), 0); + assert_eq!(ErasStakersPaged::::iter_prefix(i as EraIndex).count(), 0); + } + }); +} + mod staking_interface { use frame_support::storage::with_storage_layer; use sp_staking::StakingInterface; From 99913b3dc579295897103d410094d743ec8e844b Mon Sep 17 00:00:00 2001 From: Ankan Date: Mon, 16 Jan 2023 17:32:49 +0100 Subject: [PATCH 028/162] small comment --- frame/staking/src/pallet/mod.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index 28214afce5126..62ed515bc726e 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -442,10 +442,10 @@ pub mod pallet { /// Paginated exposure of a validator at given era. /// - /// This is keyed first by the era index to allow bulk deletion, then the stash account and - /// finally the page. + /// This is keyed first by the era index to allow bulk deletion, then the tuple of stash account + /// and page. /// - /// It is removed after `HISTORY_DEPTH` eras. + /// This uses DoubleMap instead of NMap to efficiently clear this after `HISTORY_DEPTH` eras. /// If stakers hasn't been set or has been removed then empty exposure is returned. #[pallet::storage] #[pallet::getter(fn eras_stakers_paged)] From cc6be46e08dd3dc18ba73129215cf757bcae0a4d Mon Sep 17 00:00:00 2001 From: Ankan Date: Mon, 16 Jan 2023 17:39:39 +0100 Subject: [PATCH 029/162] reuse MaxNominatorRewardedPerValidator --- frame/staking/src/mock.rs | 1 - frame/staking/src/pallet/mod.rs | 10 ++++------ 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/frame/staking/src/mock.rs b/frame/staking/src/mock.rs index 754dde0165549..d5204b440f0a8 100644 --- a/frame/staking/src/mock.rs +++ b/frame/staking/src/mock.rs @@ -295,7 +295,6 @@ impl crate::pallet::pallet::Config for Test { type EraPayout = ConvertCurve; type NextNewSession = Session; type MaxNominatorRewardedPerValidator = ConstU32<64>; - type ExposurePageSize = ConstU32<64>; type OffendingValidatorsThreshold = OffendingValidatorsThreshold; type ElectionProvider = onchain::OnChainExecution; type GenesisElectionProvider = Self::ElectionProvider; diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index 62ed515bc726e..3b2c7dac17175 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -205,12 +205,10 @@ pub mod pallet { /// /// For each validator only the `$MaxNominatorRewardedPerValidator` biggest stakers can /// claim their reward. This used to limit the i/o cost for the nominator payout. + // TODO(ank4n): Refactor into a better name to indicate that this is a per-page limit. #[pallet::constant] type MaxNominatorRewardedPerValidator: Get; - #[pallet::constant] - type ExposurePageSize: 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; @@ -659,7 +657,7 @@ pub mod pallet { >::insert(era, &validator, &exposure); exposure - .into_pages(T::ExposurePageSize::get() as usize) + .into_pages(T::MaxNominatorRewardedPerValidator::get() as usize) .iter() .enumerate() .for_each(|(page, paged_exposure)| { @@ -1599,12 +1597,12 @@ pub mod pallet { /// The origin of this call must be _Signed_. Any account can call this function, even if /// it is not one of the stakers. /// - /// The list of nominators is paged, each page being capped at `T::ExposurePageSize`. For + /// The list of nominators is paged, each page being capped at `T::MaxNominatorRewardedPerValidator`. For /// rewarding all the nominators, the call needs to be called for each page. If rewards are /// not claimed in `${HistoryDepth}` eras, they are lost. /// /// # - /// - Time complexity: at most O(ExposurePageSize). + /// - Time complexity: at most O(MaxNominatorRewardedPerValidator). /// - Contains a limited number of reads and writes. /// ----------- /// N is the Number of payouts for the validator (including the validator) From 6623056a1004f0ffdab35007b5e52602a041a022 Mon Sep 17 00:00:00 2001 From: Ankan Date: Thu, 19 Jan 2023 00:18:25 +0100 Subject: [PATCH 030/162] get to the same stage as 1st attempt --- frame/staking/src/lib.rs | 76 ++++++++++++++++++--------------- frame/staking/src/mock.rs | 3 +- frame/staking/src/pallet/mod.rs | 47 ++++++++++++++------ frame/staking/src/tests.rs | 53 ++++++++++++----------- 4 files changed, 105 insertions(+), 74 deletions(-) diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index 25da7e0196aef..cff9f7873e4f3 100644 --- a/frame/staking/src/lib.rs +++ b/frame/staking/src/lib.rs @@ -313,7 +313,7 @@ use sp_runtime::{ }; use sp_staking::{ offence::{Offence, OffenceError, ReportOffence}, - EraIndex, SessionIndex, + EraIndex, PageIndex, SessionIndex, }; use sp_std::{collections::btree_map::BTreeMap, prelude::*}; pub use weights::WeightInfo; @@ -736,63 +736,54 @@ impl Default for Exposure Exposure { - fn into_pages(&self, page_size: usize) -> Vec> { - let individual_chunks = self.others.chunks(page_size); - let mut paged_exposure: Vec> = + fn as_pages( + &self, + page_size: u32, + ) -> (ExposureOverview, Vec>) { + let individual_chunks = self.others.chunks(page_size as usize); + let mut exposure_pages: Vec> = Vec::with_capacity(individual_chunks.len()); - // own balance that has not been accounted for in the paged exposure - let mut own_left = self.own; - for chunk in individual_chunks { - let own = own_left; - let mut page_total = own; + let mut page_total: Balance = Zero::zero(); for individual in chunk.iter() { page_total = page_total.saturating_add(individual.value); } - paged_exposure.push(ExposurePage { - total: self.total, + exposure_pages.push(ExposurePage { page_total, - own, others: chunk .iter() .map(|c| IndividualExposure { who: c.who.clone(), value: c.value }) .collect(), }); - - // subtract own that has been accounted - own_left = own_left.saturating_sub(own); } - paged_exposure + ( + ExposureOverview { + total: self.total, + own: self.own, + nominator_count: self.others.len() as u32, + page_count: exposure_pages.len() as PageIndex, + }, + exposure_pages, + ) } } /// A snapshot of the stake backing a single validator in the system. #[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Encode, Decode, RuntimeDebug, TypeInfo)] pub struct ExposurePage { - /// The total balance backing this validator. - #[codec(compact)] - pub total: Balance, /// The total balance of this chunk/page. #[codec(compact)] pub page_total: Balance, - /// The validator's own stash that is exposed. - #[codec(compact)] - pub own: Balance, /// The portions of nominators stashes that are exposed. pub others: Vec>, } impl Default for ExposurePage { fn default() -> Self { - Self { - total: Default::default(), - page_total: Default::default(), - own: Default::default(), - others: vec![], - } + Self { page_total: Default::default(), others: vec![] } } } @@ -800,14 +791,31 @@ impl From> for ExposurePage { fn from(exposure: Exposure) -> Self { - Self { - total: exposure.total, - page_total: exposure.total, - own: exposure.own, - others: exposure.others, - } + Self { page_total: exposure.total, others: exposure.others } } } + +/// A snapshot of the stake backing a single validator in the system. +#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Encode, Decode, RuntimeDebug, TypeInfo)] +pub struct ExposureOverview { + /// The total balance backing this validator. + #[codec(compact)] + pub total: Balance, + /// The validator's own stash that is exposed. + #[codec(compact)] + pub own: Balance, + /// Number of nominators backing this validator. + pub nominator_count: u32, + /// Number of pages of backers. + pub page_count: PageIndex, +} + +impl Default for ExposureOverview { + fn default() -> Self { + Self { total: Default::default(), own: Default::default(), nominator_count: Default::default(), page_count: Default::default() } + } +} + /// A pending slash record. The value of the slash has been computed but not applied yet, /// rather deferred for several eras. #[derive(Encode, Decode, RuntimeDebug, TypeInfo)] diff --git a/frame/staking/src/mock.rs b/frame/staking/src/mock.rs index d5204b440f0a8..f76ae70040975 100644 --- a/frame/staking/src/mock.rs +++ b/frame/staking/src/mock.rs @@ -232,6 +232,7 @@ parameter_types! { pub static BagThresholds: &'static [sp_npos_elections::VoteWeight] = &THRESHOLDS; pub static MaxNominations: u32 = 16; pub static HistoryDepth: u32 = 80; + pub static MaxNominatorRewardedPerValidator: u32 = 64; pub static MaxUnlockingChunks: u32 = 32; pub static RewardOnUnbalanceWasCalled: bool = false; pub static LedgerSlashPerEra: (BalanceOf, BTreeMap>) = (Zero::zero(), BTreeMap::new()); @@ -294,7 +295,7 @@ impl crate::pallet::pallet::Config for Test { type SessionInterface = Self; type EraPayout = ConvertCurve; type NextNewSession = Session; - type MaxNominatorRewardedPerValidator = ConstU32<64>; + type MaxNominatorRewardedPerValidator = MaxNominatorRewardedPerValidator; type OffendingValidatorsThreshold = OffendingValidatorsThreshold; type ElectionProvider = onchain::OnChainExecution; type GenesisElectionProvider = Self::ElectionProvider; diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index 3b2c7dac17175..f5a5182ca6456 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -59,7 +59,7 @@ pub(crate) const SPECULATIVE_NUM_SPANS: u32 = 32; pub mod pallet { use frame_election_provider_support::ElectionDataProvider; - use crate::BenchmarkingConfig; + use crate::{BenchmarkingConfig, ExposureOverview}; use super::*; @@ -414,6 +414,20 @@ pub mod pallet { ValueQuery, >; + // TODO(ank4n) + #[pallet::storage] + #[pallet::getter(fn eras_stakers_overview)] + #[pallet::unbounded] + pub type ErasStakersOverview = StorageDoubleMap< + _, + Twox64Concat, + EraIndex, + Twox64Concat, + T::AccountId, + ExposureOverview>, + ValueQuery, + >; + /// Clipped Exposure of validator at era. /// /// This is similar to [`ErasStakers`] but number of nominators exposed is reduced to the @@ -630,11 +644,15 @@ pub mod pallet { era: EraIndex, validator: &T::AccountId, page: PageIndex, - ) -> ExposurePage> { + ) -> Exposure> { return match >::get(era, (validator, page)) { - Some(paged_exposure) => paged_exposure, // only return clipped exposure if page zero and no paged exposure entry - None if page == 0 => >::get(&era, validator).into(), + None if page == 0 => >::get(&era, validator), + Some(page) => { + // TODO(ank4n): more due diligence on the correctness of this. + let overview = >::get(&era, validator); + Exposure { total: overview.total, own: overview.own, others: page.others } + }, _ => Default::default(), } } @@ -656,13 +674,13 @@ pub mod pallet { ) { >::insert(era, &validator, &exposure); - exposure - .into_pages(T::MaxNominatorRewardedPerValidator::get() as usize) - .iter() - .enumerate() - .for_each(|(page, paged_exposure)| { - >::insert(era, (&validator, page as u32), &paged_exposure); - }); + let (exposure_overview, exposure_pages) = + exposure.as_pages(T::MaxNominatorRewardedPerValidator::get()); + + >::insert(era, &validator, &exposure_overview); + exposure_pages.iter().enumerate().for_each(|(page, paged_exposure)| { + >::insert(era, (&validator, page as u32), &paged_exposure); + }); } pub(crate) fn set_total_stake(era: EraIndex, total_stake: BalanceOf) { @@ -1597,9 +1615,10 @@ pub mod pallet { /// The origin of this call must be _Signed_. Any account can call this function, even if /// it is not one of the stakers. /// - /// The list of nominators is paged, each page being capped at `T::MaxNominatorRewardedPerValidator`. For - /// rewarding all the nominators, the call needs to be called for each page. If rewards are - /// not claimed in `${HistoryDepth}` eras, they are lost. + /// The list of nominators is paged, each page being capped at + /// `T::MaxNominatorRewardedPerValidator`. For rewarding all the nominators, the call needs + /// to be called for each page. If rewards are not claimed in `${HistoryDepth}` eras, they + /// are lost. /// /// # /// - Time complexity: at most O(MaxNominatorRewardedPerValidator). diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index e84bc9a7553a1..ba17465f459da 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -2194,7 +2194,8 @@ fn reward_validator_slashing_validator_does_not_overflow() { let _ = Balances::make_free_balance_be(&11, stake); let exposure = Exposure:: { total: stake, own: stake, others: vec![] }; - let exposure_page: ExposurePage = exposure.clone().into(); + let (exposure_overview, _) = + exposure.clone().as_pages(MaxNominatorRewardedPerValidator::get()); let reward = EraRewardPoints:: { total: 1, individual: vec![(11, 1)].into_iter().collect(), @@ -2203,7 +2204,7 @@ fn reward_validator_slashing_validator_does_not_overflow() { // Check reward ErasRewardPoints::::insert(0, reward); ErasStakers::::insert(0, 11, &exposure); - ErasStakersPaged::::insert(0, (11, 0), exposure_page); + ErasStakersOverview::::insert(0, 11, exposure_overview); ErasValidatorReward::::insert(0, stake); assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, 0, 0)); assert_eq!(Balances::total_balance(&11), stake * 2); @@ -3691,7 +3692,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 as Get<_>>::get() { + for i in 0..=MaxNominatorRewardedPerValidator::get() { let stash = 10_000 + i as AccountId; let controller = 20_000 + i as AccountId; let balance = 10_000 + i as Balance; @@ -3714,7 +3715,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 as Get<_>>::get() { + for i in 0..=MaxNominatorRewardedPerValidator::get() { let stash = 10_000 + i as AccountId; let balance = 10_000 + i as Balance; if stash == 10_000 { @@ -3985,8 +3986,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 as Get<_>>::get(); + let max_nom_rewarded = MaxNominatorRewardedPerValidator::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; @@ -5673,29 +5673,31 @@ fn can_page_exposure() { Exposure { total: total_stake, own: own_stake, others }; // when - let paged_exposures: Vec> = exposure.clone().into_pages(3); + let (exposure_overview, exposure_page): ( + ExposureOverview, + Vec>, + ) = exposure.clone().as_pages(3); // then // 7 pages of nominators. - assert_eq!(paged_exposures.len(), (19 / 3) + 1); - // first page stake = 500 (own) + 100 + 200 + 300 - assert!(matches!( - paged_exposures[0], - ExposurePage { total: 19_500, page_total: 1100, own: 500, .. } - )); + assert_eq!(exposure_page.len(), 7); + assert_eq!(exposure_overview.page_count, 7); + // first page stake = 100 + 200 + 300 + assert!(matches!(exposure_page[0], ExposurePage { page_total: 600, .. })); // second page stake = 0 + 400 + 500 + 600 - assert!(matches!( - paged_exposures[1], - ExposurePage { total: 19_500, page_total: 1500, own: 0, .. } - )); - // verify total is always the total stake backing a validator for all the pages. - assert_eq!(paged_exposures.iter().filter(|a| a.total == 19_500).count(), 7); + assert!(matches!(exposure_page[1], ExposurePage { page_total: 1500, .. })); + // verify overview has the total + assert_eq!(exposure_overview.total, 19_500); // verify total stake is same as in the original exposure. - assert_eq!(paged_exposures.iter().map(|a| a.page_total).reduce(|a, b| a + b).unwrap(), 19_500); - // verify own stake is same as in the original exposure. - assert_eq!(paged_exposures.iter().map(|a| a.own).reduce(|a, b| a + b).unwrap(), 500); + assert_eq!( + exposure_page.iter().map(|a| a.page_total).reduce(|a, b| a + b).unwrap(), + 19_500 - exposure_overview.own + ); + // verify own stake is correct + assert_eq!(exposure_overview.own, 500); // verify number of nominators are same as in the original exposure. - assert_eq!(paged_exposures.iter().map(|a| a.others.len()).reduce(|a, b| a + b).unwrap(), 19); + assert_eq!(exposure_page.iter().map(|a| a.others.len()).reduce(|a, b| a + b).unwrap(), 19); + assert_eq!(exposure_overview.nominator_count, 19); } #[test] @@ -5709,8 +5711,9 @@ fn should_retain_era_info_only_upto_history_depth() { ClaimedRewards::::insert(era, &validator_stash, vec![0, 1, 2]); for page in 0..3 { ErasStakersPaged::::insert( - era, (&validator_stash, page), - ExposurePage { total: 100, page_total: 100, own: 100, others: vec![] }, + era, + (&validator_stash, page), + ExposurePage { page_total: 100, others: vec![] }, ); } } From 90e7a9d6c0b2a0d1b92f7b675ca4b52783d3c769 Mon Sep 17 00:00:00 2001 From: Ankan Date: Sat, 21 Jan 2023 20:29:52 +0100 Subject: [PATCH 031/162] pay all pages --- frame/staking/src/mock.rs | 5 ++++- frame/staking/src/pallet/mod.rs | 4 ++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/frame/staking/src/mock.rs b/frame/staking/src/mock.rs index f76ae70040975..5afb219b3c27d 100644 --- a/frame/staking/src/mock.rs +++ b/frame/staking/src/mock.rs @@ -761,7 +761,10 @@ pub(crate) fn make_all_reward_payment(era: EraIndex) { // reward validators for validator_controller in validators_with_reward.iter().filter_map(Staking::bonded) { let ledger = >::get(&validator_controller).unwrap(); - assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), ledger.stash, era, 0)); + for page in 0..EraInfo::::get_page_count(era, &ledger.stash) { + assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), ledger.stash, era, page)); + } + } } diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index f5a5182ca6456..0af0ef4b17fea 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -657,6 +657,10 @@ pub mod pallet { } } + // return atleast one page of exposure to be backward compatible to `EraStakersClipped` exposures. + pub(crate) fn get_page_count(era: EraIndex, validator: &T::AccountId) -> PageIndex { + >::get(&era, validator).page_count.max(1) + } pub(crate) fn set_rewards_as_claimed( era: EraIndex, validator: &T::AccountId, From cf6ee88a129d6b08d38714fb4c4b48ffd40da7db Mon Sep 17 00:00:00 2001 From: Ankan Date: Sat, 21 Jan 2023 20:42:54 +0100 Subject: [PATCH 032/162] introduce invalid page error --- frame/staking/src/pallet/impls.rs | 2 ++ frame/staking/src/pallet/mod.rs | 17 +++++++++++------ 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index f7f76dfc61401..cf063bd05fcd6 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -149,6 +149,8 @@ impl Pallet { .with_weight(T::WeightInfo::payout_stakers_alive_staked(0)) ); + ensure!(page < EraInfo::::get_page_count(era, &validator_stash), Error::::InvalidPage); + // Note: if era has no reward to be claimed, era may be future. better not to update // `ledger.legacy_claimed_rewards` in this case. let era_payout = >::get(&era).ok_or_else(|| { diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index 0af0ef4b17fea..61c67a952f7cb 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -657,10 +657,14 @@ pub mod pallet { } } - // return atleast one page of exposure to be backward compatible to `EraStakersClipped` exposures. + /// Returns the number of pages of exposure a validator has for the given era. + /// + /// This will always return at minimum one count of exposure to be backward compatible to + /// non-paged reward payouts. pub(crate) fn get_page_count(era: EraIndex, validator: &T::AccountId) -> PageIndex { >::get(&era, validator).page_count.max(1) } + pub(crate) fn set_rewards_as_claimed( era: EraIndex, validator: &T::AccountId, @@ -883,6 +887,8 @@ pub mod pallet { NotSortedAndUnique, /// Rewards for this era have already been claimed for this validator. AlreadyClaimed, + /// No nominators exist on this page. + InvalidPage, /// Incorrect previous history depth input provided. IncorrectHistoryDepth, /// Incorrect number of slashing spans provided. @@ -1619,10 +1625,10 @@ pub mod pallet { /// The origin of this call must be _Signed_. Any account can call this function, even if /// it is not one of the stakers. /// - /// The list of nominators is paged, each page being capped at - /// `T::MaxNominatorRewardedPerValidator`. For rewarding all the nominators, the call needs - /// to be called for each page. If rewards are not claimed in `${HistoryDepth}` eras, they - /// are lost. + /// The list of nominators is paged, with each page being capped at + /// `T::MaxNominatorRewardedPerValidator`. If a validator has multiple pages of nominators, + /// the call needs to be made for each page such that all nominators receive the reward. If + /// rewards are not claimed in `${HistoryDepth}` eras, they are lost. /// /// # /// - Time complexity: at most O(MaxNominatorRewardedPerValidator). @@ -1636,7 +1642,6 @@ pub mod pallet { /// NOTE: weights are assuming that payouts are made to alive stash account (Staked). /// Paying even a dead controller is cheaper weight-wise. We don't do any refunds here. /// # - // todo(ank4n): fix weights. #[pallet::call_index(18)] #[pallet::weight(T::WeightInfo::payout_stakers_alive_staked( T::MaxNominatorRewardedPerValidator::get() From b86e3f88405d43ad3066d4e48dbfeb9c02ffc197 Mon Sep 17 00:00:00 2001 From: Ankan Date: Sat, 21 Jan 2023 20:59:18 +0100 Subject: [PATCH 033/162] docs --- frame/staking/src/mock.rs | 1 - frame/staking/src/pallet/mod.rs | 19 ++++++++++++++++++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/frame/staking/src/mock.rs b/frame/staking/src/mock.rs index 5afb219b3c27d..e90549d81c1b7 100644 --- a/frame/staking/src/mock.rs +++ b/frame/staking/src/mock.rs @@ -750,7 +750,6 @@ pub(crate) fn add_slash(who: &AccountId) { } /// Make all validator and nominator request their payment -// TODO(ank4n) pay out all the paged nominators. pub(crate) fn make_all_reward_payment(era: EraIndex) { let validators_with_reward = ErasRewardPoints::::get(era) .individual diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index 61c67a952f7cb..344a3c03c4b43 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -414,7 +414,17 @@ pub mod pallet { ValueQuery, >; - // TODO(ank4n) + /// Summary of validator exposure at a given era. + /// + /// This contains the total stake in support of the validator and their own stake. In addition, + /// it can also be used to get the number of nominators backing this validator and the number of + /// exposure pages they are divided into. The page count is useful to determine the number of + /// pages of rewards that needs to be claimed. + /// + /// This is keyed first by the era index to allow bulk deletion and then the stash account. + /// + /// Is it removed after `HISTORY_DEPTH` eras. + /// If stakers hasn't been set or has been removed then empty overview is returned. #[pallet::storage] #[pallet::getter(fn eras_stakers_overview)] #[pallet::unbounded] @@ -640,6 +650,10 @@ pub mod pallet { ClaimedRewards::::get(era, validator).iter().find(|&&p| page == p).is_some() } + /// Get exposure info for a validator at a given era and page. + /// + /// This builds a paged exposure from `ExposureOverview` and `ExposurePage` of the + /// validator. For older non-paged exposure, it returns the clipped exposure directly. pub(crate) fn get_validator_exposure( era: EraIndex, validator: &T::AccountId, @@ -665,6 +679,7 @@ pub mod pallet { >::get(&era, validator).page_count.max(1) } + /// Creates an entry to track validator reward has been claimed for a given era and page. pub(crate) fn set_rewards_as_claimed( era: EraIndex, validator: &T::AccountId, @@ -675,6 +690,7 @@ pub mod pallet { }) } + /// Store exposure for elected validators at start of an era. pub(crate) fn set_validator_exposure( era: EraIndex, validator: &T::AccountId, @@ -691,6 +707,7 @@ pub mod pallet { }); } + /// Store total exposure for all the elected validators in the era. pub(crate) fn set_total_stake(era: EraIndex, total_stake: BalanceOf) { >::insert(era, total_stake); } From 107214794d96f27c343fc183fa2270921fdfa15e Mon Sep 17 00:00:00 2001 From: Ankan Date: Sat, 21 Jan 2023 21:33:03 +0100 Subject: [PATCH 034/162] test all nominators are paid --- frame/staking/src/pallet/mod.rs | 2 +- frame/staking/src/tests.rs | 31 ++++++++++++++++++++----------- 2 files changed, 21 insertions(+), 12 deletions(-) diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index 344a3c03c4b43..fd611b07a3132 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -622,7 +622,7 @@ pub mod pallet { pub type CurrentPlannedSession = StorageValue<_, SessionIndex, ValueQuery>; /// Wrapper struct for Era related information. It is not a pure encapsulation as these storage - /// items can be accessed directly but nevertheless recommended to use `EraInfo` for accesing + /// items can be accessed directly but nevertheless recommended to use `EraInfo` for accessing /// the following: (1) `ErasStakers`, (2) `ClaimedRewards`, (3) `ErasStakersClipped`, /// (4) `ErasStakersPaged`, (5) `ErasTotalStake`. // TODO(ank4n): docs, tests and add more methods to `EraInfo` for the supported storage items. diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index ba17465f459da..d6e34f363e8d3 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -3690,9 +3690,12 @@ fn six_session_delay() { } #[test] -fn test_max_nominator_rewarded_per_validator_and_cant_steal_someone_else_reward() { +fn test_nominators_are_rewarded_for_all_exposure_page() { ExtBuilder::default().build_and_execute(|| { - for i in 0..=MaxNominatorRewardedPerValidator::get() { + // 3 pages of exposure + let nominator_count = 2 * MaxNominatorRewardedPerValidator::get() + 1; + + for i in 0..nominator_count { let stash = 10_000 + i as AccountId; let controller = 20_000 + i as AccountId; let balance = 10_000 + i as Balance; @@ -3714,15 +3717,21 @@ fn test_max_nominator_rewarded_per_validator_and_cant_steal_someone_else_reward( mock::start_active_era(2); mock::make_all_reward_payment(1); - // Assert only nominators from 1 to Max are rewarded - for i in 0..=MaxNominatorRewardedPerValidator::get() { - let stash = 10_000 + i as AccountId; - let balance = 10_000 + i as Balance; - if stash == 10_000 { - assert!(Balances::free_balance(&stash) == balance); - } else { - assert!(Balances::free_balance(&stash) > balance); - } + assert_eq!(EraInfo::::get_page_count(1, &11), 3); + + // Assert all nominators are rewarded according to their stake + for i in 0..nominator_count { + // balance of the nominator after the reward payout. + let current_balance = Balances::free_balance(&((10000 + i) as AccountId)); + // balance of the nominator in the previous iteration. + let previous_balance = Balances::free_balance(&((10000 + i - 1) as AccountId)); + // balance before the reward. + let original_balance = 10_000 + i as Balance; + + assert!(current_balance > original_balance); + // since the stake of the nominator is increasing for each iteration, the final balance + // after the reward should also be higher than the previous iteration. + assert!(current_balance > previous_balance); } }); } From 9f4ea044cfebffb5829a1a9825ea0ad91b6236ee Mon Sep 17 00:00:00 2001 From: Ankan Date: Sat, 21 Jan 2023 23:34:17 +0100 Subject: [PATCH 035/162] all test pass --- frame/staking/src/pallet/mod.rs | 7 +- frame/staking/src/tests.rs | 160 +++++++++++++++++--------------- 2 files changed, 90 insertions(+), 77 deletions(-) diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index fd611b07a3132..2e6bdbb6b6adc 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -662,10 +662,11 @@ pub mod pallet { return match >::get(era, (validator, page)) { // only return clipped exposure if page zero and no paged exposure entry None if page == 0 => >::get(&era, validator), - Some(page) => { - // TODO(ank4n): more due diligence on the correctness of this. + Some(exposure_page) => { let overview = >::get(&era, validator); - Exposure { total: overview.total, own: overview.own, others: page.others } + // own stake is included only once in the first page. + let own = if page == 0 { overview.own } else { Zero::zero() }; + Exposure { total: overview.total, own, others: exposure_page.others } }, _ => Default::default(), } diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index d6e34f363e8d3..7539a350270dd 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -3737,7 +3737,7 @@ fn test_nominators_are_rewarded_for_all_exposure_page() { } #[test] -fn test_payout_stakers() { +fn test_multi_page_payout_stakers() { // Test that payout_stakers work in general, including that only the top // `T::MaxNominatorRewardedPerValidator` nominators are rewarded. ExtBuilder::default().has_stakers(false).build_and_execute(|| { @@ -3755,45 +3755,65 @@ fn test_payout_stakers() { let bond_amount = balance + i as Balance; bond_nominator(1000 + i, 100 + i, bond_amount, vec![11]); total_exposure += bond_amount; - if i >= 36 { - payout_exposure += bond_amount; - }; + // with multi page reward payout, payout exposure is same as total exposure. + payout_exposure += bond_amount; } + let payout_exposure_part = Perbill::from_rational(payout_exposure, total_exposure); mock::start_active_era(1); Staking::reward_by_ids(vec![(11, 1)]); + // Since `MaxNominatorRewardedPerValidator = 64`, there are two pages of validator exposure. + assert_eq!(EraInfo::::get_page_count(1, &11), 2); + // compute and ensure the reward amount is greater than zero. let payout = current_total_payout_for_duration(reward_time_per_era()); let actual_paid_out = payout_exposure_part * payout; - + println!("Actual paid out {:?}", actual_paid_out); mock::start_active_era(2); + // verify the exposures are calculated correctly. + let actual_exposure_0 = EraInfo::::get_validator_exposure(1, &11, 0); + assert_eq!(actual_exposure_0.total, total_exposure); + assert_eq!(actual_exposure_0.own, 1000); + assert_eq!(actual_exposure_0.others.len(), 64); + let actual_exposure_1 = EraInfo::::get_validator_exposure(1, &11, 1); + assert_eq!(actual_exposure_1.total, total_exposure); + // own stake is only included once in the first page + assert_eq!(actual_exposure_1.own, 0); + assert_eq!(actual_exposure_1.others.len(), 100 - 64); + let pre_payout_total_issuance = Balances::total_issuance(); RewardOnUnbalanceWasCalled::set(false); + + // Payout rewards for first exposure page assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, 1, 0)); - // FIXME(ank4n): this won't work since the exposure page is not sorted anymore. Instead fix - // it with multi block reward payout expectation. + + // verify rewards have been paid out but still some left + assert!(Balances::total_issuance() > pre_payout_total_issuance); + assert!(Balances::total_issuance() < pre_payout_total_issuance + actual_paid_out); + + // Payout the second and last page of nominators + assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, 1, 1)); + + // verify all rewards have been paid out assert_eq_error_rate!( Balances::total_issuance(), pre_payout_total_issuance + actual_paid_out, - 1 + 2 ); assert!(RewardOnUnbalanceWasCalled::get()); - // Top 64 nominators of validator 11 automatically paid out, including the validator + // verify all nominators of validator 11 are paid out, including the validator // Validator payout goes to controller. assert!(Balances::free_balance(&10) > balance); - for i in 36..100 { + for i in 0..100 { assert!(Balances::free_balance(&(100 + i)) > balance + i as Balance); } - // The bottom 36 do not - for i in 0..36 { - assert_eq!(Balances::free_balance(&(100 + i)), balance + i as Balance); - } - // We track rewards in `legacy_claimed_rewards` vec + // verify we no longer track rewards in `legacy_claimed_rewards` vec + let ledger = Staking::ledger(&10); assert_eq!( Staking::ledger(&10), Some(StakingLedger { @@ -3801,10 +3821,18 @@ fn test_payout_stakers() { total: 1000, active: 1000, unlocking: Default::default(), - legacy_claimed_rewards: bounded_vec![1] + legacy_claimed_rewards: bounded_vec![] }) ); + // verify rewards are tracked to prevent double claims + for page in 0..EraInfo::::get_page_count(1, &11) { + assert_eq!( + EraInfo::::is_rewards_claimed_temp(1, ledger.as_ref().unwrap(), &11, page), + true + ); + } + for i in 3..16 { Staking::reward_by_ids(vec![(11, 1)]); @@ -3815,31 +3843,34 @@ fn test_payout_stakers() { mock::start_active_era(i); RewardOnUnbalanceWasCalled::set(false); - assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, i - 1, 0)); + mock::make_all_reward_payment(i - 1); assert_eq_error_rate!( Balances::total_issuance(), pre_payout_total_issuance + actual_paid_out, - 1 + 2 ); assert!(RewardOnUnbalanceWasCalled::get()); + + // verify we track rewards for each era and page + for page in 0..EraInfo::::get_page_count(i - 1, &11) { + assert_eq!( + EraInfo::::is_rewards_claimed_temp( + i - 1, + Staking::ledger(&10).as_ref().unwrap(), + &11, + page + ), + true + ); + } } - // We track rewards in `claimed_rewards` vec - assert_eq!( - Staking::ledger(&10), - Some(StakingLedger { - stash: 11, - total: 1000, - active: 1000, - unlocking: Default::default(), - legacy_claimed_rewards: (1..=14).collect::>().try_into().unwrap() - }) - ); + assert_eq!(Staking::claimed_rewards(14, &11), vec![0, 1]); let last_era = 99; let history_depth = HistoryDepth::get(); - let expected_last_reward_era = last_era - 1; - let expected_start_reward_era = last_era - history_depth; + let last_reward_era = last_era - 1; + let first_claimable_reward_era = last_era - history_depth; for i in 16..=last_era { Staking::reward_by_ids(vec![(11, 1)]); // compute and ensure the reward amount is greater than zero. @@ -3847,53 +3878,34 @@ fn test_payout_stakers() { mock::start_active_era(i); } - // We clean it up as history passes - assert_ok!(Staking::payout_stakers( - RuntimeOrigin::signed(1337), - 11, - expected_start_reward_era, - 0 - )); - assert_ok!(Staking::payout_stakers( - RuntimeOrigin::signed(1337), - 11, - expected_last_reward_era, - 0 - )); - assert_eq!( - Staking::ledger(&10), - Some(StakingLedger { - stash: 11, - total: 1000, - active: 1000, - unlocking: Default::default(), - legacy_claimed_rewards: bounded_vec![ - expected_start_reward_era, - expected_last_reward_era - ] - }) - ); + // verify we clean up history as we go + for era in 0..15 { + assert_eq!(Staking::claimed_rewards(era, &11), Vec::::new()); + } + + // verify only page 0 is marked as claimed + assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, first_claimable_reward_era, 0)); + assert_eq!(Staking::claimed_rewards(first_claimable_reward_era, &11), vec![0]); + + // verify page 0 and 1 are marked as claimed + assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, first_claimable_reward_era, 1)); + assert_eq!(Staking::claimed_rewards(first_claimable_reward_era, &11), vec![0, 1]); + + // verify only page 0 is marked as claimed + assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, last_reward_era, 0)); + assert_eq!(Staking::claimed_rewards(last_reward_era, &11), vec![0]); + + // verify page 0 and 1 are marked as claimed + assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, last_reward_era, 1)); + assert_eq!(Staking::claimed_rewards(last_reward_era, &11), vec![0, 1]); // Out of order claims works. assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, 69, 0)); - assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, 23, 0)); + assert_eq!(Staking::claimed_rewards(69, &11), vec![0]); + assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, 23, 1)); + assert_eq!(Staking::claimed_rewards(23, &11), vec![1]); assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, 42, 0)); - assert_eq!( - Staking::ledger(&10), - Some(StakingLedger { - stash: 11, - total: 1000, - active: 1000, - unlocking: Default::default(), - legacy_claimed_rewards: bounded_vec![ - expected_start_reward_era, - 23, - 42, - 69, - expected_last_reward_era - ] - }) - ); + assert_eq!(Staking::claimed_rewards(42, &11), vec![0]); }); } From 42429e91a2ff76f7a08877d5edd8cece4bd7cf46 Mon Sep 17 00:00:00 2001 From: Ankan Date: Sun, 22 Jan 2023 00:45:47 +0100 Subject: [PATCH 036/162] cargo fmt --- frame/staking/src/lib.rs | 7 ++++++- frame/staking/src/mock.rs | 8 ++++++-- frame/staking/src/pallet/impls.rs | 5 ++++- frame/staking/src/pallet/mod.rs | 13 +++++++------ 4 files changed, 23 insertions(+), 10 deletions(-) diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index cff9f7873e4f3..1a18df980fbbc 100644 --- a/frame/staking/src/lib.rs +++ b/frame/staking/src/lib.rs @@ -812,7 +812,12 @@ pub struct ExposureOverview { impl Default for ExposureOverview { fn default() -> Self { - Self { total: Default::default(), own: Default::default(), nominator_count: Default::default(), page_count: Default::default() } + Self { + total: Default::default(), + own: Default::default(), + nominator_count: Default::default(), + page_count: Default::default(), + } } } diff --git a/frame/staking/src/mock.rs b/frame/staking/src/mock.rs index e90549d81c1b7..edf8d29645a55 100644 --- a/frame/staking/src/mock.rs +++ b/frame/staking/src/mock.rs @@ -761,9 +761,13 @@ pub(crate) fn make_all_reward_payment(era: EraIndex) { for validator_controller in validators_with_reward.iter().filter_map(Staking::bonded) { let ledger = >::get(&validator_controller).unwrap(); for page in 0..EraInfo::::get_page_count(era, &ledger.stash) { - assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), ledger.stash, era, page)); + assert_ok!(Staking::payout_stakers( + RuntimeOrigin::signed(1337), + ledger.stash, + era, + page + )); } - } } diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index cf063bd05fcd6..150545c827fdf 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -149,7 +149,10 @@ impl Pallet { .with_weight(T::WeightInfo::payout_stakers_alive_staked(0)) ); - ensure!(page < EraInfo::::get_page_count(era, &validator_stash), Error::::InvalidPage); + ensure!( + page < EraInfo::::get_page_count(era, &validator_stash), + Error::::InvalidPage + ); // Note: if era has no reward to be claimed, era may be future. better not to update // `ledger.legacy_claimed_rewards` in this case. diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index 2e6bdbb6b6adc..1f5342a60fd8f 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -622,15 +622,16 @@ pub mod pallet { pub type CurrentPlannedSession = StorageValue<_, SessionIndex, ValueQuery>; /// Wrapper struct for Era related information. It is not a pure encapsulation as these storage - /// items can be accessed directly but nevertheless recommended to use `EraInfo` for accessing - /// the following: (1) `ErasStakers`, (2) `ClaimedRewards`, (3) `ErasStakersClipped`, + /// items can be accessed directly but nevertheless, its recommended to use `EraInfo` for + /// accessing the following: (1) `ErasStakers`, (2) `ClaimedRewards`, (3) `ErasStakersClipped`, /// (4) `ErasStakersPaged`, (5) `ErasTotalStake`. - // TODO(ank4n): docs, tests and add more methods to `EraInfo` for the supported storage items. + // TODO(Ank4n): add all era related storage items in this struct pub(crate) struct EraInfo(sp_std::marker::PhantomData); impl EraInfo { - /// Temporary function which looks at both (1) `T::StakingLedger` for legacy non-paged - /// rewards, and (2) `T::ClaimedRewards` for paged rewards. This can be removed once - /// `$HistoryDepth` eras have passed and none of the older non-paged rewards are claimable. + /// Temporary function which looks at both (1) passed param `T::StakingLedger` for legacy + /// non-paged rewards, and (2) `T::ClaimedRewards` for paged rewards. This function can be + /// removed once `$HistoryDepth` eras have passed and none of the older non-paged rewards + /// are relevant/claimable. // TODO: Cleanup tracking issue: #13034 pub(crate) fn is_rewards_claimed_temp( era: EraIndex, From 4260bca18f99529590e95105881248c1dc0efe2b Mon Sep 17 00:00:00 2001 From: Ankan Date: Sun, 22 Jan 2023 02:32:49 +0100 Subject: [PATCH 037/162] add more tests --- frame/staking/src/pallet/impls.rs | 2 +- frame/staking/src/tests.rs | 199 +++++++++++++++++++++++++++++- 2 files changed, 198 insertions(+), 3 deletions(-) diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index 150545c827fdf..dbaa00a8780ca 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -151,7 +151,7 @@ impl Pallet { ensure!( page < EraInfo::::get_page_count(era, &validator_stash), - Error::::InvalidPage + Error::::InvalidPage.with_weight(T::WeightInfo::payout_stakers_alive_staked(0)) ); // Note: if era has no reward to be claimed, era may be future. better not to update diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index 7539a350270dd..81c5af9f90365 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -25,6 +25,7 @@ use frame_support::{ pallet_prelude::*, traits::{Currency, Get, ReservableCurrency}, }; + use mock::*; use pallet_balances::Error as BalancesError; use sp_runtime::{ @@ -3884,11 +3885,21 @@ fn test_multi_page_payout_stakers() { } // verify only page 0 is marked as claimed - assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, first_claimable_reward_era, 0)); + assert_ok!(Staking::payout_stakers( + RuntimeOrigin::signed(1337), + 11, + first_claimable_reward_era, + 0 + )); assert_eq!(Staking::claimed_rewards(first_claimable_reward_era, &11), vec![0]); // verify page 0 and 1 are marked as claimed - assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, first_claimable_reward_era, 1)); + assert_ok!(Staking::payout_stakers( + RuntimeOrigin::signed(1337), + 11, + first_claimable_reward_era, + 1 + )); assert_eq!(Staking::claimed_rewards(first_claimable_reward_era, &11), vec![0, 1]); // verify only page 0 is marked as claimed @@ -5757,6 +5768,190 @@ fn should_retain_era_info_only_upto_history_depth() { }); } +#[test] +fn test_legacy_claimed_rewards_is_checked_at_reward_payout() { + ExtBuilder::default().has_stakers(false).build_and_execute(|| { + // Create a validator: + bond_validator(11, 10, 1000); + + // reward validator for next 2 eras + mock::start_active_era(1); + Pallet::::reward_by_ids(vec![(11, 1)]); + mock::start_active_era(2); + Pallet::::reward_by_ids(vec![(11, 1)]); + mock::start_active_era(3); + + //verify rewards are not claimed + assert_eq!( + EraInfo::::is_rewards_claimed_temp( + 1, + Staking::ledger(10).as_ref().unwrap(), + &11, + 0 + ), + false + ); + assert_eq!( + EraInfo::::is_rewards_claimed_temp( + 2, + Staking::ledger(10).as_ref().unwrap(), + &11, + 0 + ), + false + ); + + // assume reward claim for era 1 was stored in legacy storage + Ledger::::insert( + 10, + StakingLedger { + stash: 11, + total: 1000, + active: 1000, + unlocking: Default::default(), + legacy_claimed_rewards: bounded_vec![1], + }, + ); + + // verify rewards for era 1 cannot be claimed + assert_noop!( + Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, 1, 0), + Error::::AlreadyClaimed + .with_weight(::WeightInfo::payout_stakers_alive_staked(0)), + ); + assert_eq!( + EraInfo::::is_rewards_claimed_temp( + 1, + Staking::ledger(10).as_ref().unwrap(), + &11, + 0 + ), + true + ); + + // verify rewards for era 2 can be claimed + assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, 2, 0)); + assert_eq!( + EraInfo::::is_rewards_claimed_temp( + 2, + Staking::ledger(10).as_ref().unwrap(), + &11, + 0 + ), + true + ); + // but the new claimed rewards for era 2 is not stored in legacy storage + assert_eq!( + Ledger::::get(10).unwrap(), + StakingLedger { + stash: 11, + total: 1000, + active: 1000, + unlocking: Default::default(), + legacy_claimed_rewards: bounded_vec![1], + }, + ); + // instead it is kept in `ClaimedRewards` + assert_eq!(ClaimedRewards::::get(2, 11), vec![0]); + }); +} + +#[test] +fn test_validator_exposure_is_backward_compatible_with_non_paged_rewards_payout() { + ExtBuilder::default().has_stakers(false).build_and_execute(|| { + // case 1: exposure exist in clipped. + // set page cap to 10 + MaxNominatorRewardedPerValidator::set(10); + bond_validator(11, 10, 1000); + let mut expected_individual_exposures: Vec> = vec![]; + let mut total_exposure: Balance = 0; + // 1st exposure page + for i in 0..10 { + let who = 1000 + i; + let value = 1000 + i as Balance; + bond_nominator(who, 100 + i, value, vec![11]); + expected_individual_exposures.push(IndividualExposure { who, value }); + total_exposure += value; + } + + for i in 10..15 { + let who = 1000 + i; + let value = 1000 + i as Balance; + bond_nominator(who, 100 + i, value, vec![11]); + expected_individual_exposures.push(IndividualExposure { who, value }); + total_exposure += value; + } + + mock::start_active_era(1); + // reward validator for current era + Pallet::::reward_by_ids(vec![(11, 1)]); + + // start new era + mock::start_active_era(2); + // verify exposure for era 1 is stored in paged storage, that each exposure is stored in + // one and only one page, and no exposure is repeated. + let actual_exposure_page_0 = ErasStakersPaged::::get(1, (11, 0)).unwrap(); + let actual_exposure_page_1 = ErasStakersPaged::::get(1, (11, 1)).unwrap(); + expected_individual_exposures.iter().for_each(|exposure| { + assert!( + actual_exposure_page_0.others.contains(exposure) || + actual_exposure_page_1.others.contains(exposure) + ); + }); + assert_eq!( + expected_individual_exposures.len(), + actual_exposure_page_0.others.len() + actual_exposure_page_1.others.len() + ); + // verify `EraInfo` returns page from paged storage + assert_eq!( + EraInfo::::get_validator_exposure(1, &11, 0).others, + actual_exposure_page_0.others + ); + assert_eq!( + EraInfo::::get_validator_exposure(1, &11, 1).others, + actual_exposure_page_1.others + ); + assert_eq!(EraInfo::::get_page_count(1, &11), 2); + + // case 2: exposure exist in clipped storage. + // delete paged storage and add exposure to clipped storage + >::remove(1, (11, 0)); + >::remove(1, (11, 1)); + >::remove(1, 11); + let mut clipped_exposure = expected_individual_exposures.clone(); + clipped_exposure.sort_by(|a, b| b.who.cmp(&a.who)); + clipped_exposure.truncate(10); + >::insert(1, 11, Exposure { + total: total_exposure, + own: 1000, + others: clipped_exposure.clone(), + }); + + // verify `EraInfo` returns exposure from clipped storage + assert!(matches!( + EraInfo::::get_validator_exposure(1, &11, 0), + Exposure { + own, + others, + .. + } if others == clipped_exposure && own == 1000)); + + // for pages other than 0, clipped storage returns empty exposure + assert_eq!( + EraInfo::::get_validator_exposure(1, &11, 1), + Default::default() + ); + // page size is 1 for clipped storage + assert_eq!(EraInfo::::get_page_count(1, &11), 1); + + // payout for page 0 works + assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, 0, 0)); + // payout for page 1 fails + assert_noop!(Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, 0, 1), + Error::::InvalidPage.with_weight(::WeightInfo::payout_stakers_alive_staked(0))); + }); +} + mod staking_interface { use frame_support::storage::with_storage_layer; use sp_staking::StakingInterface; From eb0709ba8c0a4b5dff5ce9a7c024a513ab7f5e30 Mon Sep 17 00:00:00 2001 From: Ankan Date: Sun, 22 Jan 2023 02:33:13 +0100 Subject: [PATCH 038/162] cargo fmt --- frame/staking/src/tests.rs | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index 81c5af9f90365..2fc2e7838f45c 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -5921,11 +5921,11 @@ fn test_validator_exposure_is_backward_compatible_with_non_paged_rewards_payout( let mut clipped_exposure = expected_individual_exposures.clone(); clipped_exposure.sort_by(|a, b| b.who.cmp(&a.who)); clipped_exposure.truncate(10); - >::insert(1, 11, Exposure { - total: total_exposure, - own: 1000, - others: clipped_exposure.clone(), - }); + >::insert( + 1, + 11, + Exposure { total: total_exposure, own: 1000, others: clipped_exposure.clone() }, + ); // verify `EraInfo` returns exposure from clipped storage assert!(matches!( @@ -5937,18 +5937,18 @@ fn test_validator_exposure_is_backward_compatible_with_non_paged_rewards_payout( } if others == clipped_exposure && own == 1000)); // for pages other than 0, clipped storage returns empty exposure - assert_eq!( - EraInfo::::get_validator_exposure(1, &11, 1), - Default::default() - ); + assert_eq!(EraInfo::::get_validator_exposure(1, &11, 1), Default::default()); // page size is 1 for clipped storage assert_eq!(EraInfo::::get_page_count(1, &11), 1); // payout for page 0 works assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, 0, 0)); // payout for page 1 fails - assert_noop!(Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, 0, 1), - Error::::InvalidPage.with_weight(::WeightInfo::payout_stakers_alive_staked(0))); + assert_noop!( + Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, 0, 1), + Error::::InvalidPage + .with_weight(::WeightInfo::payout_stakers_alive_staked(0)) + ); }); } From ec6ae58baa874ea1e4987d4bc1c026f76a3b39b7 Mon Sep 17 00:00:00 2001 From: Ankan Date: Mon, 23 Jan 2023 12:43:01 +0100 Subject: [PATCH 039/162] fix benchmarks --- frame/staking/src/benchmarking.rs | 6 +++--- frame/staking/src/lib.rs | 5 ++--- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/frame/staking/src/benchmarking.rs b/frame/staking/src/benchmarking.rs index f97c29b61ba75..49071ef4e8875 100644 --- a/frame/staking/src/benchmarking.rs +++ b/frame/staking/src/benchmarking.rs @@ -565,7 +565,7 @@ benchmarks! { let balance = T::Currency::free_balance(controller); ensure!(balance.is_zero(), "Controller has balance, but should be dead."); } - }: payout_stakers(RawOrigin::Signed(caller), validator, current_era) + }: payout_stakers(RawOrigin::Signed(caller), validator, current_era, 0) verify { let balance_after = T::Currency::free_balance(&validator_controller); ensure!( @@ -598,7 +598,7 @@ benchmarks! { let balance = T::Currency::free_balance(stash); nominator_balances_before.push(balance); } - }: payout_stakers(RawOrigin::Signed(caller), validator.clone(), current_era) + }: payout_stakers(RawOrigin::Signed(caller), validator.clone(), current_era, 0) verify { let balance_after = T::Currency::free_balance(&validator); ensure!( @@ -754,7 +754,7 @@ benchmarks! { let caller: T::AccountId = whitelisted_caller(); let origin = RawOrigin::Signed(caller); let calls: Vec<_> = payout_calls_arg.iter().map(|arg| - Call::::payout_stakers { validator_stash: arg.0.clone(), era: arg.1 }.encode() + Call::::payout_stakers { validator_stash: arg.0.clone(), era: arg.1, page: 0 }.encode() ).collect(); }: { for call in calls { diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index 1a18df980fbbc..61d51cfe5d870 100644 --- a/frame/staking/src/lib.rs +++ b/frame/staking/src/lib.rs @@ -318,7 +318,6 @@ use sp_staking::{ use sp_std::{collections::btree_map::BTreeMap, prelude::*}; pub use weights::WeightInfo; -use frame_support::traits::ConstU32; pub use pallet::{pallet::*, *}; pub(crate) const LOG_TARGET: &str = "runtime::staking"; @@ -1044,6 +1043,6 @@ pub struct TestBenchmarkingConfig; #[cfg(feature = "std")] impl BenchmarkingConfig for TestBenchmarkingConfig { - type MaxValidators = ConstU32<100>; - type MaxNominators = ConstU32<100>; + type MaxValidators = frame_support::traits::ConstU32<100>; + type MaxNominators = frame_support::traits::ConstU32<100>; } From 03c53a0f3fcdaf2b5a8bf7e518135822c2e64c63 Mon Sep 17 00:00:00 2001 From: Ankan Date: Mon, 23 Jan 2023 13:05:30 +0100 Subject: [PATCH 040/162] fix clippy suggestion --- frame/staking/src/pallet/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index 1f5342a60fd8f..13ab1f32a99c1 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -648,7 +648,7 @@ pub mod pallet { /// This is only used for paged rewards. Once older non-paged rewards are no longer /// relevant, `is_rewards_claimed_temp` can be removed and this function can be made public. fn is_rewards_claimed(era: EraIndex, validator: &T::AccountId, page: PageIndex) -> bool { - ClaimedRewards::::get(era, validator).iter().find(|&&p| page == p).is_some() + ClaimedRewards::::get(era, validator).iter().any(|&p| page == p) } /// Get exposure info for a validator at a given era and page. From 554bb7cb1a3e8c2ac9a957ef51e27e5a80e3d286 Mon Sep 17 00:00:00 2001 From: command-bot <> Date: Mon, 23 Jan 2023 17:03:59 +0000 Subject: [PATCH 041/162] ".git/.scripts/commands/bench/bench.sh" pallet dev pallet_staking --- frame/staking/src/weights.rs | 420 ++++++++++++++++++----------------- 1 file changed, 216 insertions(+), 204 deletions(-) diff --git a/frame/staking/src/weights.rs b/frame/staking/src/weights.rs index 9c283f5a065e3..dc62a86201be6 100644 --- a/frame/staking/src/weights.rs +++ b/frame/staking/src/weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) 2023 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,7 +18,7 @@ //! Autogenerated weights for pallet_staking //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-12-25, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-01-23, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 @@ -85,13 +85,12 @@ pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { // Storage: Staking Bonded (r:1 w:1) // Storage: Staking Ledger (r:1 w:1) - // Storage: Staking CurrentEra (r:1 w:0) // Storage: Balances Locks (r:1 w:1) // Storage: Staking Payee (r:0 w:1) fn bond() -> Weight { - // Minimum execution time: 54_884 nanoseconds. - Weight::from_ref_time(55_487_000) - .saturating_add(T::DbWeight::get().reads(4)) + // Minimum execution time: 51_611 nanoseconds. + Weight::from_ref_time(52_566_000) + .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(4)) } // Storage: Staking Bonded (r:1 w:0) @@ -100,8 +99,8 @@ impl WeightInfo for SubstrateWeight { // Storage: VoterList ListNodes (r:3 w:3) // Storage: VoterList ListBags (r:2 w:2) fn bond_extra() -> Weight { - // Minimum execution time: 95_115 nanoseconds. - Weight::from_ref_time(96_213_000) + // Minimum execution time: 92_297 nanoseconds. + Weight::from_ref_time(93_016_000) .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(7)) } @@ -115,8 +114,8 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking Bonded (r:1 w:0) // Storage: VoterList ListBags (r:2 w:2) fn unbond() -> Weight { - // Minimum execution time: 102_031 nanoseconds. - Weight::from_ref_time(102_842_000) + // Minimum execution time: 98_447 nanoseconds. + Weight::from_ref_time(99_317_000) .saturating_add(T::DbWeight::get().reads(12)) .saturating_add(T::DbWeight::get().writes(8)) } @@ -126,10 +125,10 @@ impl WeightInfo for SubstrateWeight { // Storage: System Account (r:1 w:1) /// The range of component `s` is `[0, 100]`. fn withdraw_unbonded_update(s: u32, ) -> Weight { - // Minimum execution time: 46_569 nanoseconds. - Weight::from_ref_time(48_034_493) - // Standard Error: 654 - .saturating_add(Weight::from_ref_time(63_628).saturating_mul(s.into())) + // Minimum execution time: 45_142 nanoseconds. + Weight::from_ref_time(46_003_517) + // Standard Error: 564 + .saturating_add(Weight::from_ref_time(60_400).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -149,10 +148,10 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking SpanSlash (r:0 w:2) /// The range of component `s` is `[0, 100]`. fn withdraw_unbonded_kill(s: u32, ) -> Weight { - // Minimum execution time: 90_154 nanoseconds. - Weight::from_ref_time(95_725_631) - // Standard Error: 2_491 - .saturating_add(Weight::from_ref_time(1_110_795).saturating_mul(s.into())) + // Minimum execution time: 86_176 nanoseconds. + Weight::from_ref_time(91_591_693) + // Standard Error: 2_162 + .saturating_add(Weight::from_ref_time(1_089_160).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(13)) .saturating_add(T::DbWeight::get().writes(12)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) @@ -169,8 +168,8 @@ impl WeightInfo for SubstrateWeight { // Storage: VoterList CounterForListNodes (r:1 w:1) // Storage: Staking CounterForValidators (r:1 w:1) fn validate() -> Weight { - // Minimum execution time: 67_978 nanoseconds. - Weight::from_ref_time(69_153_000) + // Minimum execution time: 65_754 nanoseconds. + Weight::from_ref_time(66_793_000) .saturating_add(T::DbWeight::get().reads(11)) .saturating_add(T::DbWeight::get().writes(5)) } @@ -178,10 +177,10 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking Nominators (r:1 w:1) /// The range of component `k` is `[1, 128]`. fn kick(k: u32, ) -> Weight { - // Minimum execution time: 45_328 nanoseconds. - Weight::from_ref_time(47_719_103) - // Standard Error: 14_458 - .saturating_add(Weight::from_ref_time(6_999_252).saturating_mul(k.into())) + // Minimum execution time: 44_020 nanoseconds. + Weight::from_ref_time(41_692_773) + // Standard Error: 12_148 + .saturating_add(Weight::from_ref_time(7_092_259).saturating_mul(k.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(k.into()))) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(k.into()))) @@ -199,10 +198,10 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking CounterForNominators (r:1 w:1) /// The range of component `n` is `[1, 16]`. fn nominate(n: u32, ) -> Weight { - // Minimum execution time: 74_650 nanoseconds. - Weight::from_ref_time(74_350_075) - // Standard Error: 10_527 - .saturating_add(Weight::from_ref_time(2_878_737).saturating_mul(n.into())) + // Minimum execution time: 72_131 nanoseconds. + Weight::from_ref_time(71_703_530) + // Standard Error: 6_947 + .saturating_add(Weight::from_ref_time(2_757_165).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(12)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(6)) @@ -215,58 +214,58 @@ impl WeightInfo for SubstrateWeight { // Storage: VoterList ListBags (r:1 w:1) // Storage: VoterList CounterForListNodes (r:1 w:1) fn chill() -> Weight { - // Minimum execution time: 67_790 nanoseconds. - Weight::from_ref_time(68_738_000) + // Minimum execution time: 66_151 nanoseconds. + Weight::from_ref_time(66_596_000) .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(6)) } // Storage: Staking Ledger (r:1 w:0) // Storage: Staking Payee (r:0 w:1) fn set_payee() -> Weight { - // Minimum execution time: 19_237 nanoseconds. - Weight::from_ref_time(19_534_000) + // Minimum execution time: 17_305 nanoseconds. + Weight::from_ref_time(17_506_000) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } // Storage: Staking Bonded (r:1 w:1) // Storage: Staking Ledger (r:2 w:2) fn set_controller() -> Weight { - // Minimum execution time: 27_288 nanoseconds. - Weight::from_ref_time(27_667_000) + // Minimum execution time: 24_482 nanoseconds. + Weight::from_ref_time(25_101_000) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(3)) } // Storage: Staking ValidatorCount (r:0 w:1) fn set_validator_count() -> Weight { - // Minimum execution time: 5_155 nanoseconds. - Weight::from_ref_time(5_464_000) + // Minimum execution time: 5_100 nanoseconds. + Weight::from_ref_time(5_274_000) .saturating_add(T::DbWeight::get().writes(1)) } // Storage: Staking ForceEra (r:0 w:1) fn force_no_eras() -> Weight { - // Minimum execution time: 5_405 nanoseconds. - Weight::from_ref_time(5_670_000) + // Minimum execution time: 19_788 nanoseconds. + Weight::from_ref_time(20_313_000) .saturating_add(T::DbWeight::get().writes(1)) } // Storage: Staking ForceEra (r:0 w:1) fn force_new_era() -> Weight { - // Minimum execution time: 5_459 nanoseconds. - Weight::from_ref_time(5_616_000) + // Minimum execution time: 19_499 nanoseconds. + Weight::from_ref_time(19_987_000) .saturating_add(T::DbWeight::get().writes(1)) } // Storage: Staking ForceEra (r:0 w:1) fn force_new_era_always() -> Weight { - // Minimum execution time: 5_476 nanoseconds. - Weight::from_ref_time(5_692_000) + // Minimum execution time: 19_846 nanoseconds. + Weight::from_ref_time(20_127_000) .saturating_add(T::DbWeight::get().writes(1)) } // Storage: Staking Invulnerables (r:0 w:1) /// The range of component `v` is `[0, 1000]`. fn set_invulnerables(v: u32, ) -> Weight { - // Minimum execution time: 5_544 nanoseconds. - Weight::from_ref_time(6_513_190) - // Standard Error: 76 - .saturating_add(Weight::from_ref_time(9_975).saturating_mul(v.into())) + // Minimum execution time: 5_301 nanoseconds. + Weight::from_ref_time(6_147_935) + // Standard Error: 32 + .saturating_add(Weight::from_ref_time(10_076).saturating_mul(v.into())) .saturating_add(T::DbWeight::get().writes(1)) } // Storage: Staking Bonded (r:1 w:1) @@ -284,10 +283,10 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking SpanSlash (r:0 w:2) /// The range of component `s` is `[0, 100]`. fn force_unstake(s: u32, ) -> Weight { - // Minimum execution time: 82_414 nanoseconds. - Weight::from_ref_time(88_511_246) - // Standard Error: 2_622 - .saturating_add(Weight::from_ref_time(1_131_814).saturating_mul(s.into())) + // Minimum execution time: 79_381 nanoseconds. + Weight::from_ref_time(85_216_285) + // Standard Error: 2_681 + .saturating_add(Weight::from_ref_time(1_100_353).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(11)) .saturating_add(T::DbWeight::get().writes(12)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) @@ -295,17 +294,20 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking UnappliedSlashes (r:1 w:1) /// The range of component `s` is `[1, 1000]`. fn cancel_deferred_slash(s: u32, ) -> Weight { - // Minimum execution time: 94_197 nanoseconds. - Weight::from_ref_time(903_418_326) - // Standard Error: 59_354 - .saturating_add(Weight::from_ref_time(4_948_354).saturating_mul(s.into())) + // Minimum execution time: 92_049 nanoseconds. + Weight::from_ref_time(894_164_159) + // Standard Error: 58_104 + .saturating_add(Weight::from_ref_time(4_961_170).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } // Storage: Staking CurrentEra (r:1 w:0) + // Storage: Staking ErasStakersOverview (r:1 w:0) // Storage: Staking ErasValidatorReward (r:1 w:0) // Storage: Staking Bonded (r:1 w:0) // Storage: Staking Ledger (r:1 w:1) + // Storage: Staking ClaimedRewards (r:1 w:1) + // Storage: Staking ErasStakersPaged (r:1 w:0) // Storage: Staking ErasStakersClipped (r:1 w:0) // Storage: Staking ErasRewardPoints (r:1 w:0) // Storage: Staking ErasValidatorPrefs (r:1 w:0) @@ -313,19 +315,22 @@ impl WeightInfo for SubstrateWeight { // Storage: System Account (r:1 w:1) /// The range of component `n` is `[0, 256]`. fn payout_stakers_dead_controller(n: u32, ) -> Weight { - // Minimum execution time: 133_065 nanoseconds. - Weight::from_ref_time(197_555_906) - // Standard Error: 19_561 - .saturating_add(Weight::from_ref_time(22_683_426).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(9)) + // Minimum execution time: 134_548 nanoseconds. + Weight::from_ref_time(195_909_318) + // Standard Error: 17_825 + .saturating_add(Weight::from_ref_time(22_179_182).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(11)) .saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(n.into()))) - .saturating_add(T::DbWeight::get().writes(2)) + .saturating_add(T::DbWeight::get().writes(3)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(n.into()))) } // Storage: Staking CurrentEra (r:1 w:0) + // Storage: Staking ErasStakersOverview (r:1 w:0) // Storage: Staking ErasValidatorReward (r:1 w:0) // Storage: Staking Bonded (r:1 w:0) // Storage: Staking Ledger (r:1 w:1) + // Storage: Staking ClaimedRewards (r:1 w:1) + // Storage: Staking ErasStakersPaged (r:1 w:0) // Storage: Staking ErasStakersClipped (r:1 w:0) // Storage: Staking ErasRewardPoints (r:1 w:0) // Storage: Staking ErasValidatorPrefs (r:1 w:0) @@ -334,13 +339,13 @@ impl WeightInfo for SubstrateWeight { // Storage: Balances Locks (r:1 w:1) /// The range of component `n` is `[0, 256]`. fn payout_stakers_alive_staked(n: u32, ) -> Weight { - // Minimum execution time: 164_719 nanoseconds. - Weight::from_ref_time(226_304_276) - // Standard Error: 31_675 - .saturating_add(Weight::from_ref_time(32_622_427).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(10)) + // Minimum execution time: 167_574 nanoseconds. + Weight::from_ref_time(232_044_473) + // Standard Error: 25_865 + .saturating_add(Weight::from_ref_time(31_272_789).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(12)) .saturating_add(T::DbWeight::get().reads((5_u64).saturating_mul(n.into()))) - .saturating_add(T::DbWeight::get().writes(3)) + .saturating_add(T::DbWeight::get().writes(4)) .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(n.into()))) } // Storage: Staking Ledger (r:1 w:1) @@ -351,10 +356,10 @@ impl WeightInfo for SubstrateWeight { // Storage: VoterList ListBags (r:2 w:2) /// The range of component `l` is `[1, 32]`. fn rebond(l: u32, ) -> Weight { - // Minimum execution time: 95_631 nanoseconds. - Weight::from_ref_time(96_861_556) - // Standard Error: 2_114 - .saturating_add(Weight::from_ref_time(37_543).saturating_mul(l.into())) + // Minimum execution time: 91_739 nanoseconds. + Weight::from_ref_time(93_123_333) + // Standard Error: 3_580 + .saturating_add(Weight::from_ref_time(69_425).saturating_mul(l.into())) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(8)) } @@ -373,10 +378,10 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking SpanSlash (r:0 w:1) /// The range of component `s` is `[1, 100]`. fn reap_stash(s: u32, ) -> Weight { - // Minimum execution time: 95_251 nanoseconds. - Weight::from_ref_time(97_818_954) - // Standard Error: 2_356 - .saturating_add(Weight::from_ref_time(1_104_695).saturating_mul(s.into())) + // Minimum execution time: 90_792 nanoseconds. + Weight::from_ref_time(93_893_087) + // Standard Error: 4_158 + .saturating_add(Weight::from_ref_time(1_084_858).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(12)) .saturating_add(T::DbWeight::get().writes(12)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) @@ -392,8 +397,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking ValidatorCount (r:1 w:0) // Storage: Staking MinimumValidatorCount (r:1 w:0) // Storage: Staking CurrentEra (r:1 w:1) - // Storage: Staking ErasStakersClipped (r:0 w:1) // Storage: Staking ErasValidatorPrefs (r:0 w:1) + // Storage: Staking ErasStakersPaged (r:0 w:1) + // Storage: Staking ErasStakersOverview (r:0 w:1) // Storage: Staking ErasStakers (r:0 w:1) // Storage: Staking ErasTotalStake (r:0 w:1) // Storage: Staking ErasStartSessionIndex (r:0 w:1) @@ -401,17 +407,17 @@ impl WeightInfo for SubstrateWeight { /// The range of component `v` is `[1, 10]`. /// The range of component `n` is `[0, 100]`. fn new_era(v: u32, n: u32, ) -> Weight { - // Minimum execution time: 512_923 nanoseconds. - Weight::from_ref_time(514_740_000) - // Standard Error: 1_790_238 - .saturating_add(Weight::from_ref_time(59_320_539).saturating_mul(v.into())) - // Standard Error: 178_387 - .saturating_add(Weight::from_ref_time(13_902_705).saturating_mul(n.into())) + // Minimum execution time: 506_210 nanoseconds. + Weight::from_ref_time(508_476_000) + // Standard Error: 1_787_036 + .saturating_add(Weight::from_ref_time(60_417_557).saturating_mul(v.into())) + // Standard Error: 178_068 + .saturating_add(Weight::from_ref_time(13_499_037).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(206)) .saturating_add(T::DbWeight::get().reads((5_u64).saturating_mul(v.into()))) .saturating_add(T::DbWeight::get().reads((4_u64).saturating_mul(n.into()))) - .saturating_add(T::DbWeight::get().writes(4)) - .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(v.into()))) + .saturating_add(T::DbWeight::get().writes(3)) + .saturating_add(T::DbWeight::get().writes((4_u64).saturating_mul(v.into()))) } // Storage: VoterList CounterForListNodes (r:1 w:0) // Storage: VoterList ListBags (r:200 w:0) @@ -424,12 +430,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `v` is `[500, 1000]`. /// The range of component `n` is `[500, 1000]`. fn get_npos_voters(v: u32, n: u32, ) -> Weight { - // Minimum execution time: 24_913_316 nanoseconds. - Weight::from_ref_time(25_053_596_000) - // Standard Error: 324_610 - .saturating_add(Weight::from_ref_time(3_454_859).saturating_mul(v.into())) - // Standard Error: 324_610 - .saturating_add(Weight::from_ref_time(3_020_267).saturating_mul(n.into())) + // Minimum execution time: 24_070_794 nanoseconds. + Weight::from_ref_time(24_294_007_000) + // Standard Error: 322_618 + .saturating_add(Weight::from_ref_time(3_570_673).saturating_mul(v.into())) + // Standard Error: 322_618 + .saturating_add(Weight::from_ref_time(2_900_021).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(201)) .saturating_add(T::DbWeight::get().reads((5_u64).saturating_mul(v.into()))) .saturating_add(T::DbWeight::get().reads((4_u64).saturating_mul(n.into()))) @@ -439,10 +445,10 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking Validators (r:501 w:0) /// The range of component `v` is `[500, 1000]`. fn get_npos_targets(v: u32, ) -> Weight { - // Minimum execution time: 4_916_401 nanoseconds. - Weight::from_ref_time(81_160_966) - // Standard Error: 23_829 - .saturating_add(Weight::from_ref_time(9_883_413).saturating_mul(v.into())) + // Minimum execution time: 4_776_351 nanoseconds. + Weight::from_ref_time(4_849_553_000) + // Standard Error: 55_132 + .saturating_add(Weight::from_ref_time(3_604_980).saturating_mul(v.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(v.into()))) } @@ -453,8 +459,8 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking MaxNominatorsCount (r:0 w:1) // Storage: Staking MinNominatorBond (r:0 w:1) fn set_staking_configs_all_set() -> Weight { - // Minimum execution time: 10_937 nanoseconds. - Weight::from_ref_time(11_324_000) + // Minimum execution time: 10_781 nanoseconds. + Weight::from_ref_time(11_034_000) .saturating_add(T::DbWeight::get().writes(6)) } // Storage: Staking MinCommission (r:0 w:1) @@ -464,8 +470,8 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking MaxNominatorsCount (r:0 w:1) // Storage: Staking MinNominatorBond (r:0 w:1) fn set_staking_configs_all_remove() -> Weight { - // Minimum execution time: 9_424 nanoseconds. - Weight::from_ref_time(10_021_000) + // Minimum execution time: 9_418 nanoseconds. + Weight::from_ref_time(10_150_000) .saturating_add(T::DbWeight::get().writes(6)) } // Storage: Staking Ledger (r:1 w:0) @@ -479,23 +485,23 @@ impl WeightInfo for SubstrateWeight { // Storage: VoterList ListBags (r:1 w:1) // Storage: VoterList CounterForListNodes (r:1 w:1) fn chill_other() -> Weight { - // Minimum execution time: 84_495 nanoseconds. - Weight::from_ref_time(85_559_000) + // Minimum execution time: 82_590 nanoseconds. + Weight::from_ref_time(83_718_000) .saturating_add(T::DbWeight::get().reads(11)) .saturating_add(T::DbWeight::get().writes(6)) } // Storage: Staking MinCommission (r:1 w:0) // Storage: Staking Validators (r:1 w:1) fn force_apply_min_commission() -> Weight { - // Minimum execution time: 20_385 nanoseconds. - Weight::from_ref_time(20_824_000) + // Minimum execution time: 19_367 nanoseconds. + Weight::from_ref_time(19_668_000) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } // Storage: Staking MinCommission (r:0 w:1) fn set_min_commission() -> Weight { - // Minimum execution time: 6_995 nanoseconds. - Weight::from_ref_time(7_213_000) + // Minimum execution time: 6_107 nanoseconds. + Weight::from_ref_time(6_449_000) .saturating_add(T::DbWeight::get().writes(1)) } } @@ -504,13 +510,12 @@ impl WeightInfo for SubstrateWeight { impl WeightInfo for () { // Storage: Staking Bonded (r:1 w:1) // Storage: Staking Ledger (r:1 w:1) - // Storage: Staking CurrentEra (r:1 w:0) // Storage: Balances Locks (r:1 w:1) // Storage: Staking Payee (r:0 w:1) fn bond() -> Weight { - // Minimum execution time: 54_884 nanoseconds. - Weight::from_ref_time(55_487_000) - .saturating_add(RocksDbWeight::get().reads(4)) + // Minimum execution time: 51_611 nanoseconds. + Weight::from_ref_time(52_566_000) + .saturating_add(RocksDbWeight::get().reads(3)) .saturating_add(RocksDbWeight::get().writes(4)) } // Storage: Staking Bonded (r:1 w:0) @@ -519,8 +524,8 @@ impl WeightInfo for () { // Storage: VoterList ListNodes (r:3 w:3) // Storage: VoterList ListBags (r:2 w:2) fn bond_extra() -> Weight { - // Minimum execution time: 95_115 nanoseconds. - Weight::from_ref_time(96_213_000) + // Minimum execution time: 92_297 nanoseconds. + Weight::from_ref_time(93_016_000) .saturating_add(RocksDbWeight::get().reads(8)) .saturating_add(RocksDbWeight::get().writes(7)) } @@ -534,8 +539,8 @@ impl WeightInfo for () { // Storage: Staking Bonded (r:1 w:0) // Storage: VoterList ListBags (r:2 w:2) fn unbond() -> Weight { - // Minimum execution time: 102_031 nanoseconds. - Weight::from_ref_time(102_842_000) + // Minimum execution time: 98_447 nanoseconds. + Weight::from_ref_time(99_317_000) .saturating_add(RocksDbWeight::get().reads(12)) .saturating_add(RocksDbWeight::get().writes(8)) } @@ -545,10 +550,10 @@ impl WeightInfo for () { // Storage: System Account (r:1 w:1) /// The range of component `s` is `[0, 100]`. fn withdraw_unbonded_update(s: u32, ) -> Weight { - // Minimum execution time: 46_569 nanoseconds. - Weight::from_ref_time(48_034_493) - // Standard Error: 654 - .saturating_add(Weight::from_ref_time(63_628).saturating_mul(s.into())) + // Minimum execution time: 45_142 nanoseconds. + Weight::from_ref_time(46_003_517) + // Standard Error: 564 + .saturating_add(Weight::from_ref_time(60_400).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(4)) .saturating_add(RocksDbWeight::get().writes(3)) } @@ -568,10 +573,10 @@ impl WeightInfo for () { // Storage: Staking SpanSlash (r:0 w:2) /// The range of component `s` is `[0, 100]`. fn withdraw_unbonded_kill(s: u32, ) -> Weight { - // Minimum execution time: 90_154 nanoseconds. - Weight::from_ref_time(95_725_631) - // Standard Error: 2_491 - .saturating_add(Weight::from_ref_time(1_110_795).saturating_mul(s.into())) + // Minimum execution time: 86_176 nanoseconds. + Weight::from_ref_time(91_591_693) + // Standard Error: 2_162 + .saturating_add(Weight::from_ref_time(1_089_160).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(13)) .saturating_add(RocksDbWeight::get().writes(12)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(s.into()))) @@ -588,8 +593,8 @@ impl WeightInfo for () { // Storage: VoterList CounterForListNodes (r:1 w:1) // Storage: Staking CounterForValidators (r:1 w:1) fn validate() -> Weight { - // Minimum execution time: 67_978 nanoseconds. - Weight::from_ref_time(69_153_000) + // Minimum execution time: 65_754 nanoseconds. + Weight::from_ref_time(66_793_000) .saturating_add(RocksDbWeight::get().reads(11)) .saturating_add(RocksDbWeight::get().writes(5)) } @@ -597,10 +602,10 @@ impl WeightInfo for () { // Storage: Staking Nominators (r:1 w:1) /// The range of component `k` is `[1, 128]`. fn kick(k: u32, ) -> Weight { - // Minimum execution time: 45_328 nanoseconds. - Weight::from_ref_time(47_719_103) - // Standard Error: 14_458 - .saturating_add(Weight::from_ref_time(6_999_252).saturating_mul(k.into())) + // Minimum execution time: 44_020 nanoseconds. + Weight::from_ref_time(41_692_773) + // Standard Error: 12_148 + .saturating_add(Weight::from_ref_time(7_092_259).saturating_mul(k.into())) .saturating_add(RocksDbWeight::get().reads(1)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(k.into()))) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(k.into()))) @@ -618,10 +623,10 @@ impl WeightInfo for () { // Storage: Staking CounterForNominators (r:1 w:1) /// The range of component `n` is `[1, 16]`. fn nominate(n: u32, ) -> Weight { - // Minimum execution time: 74_650 nanoseconds. - Weight::from_ref_time(74_350_075) - // Standard Error: 10_527 - .saturating_add(Weight::from_ref_time(2_878_737).saturating_mul(n.into())) + // Minimum execution time: 72_131 nanoseconds. + Weight::from_ref_time(71_703_530) + // Standard Error: 6_947 + .saturating_add(Weight::from_ref_time(2_757_165).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(12)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes(6)) @@ -634,58 +639,58 @@ impl WeightInfo for () { // Storage: VoterList ListBags (r:1 w:1) // Storage: VoterList CounterForListNodes (r:1 w:1) fn chill() -> Weight { - // Minimum execution time: 67_790 nanoseconds. - Weight::from_ref_time(68_738_000) + // Minimum execution time: 66_151 nanoseconds. + Weight::from_ref_time(66_596_000) .saturating_add(RocksDbWeight::get().reads(8)) .saturating_add(RocksDbWeight::get().writes(6)) } // Storage: Staking Ledger (r:1 w:0) // Storage: Staking Payee (r:0 w:1) fn set_payee() -> Weight { - // Minimum execution time: 19_237 nanoseconds. - Weight::from_ref_time(19_534_000) + // Minimum execution time: 17_305 nanoseconds. + Weight::from_ref_time(17_506_000) .saturating_add(RocksDbWeight::get().reads(1)) .saturating_add(RocksDbWeight::get().writes(1)) } // Storage: Staking Bonded (r:1 w:1) // Storage: Staking Ledger (r:2 w:2) fn set_controller() -> Weight { - // Minimum execution time: 27_288 nanoseconds. - Weight::from_ref_time(27_667_000) + // Minimum execution time: 24_482 nanoseconds. + Weight::from_ref_time(25_101_000) .saturating_add(RocksDbWeight::get().reads(3)) .saturating_add(RocksDbWeight::get().writes(3)) } // Storage: Staking ValidatorCount (r:0 w:1) fn set_validator_count() -> Weight { - // Minimum execution time: 5_155 nanoseconds. - Weight::from_ref_time(5_464_000) + // Minimum execution time: 5_100 nanoseconds. + Weight::from_ref_time(5_274_000) .saturating_add(RocksDbWeight::get().writes(1)) } // Storage: Staking ForceEra (r:0 w:1) fn force_no_eras() -> Weight { - // Minimum execution time: 5_405 nanoseconds. - Weight::from_ref_time(5_670_000) + // Minimum execution time: 19_788 nanoseconds. + Weight::from_ref_time(20_313_000) .saturating_add(RocksDbWeight::get().writes(1)) } // Storage: Staking ForceEra (r:0 w:1) fn force_new_era() -> Weight { - // Minimum execution time: 5_459 nanoseconds. - Weight::from_ref_time(5_616_000) + // Minimum execution time: 19_499 nanoseconds. + Weight::from_ref_time(19_987_000) .saturating_add(RocksDbWeight::get().writes(1)) } // Storage: Staking ForceEra (r:0 w:1) fn force_new_era_always() -> Weight { - // Minimum execution time: 5_476 nanoseconds. - Weight::from_ref_time(5_692_000) + // Minimum execution time: 19_846 nanoseconds. + Weight::from_ref_time(20_127_000) .saturating_add(RocksDbWeight::get().writes(1)) } // Storage: Staking Invulnerables (r:0 w:1) /// The range of component `v` is `[0, 1000]`. fn set_invulnerables(v: u32, ) -> Weight { - // Minimum execution time: 5_544 nanoseconds. - Weight::from_ref_time(6_513_190) - // Standard Error: 76 - .saturating_add(Weight::from_ref_time(9_975).saturating_mul(v.into())) + // Minimum execution time: 5_301 nanoseconds. + Weight::from_ref_time(6_147_935) + // Standard Error: 32 + .saturating_add(Weight::from_ref_time(10_076).saturating_mul(v.into())) .saturating_add(RocksDbWeight::get().writes(1)) } // Storage: Staking Bonded (r:1 w:1) @@ -703,10 +708,10 @@ impl WeightInfo for () { // Storage: Staking SpanSlash (r:0 w:2) /// The range of component `s` is `[0, 100]`. fn force_unstake(s: u32, ) -> Weight { - // Minimum execution time: 82_414 nanoseconds. - Weight::from_ref_time(88_511_246) - // Standard Error: 2_622 - .saturating_add(Weight::from_ref_time(1_131_814).saturating_mul(s.into())) + // Minimum execution time: 79_381 nanoseconds. + Weight::from_ref_time(85_216_285) + // Standard Error: 2_681 + .saturating_add(Weight::from_ref_time(1_100_353).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(11)) .saturating_add(RocksDbWeight::get().writes(12)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(s.into()))) @@ -714,17 +719,20 @@ impl WeightInfo for () { // Storage: Staking UnappliedSlashes (r:1 w:1) /// The range of component `s` is `[1, 1000]`. fn cancel_deferred_slash(s: u32, ) -> Weight { - // Minimum execution time: 94_197 nanoseconds. - Weight::from_ref_time(903_418_326) - // Standard Error: 59_354 - .saturating_add(Weight::from_ref_time(4_948_354).saturating_mul(s.into())) + // Minimum execution time: 92_049 nanoseconds. + Weight::from_ref_time(894_164_159) + // Standard Error: 58_104 + .saturating_add(Weight::from_ref_time(4_961_170).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(1)) .saturating_add(RocksDbWeight::get().writes(1)) } // Storage: Staking CurrentEra (r:1 w:0) + // Storage: Staking ErasStakersOverview (r:1 w:0) // Storage: Staking ErasValidatorReward (r:1 w:0) // Storage: Staking Bonded (r:1 w:0) // Storage: Staking Ledger (r:1 w:1) + // Storage: Staking ClaimedRewards (r:1 w:1) + // Storage: Staking ErasStakersPaged (r:1 w:0) // Storage: Staking ErasStakersClipped (r:1 w:0) // Storage: Staking ErasRewardPoints (r:1 w:0) // Storage: Staking ErasValidatorPrefs (r:1 w:0) @@ -732,19 +740,22 @@ impl WeightInfo for () { // Storage: System Account (r:1 w:1) /// The range of component `n` is `[0, 256]`. fn payout_stakers_dead_controller(n: u32, ) -> Weight { - // Minimum execution time: 133_065 nanoseconds. - Weight::from_ref_time(197_555_906) - // Standard Error: 19_561 - .saturating_add(Weight::from_ref_time(22_683_426).saturating_mul(n.into())) - .saturating_add(RocksDbWeight::get().reads(9)) + // Minimum execution time: 134_548 nanoseconds. + Weight::from_ref_time(195_909_318) + // Standard Error: 17_825 + .saturating_add(Weight::from_ref_time(22_179_182).saturating_mul(n.into())) + .saturating_add(RocksDbWeight::get().reads(11)) .saturating_add(RocksDbWeight::get().reads((3_u64).saturating_mul(n.into()))) - .saturating_add(RocksDbWeight::get().writes(2)) + .saturating_add(RocksDbWeight::get().writes(3)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(n.into()))) } // Storage: Staking CurrentEra (r:1 w:0) + // Storage: Staking ErasStakersOverview (r:1 w:0) // Storage: Staking ErasValidatorReward (r:1 w:0) // Storage: Staking Bonded (r:1 w:0) // Storage: Staking Ledger (r:1 w:1) + // Storage: Staking ClaimedRewards (r:1 w:1) + // Storage: Staking ErasStakersPaged (r:1 w:0) // Storage: Staking ErasStakersClipped (r:1 w:0) // Storage: Staking ErasRewardPoints (r:1 w:0) // Storage: Staking ErasValidatorPrefs (r:1 w:0) @@ -753,13 +764,13 @@ impl WeightInfo for () { // Storage: Balances Locks (r:1 w:1) /// The range of component `n` is `[0, 256]`. fn payout_stakers_alive_staked(n: u32, ) -> Weight { - // Minimum execution time: 164_719 nanoseconds. - Weight::from_ref_time(226_304_276) - // Standard Error: 31_675 - .saturating_add(Weight::from_ref_time(32_622_427).saturating_mul(n.into())) - .saturating_add(RocksDbWeight::get().reads(10)) + // Minimum execution time: 167_574 nanoseconds. + Weight::from_ref_time(232_044_473) + // Standard Error: 25_865 + .saturating_add(Weight::from_ref_time(31_272_789).saturating_mul(n.into())) + .saturating_add(RocksDbWeight::get().reads(12)) .saturating_add(RocksDbWeight::get().reads((5_u64).saturating_mul(n.into()))) - .saturating_add(RocksDbWeight::get().writes(3)) + .saturating_add(RocksDbWeight::get().writes(4)) .saturating_add(RocksDbWeight::get().writes((3_u64).saturating_mul(n.into()))) } // Storage: Staking Ledger (r:1 w:1) @@ -770,10 +781,10 @@ impl WeightInfo for () { // Storage: VoterList ListBags (r:2 w:2) /// The range of component `l` is `[1, 32]`. fn rebond(l: u32, ) -> Weight { - // Minimum execution time: 95_631 nanoseconds. - Weight::from_ref_time(96_861_556) - // Standard Error: 2_114 - .saturating_add(Weight::from_ref_time(37_543).saturating_mul(l.into())) + // Minimum execution time: 91_739 nanoseconds. + Weight::from_ref_time(93_123_333) + // Standard Error: 3_580 + .saturating_add(Weight::from_ref_time(69_425).saturating_mul(l.into())) .saturating_add(RocksDbWeight::get().reads(9)) .saturating_add(RocksDbWeight::get().writes(8)) } @@ -792,10 +803,10 @@ impl WeightInfo for () { // Storage: Staking SpanSlash (r:0 w:1) /// The range of component `s` is `[1, 100]`. fn reap_stash(s: u32, ) -> Weight { - // Minimum execution time: 95_251 nanoseconds. - Weight::from_ref_time(97_818_954) - // Standard Error: 2_356 - .saturating_add(Weight::from_ref_time(1_104_695).saturating_mul(s.into())) + // Minimum execution time: 90_792 nanoseconds. + Weight::from_ref_time(93_893_087) + // Standard Error: 4_158 + .saturating_add(Weight::from_ref_time(1_084_858).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(12)) .saturating_add(RocksDbWeight::get().writes(12)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(s.into()))) @@ -811,8 +822,9 @@ impl WeightInfo for () { // Storage: Staking ValidatorCount (r:1 w:0) // Storage: Staking MinimumValidatorCount (r:1 w:0) // Storage: Staking CurrentEra (r:1 w:1) - // Storage: Staking ErasStakersClipped (r:0 w:1) // Storage: Staking ErasValidatorPrefs (r:0 w:1) + // Storage: Staking ErasStakersPaged (r:0 w:1) + // Storage: Staking ErasStakersOverview (r:0 w:1) // Storage: Staking ErasStakers (r:0 w:1) // Storage: Staking ErasTotalStake (r:0 w:1) // Storage: Staking ErasStartSessionIndex (r:0 w:1) @@ -820,17 +832,17 @@ impl WeightInfo for () { /// The range of component `v` is `[1, 10]`. /// The range of component `n` is `[0, 100]`. fn new_era(v: u32, n: u32, ) -> Weight { - // Minimum execution time: 512_923 nanoseconds. - Weight::from_ref_time(514_740_000) - // Standard Error: 1_790_238 - .saturating_add(Weight::from_ref_time(59_320_539).saturating_mul(v.into())) - // Standard Error: 178_387 - .saturating_add(Weight::from_ref_time(13_902_705).saturating_mul(n.into())) + // Minimum execution time: 506_210 nanoseconds. + Weight::from_ref_time(508_476_000) + // Standard Error: 1_787_036 + .saturating_add(Weight::from_ref_time(60_417_557).saturating_mul(v.into())) + // Standard Error: 178_068 + .saturating_add(Weight::from_ref_time(13_499_037).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(206)) .saturating_add(RocksDbWeight::get().reads((5_u64).saturating_mul(v.into()))) .saturating_add(RocksDbWeight::get().reads((4_u64).saturating_mul(n.into()))) - .saturating_add(RocksDbWeight::get().writes(4)) - .saturating_add(RocksDbWeight::get().writes((3_u64).saturating_mul(v.into()))) + .saturating_add(RocksDbWeight::get().writes(3)) + .saturating_add(RocksDbWeight::get().writes((4_u64).saturating_mul(v.into()))) } // Storage: VoterList CounterForListNodes (r:1 w:0) // Storage: VoterList ListBags (r:200 w:0) @@ -843,12 +855,12 @@ impl WeightInfo for () { /// The range of component `v` is `[500, 1000]`. /// The range of component `n` is `[500, 1000]`. fn get_npos_voters(v: u32, n: u32, ) -> Weight { - // Minimum execution time: 24_913_316 nanoseconds. - Weight::from_ref_time(25_053_596_000) - // Standard Error: 324_610 - .saturating_add(Weight::from_ref_time(3_454_859).saturating_mul(v.into())) - // Standard Error: 324_610 - .saturating_add(Weight::from_ref_time(3_020_267).saturating_mul(n.into())) + // Minimum execution time: 24_070_794 nanoseconds. + Weight::from_ref_time(24_294_007_000) + // Standard Error: 322_618 + .saturating_add(Weight::from_ref_time(3_570_673).saturating_mul(v.into())) + // Standard Error: 322_618 + .saturating_add(Weight::from_ref_time(2_900_021).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(201)) .saturating_add(RocksDbWeight::get().reads((5_u64).saturating_mul(v.into()))) .saturating_add(RocksDbWeight::get().reads((4_u64).saturating_mul(n.into()))) @@ -858,10 +870,10 @@ impl WeightInfo for () { // Storage: Staking Validators (r:501 w:0) /// The range of component `v` is `[500, 1000]`. fn get_npos_targets(v: u32, ) -> Weight { - // Minimum execution time: 4_916_401 nanoseconds. - Weight::from_ref_time(81_160_966) - // Standard Error: 23_829 - .saturating_add(Weight::from_ref_time(9_883_413).saturating_mul(v.into())) + // Minimum execution time: 4_776_351 nanoseconds. + Weight::from_ref_time(4_849_553_000) + // Standard Error: 55_132 + .saturating_add(Weight::from_ref_time(3_604_980).saturating_mul(v.into())) .saturating_add(RocksDbWeight::get().reads(2)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(v.into()))) } @@ -872,8 +884,8 @@ impl WeightInfo for () { // Storage: Staking MaxNominatorsCount (r:0 w:1) // Storage: Staking MinNominatorBond (r:0 w:1) fn set_staking_configs_all_set() -> Weight { - // Minimum execution time: 10_937 nanoseconds. - Weight::from_ref_time(11_324_000) + // Minimum execution time: 10_781 nanoseconds. + Weight::from_ref_time(11_034_000) .saturating_add(RocksDbWeight::get().writes(6)) } // Storage: Staking MinCommission (r:0 w:1) @@ -883,8 +895,8 @@ impl WeightInfo for () { // Storage: Staking MaxNominatorsCount (r:0 w:1) // Storage: Staking MinNominatorBond (r:0 w:1) fn set_staking_configs_all_remove() -> Weight { - // Minimum execution time: 9_424 nanoseconds. - Weight::from_ref_time(10_021_000) + // Minimum execution time: 9_418 nanoseconds. + Weight::from_ref_time(10_150_000) .saturating_add(RocksDbWeight::get().writes(6)) } // Storage: Staking Ledger (r:1 w:0) @@ -898,23 +910,23 @@ impl WeightInfo for () { // Storage: VoterList ListBags (r:1 w:1) // Storage: VoterList CounterForListNodes (r:1 w:1) fn chill_other() -> Weight { - // Minimum execution time: 84_495 nanoseconds. - Weight::from_ref_time(85_559_000) + // Minimum execution time: 82_590 nanoseconds. + Weight::from_ref_time(83_718_000) .saturating_add(RocksDbWeight::get().reads(11)) .saturating_add(RocksDbWeight::get().writes(6)) } // Storage: Staking MinCommission (r:1 w:0) // Storage: Staking Validators (r:1 w:1) fn force_apply_min_commission() -> Weight { - // Minimum execution time: 20_385 nanoseconds. - Weight::from_ref_time(20_824_000) + // Minimum execution time: 19_367 nanoseconds. + Weight::from_ref_time(19_668_000) .saturating_add(RocksDbWeight::get().reads(2)) .saturating_add(RocksDbWeight::get().writes(1)) } // Storage: Staking MinCommission (r:0 w:1) fn set_min_commission() -> Weight { - // Minimum execution time: 6_995 nanoseconds. - Weight::from_ref_time(7_213_000) + // Minimum execution time: 6_107 nanoseconds. + Weight::from_ref_time(6_449_000) .saturating_add(RocksDbWeight::get().writes(1)) } } From 1aed1b5adfb8ca777fec85a35bc0df64b5ef0682 Mon Sep 17 00:00:00 2001 From: Ankan Date: Mon, 23 Jan 2023 17:20:05 +0100 Subject: [PATCH 042/162] doc for split into pages --- frame/staking/src/lib.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index 61d51cfe5d870..6327c254398ca 100644 --- a/frame/staking/src/lib.rs +++ b/frame/staking/src/lib.rs @@ -735,6 +735,8 @@ impl Default for Exposure Exposure { + /// Splits an `Exposure` into `ExposureOverview` and multiple chunks of `IndividualExposure` + /// with each chunk having maximum of `page_size` elements. fn as_pages( &self, page_size: u32, From 18d2d1dd1468c9af1abdd268446bb234ca6458b7 Mon Sep 17 00:00:00 2001 From: Ankan Date: Mon, 23 Jan 2023 17:20:35 +0100 Subject: [PATCH 043/162] remove unused from --- frame/staking/src/lib.rs | 8 -------- 1 file changed, 8 deletions(-) diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index 6327c254398ca..25de1c9485bbb 100644 --- a/frame/staking/src/lib.rs +++ b/frame/staking/src/lib.rs @@ -788,14 +788,6 @@ impl Default for ExposurePage - From> for ExposurePage -{ - fn from(exposure: Exposure) -> Self { - Self { page_total: exposure.total, others: exposure.others } - } -} - /// A snapshot of the stake backing a single validator in the system. #[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Encode, Decode, RuntimeDebug, TypeInfo)] pub struct ExposureOverview { From b14319e73ecf640eec5662e0c710dc674b63a535 Mon Sep 17 00:00:00 2001 From: Ankan Date: Mon, 23 Jan 2023 17:26:16 +0100 Subject: [PATCH 044/162] fix doc --- frame/staking/src/lib.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index 25de1c9485bbb..2297d6ea96e90 100644 --- a/frame/staking/src/lib.rs +++ b/frame/staking/src/lib.rs @@ -788,7 +788,10 @@ impl Default for ExposurePage { /// The total balance backing this validator. From 0fa0195b178411d39c08052ca9cb1d6bc92a4f07 Mon Sep 17 00:00:00 2001 From: Ankan Date: Mon, 23 Jan 2023 18:05:21 +0100 Subject: [PATCH 045/162] rename MaxNominatorRewardedPerValidator --- bin/node/runtime/src/lib.rs | 4 +-- frame/babe/src/mock.rs | 2 +- frame/fast-unstake/src/mock.rs | 2 +- frame/grandpa/src/mock.rs | 2 +- .../nomination-pools/benchmarking/src/mock.rs | 2 +- .../nomination-pools/test-staking/src/mock.rs | 2 +- frame/offences/benchmarking/src/mock.rs | 2 +- frame/root-offences/src/mock.rs | 2 +- frame/session/benchmarking/src/mock.rs | 2 +- frame/staking/README.md | 6 ++-- frame/staking/src/benchmarking.rs | 12 +++---- frame/staking/src/lib.rs | 13 ++++--- frame/staking/src/mock.rs | 4 +-- frame/staking/src/pallet/impls.rs | 2 +- frame/staking/src/pallet/mod.rs | 35 +++++++++++-------- frame/staking/src/tests.rs | 12 +++---- 16 files changed, 55 insertions(+), 49 deletions(-) diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 0ac6ade9127e8..ec8d40fbcff66 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -541,7 +541,7 @@ parameter_types! { pub const BondingDuration: sp_staking::EraIndex = 24 * 28; pub const SlashDeferDuration: sp_staking::EraIndex = 24 * 7; // 1/4 the bonding duration. pub const RewardCurve: &'static PiecewiseLinear<'static> = &REWARD_CURVE; - pub const MaxNominatorRewardedPerValidator: u32 = 256; + pub const MaxNominatorRewardedPerPage: u32 = 256; pub const OffendingValidatorsThreshold: Perbill = Perbill::from_percent(17); pub OffchainRepeat: BlockNumber = 5; pub HistoryDepth: u32 = 84; @@ -574,7 +574,7 @@ impl pallet_staking::Config for Runtime { type SessionInterface = Self; type EraPayout = pallet_staking::ConvertCurve; type NextNewSession = Session; - type MaxNominatorRewardedPerValidator = MaxNominatorRewardedPerValidator; + type MaxNominatorRewardedPerPage = MaxNominatorRewardedPerPage; type OffendingValidatorsThreshold = OffendingValidatorsThreshold; type ElectionProvider = ElectionProviderMultiPhase; type GenesisElectionProvider = onchain::OnChainExecution; diff --git a/frame/babe/src/mock.rs b/frame/babe/src/mock.rs index abae1b7e33157..f7fd36abe67d3 100644 --- a/frame/babe/src/mock.rs +++ b/frame/babe/src/mock.rs @@ -194,7 +194,7 @@ impl pallet_staking::Config for Test { type SessionInterface = Self; type UnixTime = pallet_timestamp::Pallet; type EraPayout = pallet_staking::ConvertCurve; - type MaxNominatorRewardedPerValidator = ConstU32<64>; + type MaxNominatorRewardedPerPage = ConstU32<64>; type OffendingValidatorsThreshold = OffendingValidatorsThreshold; type NextNewSession = Session; type ElectionProvider = onchain::OnChainExecution; diff --git a/frame/fast-unstake/src/mock.rs b/frame/fast-unstake/src/mock.rs index 3f974e5e1a9d6..3dfd562cbe604 100644 --- a/frame/fast-unstake/src/mock.rs +++ b/frame/fast-unstake/src/mock.rs @@ -146,7 +146,7 @@ impl pallet_staking::Config for Runtime { type EraPayout = pallet_staking::ConvertCurve; type NextNewSession = (); type HistoryDepth = ConstU32<84>; - type MaxNominatorRewardedPerValidator = ConstU32<64>; + type MaxNominatorRewardedPerPage = ConstU32<64>; type OffendingValidatorsThreshold = (); type ElectionProvider = MockElection; type GenesisElectionProvider = Self::ElectionProvider; diff --git a/frame/grandpa/src/mock.rs b/frame/grandpa/src/mock.rs index c618705af0651..addfc8cfa86d1 100644 --- a/frame/grandpa/src/mock.rs +++ b/frame/grandpa/src/mock.rs @@ -198,7 +198,7 @@ impl pallet_staking::Config for Test { type SessionInterface = Self; type UnixTime = pallet_timestamp::Pallet; type EraPayout = pallet_staking::ConvertCurve; - type MaxNominatorRewardedPerValidator = ConstU32<64>; + type MaxNominatorRewardedPerPage = ConstU32<64>; type OffendingValidatorsThreshold = OffendingValidatorsThreshold; type NextNewSession = Session; type ElectionProvider = onchain::OnChainExecution; diff --git a/frame/nomination-pools/benchmarking/src/mock.rs b/frame/nomination-pools/benchmarking/src/mock.rs index 06a66838594c7..03ba816db917a 100644 --- a/frame/nomination-pools/benchmarking/src/mock.rs +++ b/frame/nomination-pools/benchmarking/src/mock.rs @@ -107,7 +107,7 @@ impl pallet_staking::Config for Runtime { type SessionInterface = (); type EraPayout = pallet_staking::ConvertCurve; type NextNewSession = (); - type MaxNominatorRewardedPerValidator = ConstU32<64>; + type MaxNominatorRewardedPerPage = ConstU32<64>; type OffendingValidatorsThreshold = (); type ElectionProvider = frame_election_provider_support::NoElection<(AccountId, BlockNumber, Staking, ())>; diff --git a/frame/nomination-pools/test-staking/src/mock.rs b/frame/nomination-pools/test-staking/src/mock.rs index c67aec0134b07..e69130aa17070 100644 --- a/frame/nomination-pools/test-staking/src/mock.rs +++ b/frame/nomination-pools/test-staking/src/mock.rs @@ -121,7 +121,7 @@ impl pallet_staking::Config for Runtime { type SessionInterface = (); type EraPayout = pallet_staking::ConvertCurve; type NextNewSession = (); - type MaxNominatorRewardedPerValidator = ConstU32<64>; + type MaxNominatorRewardedPerPage = ConstU32<64>; type OffendingValidatorsThreshold = (); type ElectionProvider = frame_election_provider_support::NoElection<(AccountId, BlockNumber, Staking, ())>; diff --git a/frame/offences/benchmarking/src/mock.rs b/frame/offences/benchmarking/src/mock.rs index 592e821a81d8c..bcaad06f4fa97 100644 --- a/frame/offences/benchmarking/src/mock.rs +++ b/frame/offences/benchmarking/src/mock.rs @@ -170,7 +170,7 @@ impl pallet_staking::Config for Test { type SessionInterface = Self; type EraPayout = pallet_staking::ConvertCurve; type NextNewSession = Session; - type MaxNominatorRewardedPerValidator = ConstU32<64>; + type MaxNominatorRewardedPerPage = ConstU32<64>; type OffendingValidatorsThreshold = (); type ElectionProvider = onchain::OnChainExecution; type GenesisElectionProvider = Self::ElectionProvider; diff --git a/frame/root-offences/src/mock.rs b/frame/root-offences/src/mock.rs index 273fbf614169d..871b3632f1ec2 100644 --- a/frame/root-offences/src/mock.rs +++ b/frame/root-offences/src/mock.rs @@ -184,7 +184,7 @@ impl pallet_staking::Config for Test { type SessionInterface = Self; type EraPayout = pallet_staking::ConvertCurve; type NextNewSession = Session; - type MaxNominatorRewardedPerValidator = ConstU32<64>; + type MaxNominatorRewardedPerPage = ConstU32<64>; type OffendingValidatorsThreshold = OffendingValidatorsThreshold; type ElectionProvider = onchain::OnChainExecution; type GenesisElectionProvider = Self::ElectionProvider; diff --git a/frame/session/benchmarking/src/mock.rs b/frame/session/benchmarking/src/mock.rs index 0699640bc092a..04e8668f7e61d 100644 --- a/frame/session/benchmarking/src/mock.rs +++ b/frame/session/benchmarking/src/mock.rs @@ -172,7 +172,7 @@ impl pallet_staking::Config for Test { type SessionInterface = Self; type EraPayout = pallet_staking::ConvertCurve; type NextNewSession = Session; - type MaxNominatorRewardedPerValidator = ConstU32<64>; + type MaxNominatorRewardedPerPage = ConstU32<64>; type OffendingValidatorsThreshold = (); type ElectionProvider = onchain::OnChainExecution; type GenesisElectionProvider = Self::ElectionProvider; diff --git a/frame/staking/README.md b/frame/staking/README.md index bbd5bd18f6e81..094b102b38955 100644 --- a/frame/staking/README.md +++ b/frame/staking/README.md @@ -90,9 +90,9 @@ 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`] -biggest stakers can claim their reward. This is to limit the i/o cost to mutate storage for each -nominator's account. +validator as well as its nominators. Rewards are paged to maximum of [`Config::MaxNominatorRewardedPerPage`] +nominators per call. Each page of staker payout needs to be called separately to ensure all nominators are +paid. This is to limit the i/o cost to mutate storage for each nominator's account. Slashing can occur at any point in time, once misbehavior is reported. Once slashing is determined, a value is deducted from the balance of the validator and all the nominators who diff --git a/frame/staking/src/benchmarking.rs b/frame/staking/src/benchmarking.rs index 49071ef4e8875..cbd556967cd61 100644 --- a/frame/staking/src/benchmarking.rs +++ b/frame/staking/src/benchmarking.rs @@ -546,10 +546,10 @@ benchmarks! { } payout_stakers_dead_controller { - let n in 0 .. T::MaxNominatorRewardedPerValidator::get() as u32; + let n in 0 .. T::MaxNominatorRewardedPerPage::get() as u32; let (validator, nominators) = create_validator_with_nominators::( n, - T::MaxNominatorRewardedPerValidator::get() as u32, + T::MaxNominatorRewardedPerPage::get() as u32, true, RewardDestination::Controller, )?; @@ -579,10 +579,10 @@ benchmarks! { } payout_stakers_alive_staked { - let n in 0 .. T::MaxNominatorRewardedPerValidator::get() as u32; + let n in 0 .. T::MaxNominatorRewardedPerPage::get() as u32; let (validator, nominators) = create_validator_with_nominators::( n, - T::MaxNominatorRewardedPerValidator::get() as u32, + T::MaxNominatorRewardedPerPage::get() as u32, false, RewardDestination::Staked, )?; @@ -976,7 +976,7 @@ mod tests { let (validator_stash, nominators) = create_validator_with_nominators::( n, - <::MaxNominatorRewardedPerValidator as Get<_>>::get(), + <::MaxNominatorRewardedPerPage as Get<_>>::get(), false, RewardDestination::Staked, ) @@ -1006,7 +1006,7 @@ mod tests { let (validator_stash, _nominators) = create_validator_with_nominators::( n, - <::MaxNominatorRewardedPerValidator as Get<_>>::get(), + <::MaxNominatorRewardedPerPage as Get<_>>::get(), false, RewardDestination::Staked, ) diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index 2297d6ea96e90..eda3c8437e25c 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::MaxNominatorRewardedPerPage`] //! biggest stakers can claim their reward. This is to limit the i/o cost to mutate storage for each //! nominator's account. //! @@ -224,13 +224,12 @@ //! The validator can declare an amount, named [`commission`](ValidatorPrefs::commission), that does //! not get shared with the nominators at each reward payout through its [`ValidatorPrefs`]. This //! value gets deducted from the total reward that is paid to the validator and its nominators. The -//! remaining portion is split pro rata among the validator and the top -//! [`Config::MaxNominatorRewardedPerValidator`] nominators that nominated the validator, -//! proportional to the value staked behind the validator (_i.e._ dividing the +//! remaining portion is split pro rata among the validator and the nominators that nominated the +//! validator, proportional to the value staked behind the validator (_i.e._ dividing the //! [`own`](Exposure::own) or [`others`](Exposure::others) by [`total`](Exposure::total) in -//! [`Exposure`]). Note that the pro rata division of rewards uses the total exposure behind the -//! validator, *not* just the exposure of the validator and the top -//! [`Config::MaxNominatorRewardedPerValidator`] nominators. +//! [`Exposure`]). Note that payouts are made in pages with each page capped at +//! [`T::MaxNominatorRewardedPerPage`] nominators. The distribution of nominators across pages are +//! unsorted and depends on the election result provided by [`T::ElectionProvider`]. //! //! All entities who receive a reward have the option to choose their reward destination through the //! [`Payee`] storage item (see diff --git a/frame/staking/src/mock.rs b/frame/staking/src/mock.rs index edf8d29645a55..1b737599e3080 100644 --- a/frame/staking/src/mock.rs +++ b/frame/staking/src/mock.rs @@ -232,7 +232,7 @@ parameter_types! { pub static BagThresholds: &'static [sp_npos_elections::VoteWeight] = &THRESHOLDS; pub static MaxNominations: u32 = 16; pub static HistoryDepth: u32 = 80; - pub static MaxNominatorRewardedPerValidator: u32 = 64; + pub static MaxNominatorRewardedPerPage: u32 = 64; pub static MaxUnlockingChunks: u32 = 32; pub static RewardOnUnbalanceWasCalled: bool = false; pub static LedgerSlashPerEra: (BalanceOf, BTreeMap>) = (Zero::zero(), BTreeMap::new()); @@ -295,7 +295,7 @@ impl crate::pallet::pallet::Config for Test { type SessionInterface = Self; type EraPayout = ConvertCurve; type NextNewSession = Session; - type MaxNominatorRewardedPerValidator = MaxNominatorRewardedPerValidator; + type MaxNominatorRewardedPerPage = MaxNominatorRewardedPerPage; type OffendingValidatorsThreshold = OffendingValidatorsThreshold; type ElectionProvider = onchain::OnChainExecution; type GenesisElectionProvider = Self::ElectionProvider; diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index 86eb0327a5e1a..7f4b08271eed0 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -261,7 +261,7 @@ impl Pallet { } T::Reward::on_unbalanced(total_imbalance); - debug_assert!(nominator_payout_count <= T::MaxNominatorRewardedPerValidator::get()); + debug_assert!(nominator_payout_count <= T::MaxNominatorRewardedPerPage::get()); Ok(Some(T::WeightInfo::payout_stakers_alive_staked(nominator_payout_count)).into()) } diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index 1939a53607b73..47f0ffb1097e1 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -203,11 +203,11 @@ pub mod pallet { /// The maximum number of nominators rewarded for each validator. /// - /// For each validator only the `$MaxNominatorRewardedPerValidator` biggest stakers can - /// claim their reward. This used to limit the i/o cost for the nominator payout. - // TODO(ank4n): Refactor into a better name to indicate that this is a per-page limit. + /// A reward payout is restricted to a maximum of `MaxNominatorRewardedPerPage` nominators + /// in a single call. This used to limit the i/o cost for the nominator payout. + /// See [`payout_stakers`] for more details. #[pallet::constant] - type MaxNominatorRewardedPerValidator: Get; + type MaxNominatorRewardedPerPage: Get; /// The fraction of the validator set that is safe to be offending. /// After the threshold is reached a new era will be forced. @@ -440,8 +440,11 @@ pub mod pallet { /// Clipped Exposure of validator at era. /// + /// Note: This is deprecated, should be used as read-only and will be removed in the future. + /// New `Exposure`s are stored in a paged manner in `ErasStakersPaged` instead. + /// /// This is similar to [`ErasStakers`] but number of nominators exposed is reduced to the - /// `T::MaxNominatorRewardedPerValidator` biggest stakers. + /// `T::MaxNominatorRewardedPerPage` 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. /// @@ -701,7 +704,7 @@ pub mod pallet { >::insert(era, &validator, &exposure); let (exposure_overview, exposure_pages) = - exposure.as_pages(T::MaxNominatorRewardedPerValidator::get()); + exposure.as_pages(T::MaxNominatorRewardedPerPage::get()); >::insert(era, &validator, &exposure_overview); exposure_pages.iter().enumerate().for_each(|(page, paged_exposure)| { @@ -1639,20 +1642,24 @@ pub mod pallet { /// Pay out all the stakers behind a single validator for a single era and page. /// - /// - `validator_stash` is the stash account of the validator. Their nominators, up to - /// `T::MaxNominatorRewardedPerValidator`, will also receive their rewards. + /// - `validator_stash` is the stash account of the validator. /// - `era` may be any era between `[current_era - history_depth; current_era]`. + /// - `page` is the page index of nominators to pay out with value between 0 and + /// `num_nominators / T::MaxNominatorRewardedPerPage`. /// /// The origin of this call must be _Signed_. Any account can call this function, even if /// it is not one of the stakers. /// - /// The list of nominators is paged, with each page being capped at - /// `T::MaxNominatorRewardedPerValidator`. If a validator has multiple pages of nominators, - /// the call needs to be made for each page such that all nominators receive the reward. If - /// rewards are not claimed in `${HistoryDepth}` eras, they are lost. + /// If a validator has more than `T::MaxMaxNominatorRewardedPerPage` nominators backing + /// them, then the list of nominators is paged, with each page being capped at + /// `T::MaxNominatorRewardedPerPage`. If a validator has more than one page of nominators, + /// the call needs to be made for each page separately in order for all the nominators + /// backing a validator receive the reward. The nominators are not sorted across pages and + /// so it should not be assumed the highest staker would be on the topmost page and vice + /// versa. If rewards are not claimed in `${HistoryDepth}` eras, they are lost. /// /// # - /// - Time complexity: at most O(MaxNominatorRewardedPerValidator). + /// - Time complexity: at most O(MaxNominatorRewardedPerPage). /// - Contains a limited number of reads and writes. /// ----------- /// N is the Number of payouts for the validator (including the validator) @@ -1665,7 +1672,7 @@ pub mod pallet { /// # #[pallet::call_index(18)] #[pallet::weight(T::WeightInfo::payout_stakers_alive_staked( - T::MaxNominatorRewardedPerValidator::get() + T::MaxNominatorRewardedPerPage::get() ))] pub fn payout_stakers( origin: OriginFor, diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index 1b20de3f883de..f86189e0e182a 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -2196,7 +2196,7 @@ fn reward_validator_slashing_validator_does_not_overflow() { let exposure = Exposure:: { total: stake, own: stake, others: vec![] }; let (exposure_overview, _) = - exposure.clone().as_pages(MaxNominatorRewardedPerValidator::get()); + exposure.clone().as_pages(MaxNominatorRewardedPerPage::get()); let reward = EraRewardPoints:: { total: 1, individual: vec![(11, 1)].into_iter().collect(), @@ -3701,7 +3701,7 @@ fn six_session_delay() { fn test_nominators_are_rewarded_for_all_exposure_page() { ExtBuilder::default().build_and_execute(|| { // 3 pages of exposure - let nominator_count = 2 * MaxNominatorRewardedPerValidator::get() + 1; + let nominator_count = 2 * MaxNominatorRewardedPerPage::get() + 1; for i in 0..nominator_count { let stash = 10_000 + i as AccountId; @@ -3747,7 +3747,7 @@ fn test_nominators_are_rewarded_for_all_exposure_page() { #[test] fn test_multi_page_payout_stakers() { // Test that payout_stakers work in general, including that only the top - // `T::MaxNominatorRewardedPerValidator` nominators are rewarded. + // `T::MaxNominatorRewardedPerPage` nominators are rewarded. ExtBuilder::default().has_stakers(false).build_and_execute(|| { let balance = 1000; // Track the exposure of the validator and all nominators. @@ -3772,7 +3772,7 @@ fn test_multi_page_payout_stakers() { mock::start_active_era(1); Staking::reward_by_ids(vec![(11, 1)]); - // Since `MaxNominatorRewardedPerValidator = 64`, there are two pages of validator exposure. + // Since `MaxNominatorRewardedPerPage = 64`, there are two pages of validator exposure. assert_eq!(EraInfo::::get_page_count(1, &11), 2); // compute and ensure the reward amount is greater than zero. @@ -4025,7 +4025,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 = MaxNominatorRewardedPerPage::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; @@ -5875,7 +5875,7 @@ fn test_validator_exposure_is_backward_compatible_with_non_paged_rewards_payout( ExtBuilder::default().has_stakers(false).build_and_execute(|| { // case 1: exposure exist in clipped. // set page cap to 10 - MaxNominatorRewardedPerValidator::set(10); + MaxNominatorRewardedPerPage::set(10); bond_validator(11, 10, 1000); let mut expected_individual_exposures: Vec> = vec![]; let mut total_exposure: Balance = 0; From 2d5082d3977ef05878ac1b6c1e3a83b50fccdd1f Mon Sep 17 00:00:00 2001 From: Ankan Date: Mon, 23 Jan 2023 19:22:58 +0100 Subject: [PATCH 046/162] add weight for pages other than 0 --- frame/staking/src/benchmarking.rs | 43 +++++++++++++++++++++++++++++++ frame/staking/src/pallet/impls.rs | 9 ++++++- frame/staking/src/tests.rs | 1 - frame/staking/src/weights.rs | 8 ++++++ 4 files changed, 59 insertions(+), 2 deletions(-) diff --git a/frame/staking/src/benchmarking.rs b/frame/staking/src/benchmarking.rs index cbd556967cd61..8419ba12bfc26 100644 --- a/frame/staking/src/benchmarking.rs +++ b/frame/staking/src/benchmarking.rs @@ -614,6 +614,49 @@ benchmarks! { } } + payout_stakers_alive_staked_exclude_validator { + let n in 0 .. T::MaxNominatorRewardedPerPage::get() as u32; + + // create nominators between MaxNominatorRewardedPerPage .. 2 * MaxNominatorRewardedPerPage + let (validator, nominators) = create_validator_with_nominators::( + T::MaxNominatorRewardedPerPage::get() + n, + 2*T::MaxNominatorRewardedPerPage::get() as u32, + false, + RewardDestination::Staked, + )?; + + let current_era = CurrentEra::::get().unwrap(); + // set the commission for this particular era as well. + >::insert(current_era, validator.clone(), >::validators(&validator)); + + let caller = whitelisted_caller(); + let balance_before = T::Currency::free_balance(&validator); + let mut nominator_balances_before = Vec::new(); + for (stash, _) in &nominators { + let balance = T::Currency::free_balance(stash); + nominator_balances_before.push(balance); + } + }: payout_stakers(RawOrigin::Signed(caller), validator.clone(), current_era, 1) + verify { + let balance_after = T::Currency::free_balance(&validator); + ensure!( + balance_before == balance_after, + "Balance of validator stash should have stayed same after payout since its not page 0.", + ); + let mut nominator_payout_count = 0; + for ((stash, _), balance_before) in nominators.iter().zip(nominator_balances_before.iter()) { + let balance_after = T::Currency::free_balance(stash); + if balance_before < &balance_after { + nominator_payout_count += 1; + } + } + ensure!( + nominator_payout_count == n, + "n nominators must have been paid.", + ); + } + + rebond { let l in 1 .. T::MaxUnlockingChunks::get() as u32; diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index 7f4b08271eed0..f20e1593111f6 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -262,7 +262,14 @@ impl Pallet { T::Reward::on_unbalanced(total_imbalance); debug_assert!(nominator_payout_count <= T::MaxNominatorRewardedPerPage::get()); - Ok(Some(T::WeightInfo::payout_stakers_alive_staked(nominator_payout_count)).into()) + + let payout_weight = if page == 0 { + T::WeightInfo::payout_stakers_alive_staked(nominator_payout_count) + } else { + T::WeightInfo::payout_stakers_alive_staked_exclude_validator(nominator_payout_count) + }; + + Ok(Some(payout_weight).into()) } /// Update the ledger for a controller. diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index f86189e0e182a..503205b60d0c9 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -3778,7 +3778,6 @@ fn test_multi_page_payout_stakers() { // compute and ensure the reward amount is greater than zero. let payout = current_total_payout_for_duration(reward_time_per_era()); let actual_paid_out = payout_exposure_part * payout; - println!("Actual paid out {:?}", actual_paid_out); mock::start_active_era(2); // verify the exposures are calculated correctly. diff --git a/frame/staking/src/weights.rs b/frame/staking/src/weights.rs index dc62a86201be6..17f63d836e73c 100644 --- a/frame/staking/src/weights.rs +++ b/frame/staking/src/weights.rs @@ -68,6 +68,7 @@ pub trait WeightInfo { fn cancel_deferred_slash(s: u32, ) -> Weight; fn payout_stakers_dead_controller(n: u32, ) -> Weight; fn payout_stakers_alive_staked(n: u32, ) -> Weight; + fn payout_stakers_alive_staked_exclude_validator(n: u32, ) -> Weight; fn rebond(l: u32, ) -> Weight; fn reap_stash(s: u32, ) -> Weight; fn new_era(v: u32, n: u32, ) -> Weight; @@ -348,6 +349,9 @@ impl WeightInfo for SubstrateWeight { .saturating_add(T::DbWeight::get().writes(4)) .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(n.into()))) } + fn payout_stakers_alive_staked_exclude_validator(n: u32, ) -> Weight { + Weight::from_ref_time(0) + } // Storage: Staking Ledger (r:1 w:1) // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) @@ -773,6 +777,10 @@ impl WeightInfo for () { .saturating_add(RocksDbWeight::get().writes(4)) .saturating_add(RocksDbWeight::get().writes((3_u64).saturating_mul(n.into()))) } + fn payout_stakers_alive_staked_exclude_validator(n: u32, ) -> Weight { + // Minimum execution time: 164_719 nanoseconds. + Weight::from_ref_time(0) + } // Storage: Staking Ledger (r:1 w:1) // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) From ce6700452de823cbf3e3a875a7aa686e4e42ddda Mon Sep 17 00:00:00 2001 From: Ankan Date: Mon, 23 Jan 2023 19:26:23 +0100 Subject: [PATCH 047/162] fmt --- frame/staking/src/tests.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index 503205b60d0c9..9768214bdac0a 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -2195,8 +2195,7 @@ fn reward_validator_slashing_validator_does_not_overflow() { let _ = Balances::make_free_balance_be(&11, stake); let exposure = Exposure:: { total: stake, own: stake, others: vec![] }; - let (exposure_overview, _) = - exposure.clone().as_pages(MaxNominatorRewardedPerPage::get()); + let (exposure_overview, _) = exposure.clone().as_pages(MaxNominatorRewardedPerPage::get()); let reward = EraRewardPoints:: { total: 1, individual: vec![(11, 1)].into_iter().collect(), From c330866ce43e6375aaf4d46de84fbdc63d90ba06 Mon Sep 17 00:00:00 2001 From: Ankan Date: Mon, 23 Jan 2023 19:34:40 +0100 Subject: [PATCH 048/162] use n to make the compiler happy --- frame/staking/src/weights.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frame/staking/src/weights.rs b/frame/staking/src/weights.rs index 17f63d836e73c..601e0c341524d 100644 --- a/frame/staking/src/weights.rs +++ b/frame/staking/src/weights.rs @@ -350,7 +350,7 @@ impl WeightInfo for SubstrateWeight { .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(n.into()))) } fn payout_stakers_alive_staked_exclude_validator(n: u32, ) -> Weight { - Weight::from_ref_time(0) + Weight::from_ref_time(n.into()) } // Storage: Staking Ledger (r:1 w:1) // Storage: Balances Locks (r:1 w:1) @@ -779,7 +779,7 @@ impl WeightInfo for () { } fn payout_stakers_alive_staked_exclude_validator(n: u32, ) -> Weight { // Minimum execution time: 164_719 nanoseconds. - Weight::from_ref_time(0) + Weight::from_ref_time(n.into()) } // Storage: Staking Ledger (r:1 w:1) // Storage: Balances Locks (r:1 w:1) From 99d19b783875ce7b0304e6e7d08b7fcc72453c93 Mon Sep 17 00:00:00 2001 From: Ankan Date: Mon, 23 Jan 2023 21:00:26 +0100 Subject: [PATCH 049/162] fix minimum count --- frame/staking/src/benchmarking.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/frame/staking/src/benchmarking.rs b/frame/staking/src/benchmarking.rs index 8419ba12bfc26..9344c1b608570 100644 --- a/frame/staking/src/benchmarking.rs +++ b/frame/staking/src/benchmarking.rs @@ -617,10 +617,10 @@ benchmarks! { payout_stakers_alive_staked_exclude_validator { let n in 0 .. T::MaxNominatorRewardedPerPage::get() as u32; - // create nominators between MaxNominatorRewardedPerPage .. 2 * MaxNominatorRewardedPerPage + // create nominators between MaxNominatorRewardedPerPage+1 .. =2 * MaxNominatorRewardedPerPage let (validator, nominators) = create_validator_with_nominators::( - T::MaxNominatorRewardedPerPage::get() + n, - 2*T::MaxNominatorRewardedPerPage::get() as u32, + T::MaxNominatorRewardedPerPage::get() + 1 + n, + 2 * T::MaxNominatorRewardedPerPage::get() as u32, false, RewardDestination::Staked, )?; From fc2e0913356ed7971b3f4bac97d84244fff4e15a Mon Sep 17 00:00:00 2001 From: Ankan Date: Mon, 23 Jan 2023 21:29:53 +0100 Subject: [PATCH 050/162] correct number of nominators --- frame/staking/src/benchmarking.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/frame/staking/src/benchmarking.rs b/frame/staking/src/benchmarking.rs index 9344c1b608570..4131f9b815578 100644 --- a/frame/staking/src/benchmarking.rs +++ b/frame/staking/src/benchmarking.rs @@ -616,11 +616,13 @@ benchmarks! { payout_stakers_alive_staked_exclude_validator { let n in 0 .. T::MaxNominatorRewardedPerPage::get() as u32; - // create nominators between MaxNominatorRewardedPerPage+1 .. =2 * MaxNominatorRewardedPerPage + let nominator_lower_bound = T::MaxNominatorRewardedPerPage::get() + 1; + let nominator_upper_bound = 2 * T::MaxNominatorRewardedPerPage::get() + 1; + let (validator, nominators) = create_validator_with_nominators::( - T::MaxNominatorRewardedPerPage::get() + 1 + n, - 2 * T::MaxNominatorRewardedPerPage::get() as u32, + nominator_lower_bound + n, + nominator_upper_bound as u32, false, RewardDestination::Staked, )?; From 2adf0607ffd5a50cb2823e931f048d9684297d27 Mon Sep 17 00:00:00 2001 From: Ankan Date: Mon, 23 Jan 2023 22:43:25 +0100 Subject: [PATCH 051/162] fix benchmark and commission payout --- frame/staking/src/benchmarking.rs | 14 +++++++++----- frame/staking/src/pallet/impls.rs | 15 ++++++++++----- frame/staking/src/weights.rs | 6 +++--- 3 files changed, 22 insertions(+), 13 deletions(-) diff --git a/frame/staking/src/benchmarking.rs b/frame/staking/src/benchmarking.rs index 4131f9b815578..40024d3aeb4a2 100644 --- a/frame/staking/src/benchmarking.rs +++ b/frame/staking/src/benchmarking.rs @@ -614,11 +614,11 @@ benchmarks! { } } - payout_stakers_alive_staked_exclude_validator { - let n in 0 .. T::MaxNominatorRewardedPerPage::get() as u32; + payout_stakers_nominators_only { + let n in 1 .. T::MaxNominatorRewardedPerPage::get() as u32; // create nominators between MaxNominatorRewardedPerPage+1 .. =2 * MaxNominatorRewardedPerPage - let nominator_lower_bound = T::MaxNominatorRewardedPerPage::get() + 1; - let nominator_upper_bound = 2 * T::MaxNominatorRewardedPerPage::get() + 1; + let nominator_lower_bound = T::MaxNominatorRewardedPerPage::get(); + let nominator_upper_bound = 2 * T::MaxNominatorRewardedPerPage::get(); let (validator, nominators) = create_validator_with_nominators::( nominator_lower_bound + n, @@ -638,13 +638,16 @@ benchmarks! { let balance = T::Currency::free_balance(stash); nominator_balances_before.push(balance); } + }: payout_stakers(RawOrigin::Signed(caller), validator.clone(), current_era, 1) verify { let balance_after = T::Currency::free_balance(&validator); + ensure!( balance_before == balance_after, - "Balance of validator stash should have stayed same after payout since its not page 0.", + "Validator should not have received payout for pages other than 0.", ); + let mut nominator_payout_count = 0; for ((stash, _), balance_before) in nominators.iter().zip(nominator_balances_before.iter()) { let balance_after = T::Currency::free_balance(stash); @@ -652,6 +655,7 @@ benchmarks! { nominator_payout_count += 1; } } + ensure!( nominator_payout_count == n, "n nominators must have been paid.", diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index f20e1593111f6..cc2ab13271938 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -210,10 +210,15 @@ impl Pallet { // This is how much validator + nominators are entitled to. let validator_total_payout = validator_total_reward_part * era_payout; - let validator_prefs = Self::eras_validator_prefs(&era, &validator_stash); - // Validator first gets a cut off the top. - let validator_commission = validator_prefs.commission; - let validator_commission_payout = validator_commission * validator_total_payout; + // TODO(ank4n) add test and refactor this logic + let validator_commission_payout = if page == 0 { + let validator_prefs = Self::eras_validator_prefs(&era, &validator_stash); + // Validator first gets a cut off the top. + let validator_commission = validator_prefs.commission; + validator_commission * validator_total_payout + } else { + Zero::zero() + }; let validator_leftover_payout = validator_total_payout - validator_commission_payout; // Now let's calculate how this is split to the validator. @@ -266,7 +271,7 @@ impl Pallet { let payout_weight = if page == 0 { T::WeightInfo::payout_stakers_alive_staked(nominator_payout_count) } else { - T::WeightInfo::payout_stakers_alive_staked_exclude_validator(nominator_payout_count) + T::WeightInfo::payout_stakers_nominators_only(nominator_payout_count) }; Ok(Some(payout_weight).into()) diff --git a/frame/staking/src/weights.rs b/frame/staking/src/weights.rs index 601e0c341524d..afb4fc0df6b68 100644 --- a/frame/staking/src/weights.rs +++ b/frame/staking/src/weights.rs @@ -68,7 +68,7 @@ pub trait WeightInfo { fn cancel_deferred_slash(s: u32, ) -> Weight; fn payout_stakers_dead_controller(n: u32, ) -> Weight; fn payout_stakers_alive_staked(n: u32, ) -> Weight; - fn payout_stakers_alive_staked_exclude_validator(n: u32, ) -> Weight; + fn payout_stakers_nominators_only(n: u32, ) -> Weight; fn rebond(l: u32, ) -> Weight; fn reap_stash(s: u32, ) -> Weight; fn new_era(v: u32, n: u32, ) -> Weight; @@ -349,7 +349,7 @@ impl WeightInfo for SubstrateWeight { .saturating_add(T::DbWeight::get().writes(4)) .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(n.into()))) } - fn payout_stakers_alive_staked_exclude_validator(n: u32, ) -> Weight { + fn payout_stakers_nominators_only(n: u32, ) -> Weight { Weight::from_ref_time(n.into()) } // Storage: Staking Ledger (r:1 w:1) @@ -777,7 +777,7 @@ impl WeightInfo for () { .saturating_add(RocksDbWeight::get().writes(4)) .saturating_add(RocksDbWeight::get().writes((3_u64).saturating_mul(n.into()))) } - fn payout_stakers_alive_staked_exclude_validator(n: u32, ) -> Weight { + fn payout_stakers_nominators_only(n: u32, ) -> Weight { // Minimum execution time: 164_719 nanoseconds. Weight::from_ref_time(n.into()) } From 26efca459b5ef5a0eab81d792d65320f2c2f62ba Mon Sep 17 00:00:00 2001 From: Ankan Date: Mon, 23 Jan 2023 22:53:19 +0100 Subject: [PATCH 052/162] refactor --- frame/staking/src/pallet/impls.rs | 11 ++--------- frame/staking/src/pallet/mod.rs | 30 +++++++++++++++++++++++------- 2 files changed, 25 insertions(+), 16 deletions(-) diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index cc2ab13271938..90a36dedfb906 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -210,15 +210,8 @@ impl Pallet { // This is how much validator + nominators are entitled to. let validator_total_payout = validator_total_reward_part * era_payout; - // TODO(ank4n) add test and refactor this logic - let validator_commission_payout = if page == 0 { - let validator_prefs = Self::eras_validator_prefs(&era, &validator_stash); - // Validator first gets a cut off the top. - let validator_commission = validator_prefs.commission; - validator_commission * validator_total_payout - } else { - Zero::zero() - }; + let validator_commission = EraInfo::::get_validator_commission(era, &ledger.stash, page); + let validator_commission_payout = validator_commission * validator_total_payout; let validator_leftover_payout = validator_total_payout - validator_commission_payout; // Now let's calculate how this is split to the validator. diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index 47f0ffb1097e1..9664d90b23915 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -684,11 +684,26 @@ pub mod pallet { >::get(&era, validator).page_count.max(1) } - /// Creates an entry to track validator reward has been claimed for a given era and page. - pub(crate) fn set_rewards_as_claimed( + // TODO(ank4n) add commission should only be paid in page 0 test + /// Returns validator commission for this era and page. + pub(crate) fn get_validator_commission( era: EraIndex, - validator: &T::AccountId, + validator_stash: &T::AccountId, page: PageIndex, + ) -> Perbill { + if page != 0 { + // commission is only paid in the first page + return Zero::zero() + } + + >::get(&era, validator_stash).commission + } + + /// Creates an entry to track validator reward has been claimed for a given era and page. + pub(crate) fn set_rewards_as_claimed( + era: EraIndex, + validator: &T::AccountId, + page: PageIndex, ) { ClaimedRewards::::mutate(era, validator, |pages| { pages.push(page); @@ -697,14 +712,14 @@ pub mod pallet { /// Store exposure for elected validators at start of an era. pub(crate) fn set_validator_exposure( - era: EraIndex, - validator: &T::AccountId, - exposure: Exposure>, + era: EraIndex, + validator: &T::AccountId, + exposure: Exposure>, ) { >::insert(era, &validator, &exposure); let (exposure_overview, exposure_pages) = - exposure.as_pages(T::MaxNominatorRewardedPerPage::get()); + exposure.as_pages(T::MaxNominatorRewardedPerPage::get()); >::insert(era, &validator, &exposure_overview); exposure_pages.iter().enumerate().for_each(|(page, paged_exposure)| { @@ -716,6 +731,7 @@ pub mod pallet { pub(crate) fn set_total_stake(era: EraIndex, total_stake: BalanceOf) { >::insert(era, total_stake); } + } /// Indices of validators that have offended in the active era and whether they are currently From d7ab5b7acc48e7b43c826a084c3f90ca00e826a7 Mon Sep 17 00:00:00 2001 From: Ankan Date: Mon, 23 Jan 2023 23:19:15 +0100 Subject: [PATCH 053/162] verify is paid only once per era for their own stake --- frame/staking/src/tests.rs | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index 9768214bdac0a..4160fdb97a33e 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -3751,8 +3751,6 @@ fn test_multi_page_payout_stakers() { let balance = 1000; // Track the exposure of the validator and all nominators. let mut total_exposure = balance; - // Track the exposure of the validator and the nominators that will get paid out. - let mut payout_exposure = balance; // Create a validator: bond_validator(11, 10, balance); // Default(64) assert_eq!(Validators::::count(), 1); @@ -3761,13 +3759,10 @@ fn test_multi_page_payout_stakers() { for i in 0..100 { let bond_amount = balance + i as Balance; bond_nominator(1000 + i, 100 + i, bond_amount, vec![11]); - total_exposure += bond_amount; // with multi page reward payout, payout exposure is same as total exposure. - payout_exposure += bond_amount; + total_exposure += bond_amount; } - let payout_exposure_part = Perbill::from_rational(payout_exposure, total_exposure); - mock::start_active_era(1); Staking::reward_by_ids(vec![(11, 1)]); @@ -3776,7 +3771,6 @@ fn test_multi_page_payout_stakers() { // compute and ensure the reward amount is greater than zero. let payout = current_total_payout_for_duration(reward_time_per_era()); - let actual_paid_out = payout_exposure_part * payout; mock::start_active_era(2); // verify the exposures are calculated correctly. @@ -3793,20 +3787,29 @@ fn test_multi_page_payout_stakers() { let pre_payout_total_issuance = Balances::total_issuance(); RewardOnUnbalanceWasCalled::set(false); + let controller_balance_before_p0_payout = Balances::free_balance(&10); // Payout rewards for first exposure page assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, 1, 0)); + let controller_balance_after_p0_payout = Balances::free_balance(&10); + // verify rewards have been paid out but still some left assert!(Balances::total_issuance() > pre_payout_total_issuance); - assert!(Balances::total_issuance() < pre_payout_total_issuance + actual_paid_out); + assert!(Balances::total_issuance() < pre_payout_total_issuance + payout); + + // verify the validator has been rewarded + assert!(controller_balance_after_p0_payout > controller_balance_before_p0_payout); // Payout the second and last page of nominators assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, 1, 1)); + // verify the validator was not rewarded the second time + assert_eq!(Balances::free_balance(&10), controller_balance_after_p0_payout); + // verify all rewards have been paid out assert_eq_error_rate!( Balances::total_issuance(), - pre_payout_total_issuance + actual_paid_out, + pre_payout_total_issuance + payout, 2 ); assert!(RewardOnUnbalanceWasCalled::get()); @@ -3844,7 +3847,6 @@ fn test_multi_page_payout_stakers() { // compute and ensure the reward amount is greater than zero. let payout = current_total_payout_for_duration(reward_time_per_era()); - let actual_paid_out = payout_exposure_part * payout; let pre_payout_total_issuance = Balances::total_issuance(); mock::start_active_era(i); @@ -3852,7 +3854,7 @@ fn test_multi_page_payout_stakers() { mock::make_all_reward_payment(i - 1); assert_eq_error_rate!( Balances::total_issuance(), - pre_payout_total_issuance + actual_paid_out, + pre_payout_total_issuance + payout, 2 ); assert!(RewardOnUnbalanceWasCalled::get()); From e77bd8705559cabececa4e3c2bf0629b05d02d02 Mon Sep 17 00:00:00 2001 From: Ankan Date: Mon, 23 Jan 2023 23:22:47 +0100 Subject: [PATCH 054/162] fmt --- frame/staking/src/pallet/mod.rs | 15 +++++++-------- frame/staking/src/tests.rs | 6 +----- 2 files changed, 8 insertions(+), 13 deletions(-) diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index 9664d90b23915..d4fec3c17cdca 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -701,9 +701,9 @@ pub mod pallet { /// Creates an entry to track validator reward has been claimed for a given era and page. pub(crate) fn set_rewards_as_claimed( - era: EraIndex, - validator: &T::AccountId, - page: PageIndex, + era: EraIndex, + validator: &T::AccountId, + page: PageIndex, ) { ClaimedRewards::::mutate(era, validator, |pages| { pages.push(page); @@ -712,14 +712,14 @@ pub mod pallet { /// Store exposure for elected validators at start of an era. pub(crate) fn set_validator_exposure( - era: EraIndex, - validator: &T::AccountId, - exposure: Exposure>, + era: EraIndex, + validator: &T::AccountId, + exposure: Exposure>, ) { >::insert(era, &validator, &exposure); let (exposure_overview, exposure_pages) = - exposure.as_pages(T::MaxNominatorRewardedPerPage::get()); + exposure.as_pages(T::MaxNominatorRewardedPerPage::get()); >::insert(era, &validator, &exposure_overview); exposure_pages.iter().enumerate().for_each(|(page, paged_exposure)| { @@ -731,7 +731,6 @@ pub mod pallet { pub(crate) fn set_total_stake(era: EraIndex, total_stake: BalanceOf) { >::insert(era, total_stake); } - } /// Indices of validators that have offended in the active era and whether they are currently diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index 4160fdb97a33e..d61e47063cfb8 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -3807,11 +3807,7 @@ fn test_multi_page_payout_stakers() { assert_eq!(Balances::free_balance(&10), controller_balance_after_p0_payout); // verify all rewards have been paid out - assert_eq_error_rate!( - Balances::total_issuance(), - pre_payout_total_issuance + payout, - 2 - ); + assert_eq_error_rate!(Balances::total_issuance(), pre_payout_total_issuance + payout, 2); assert!(RewardOnUnbalanceWasCalled::get()); // verify all nominators of validator 11 are paid out, including the validator From 6bc015f78cad158362b5b8872f3678694fe43811 Mon Sep 17 00:00:00 2001 From: Ankan Date: Mon, 23 Jan 2023 23:40:48 +0100 Subject: [PATCH 055/162] fix rustdoc --- frame/staking/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index eda3c8437e25c..980e6f6181b0a 100644 --- a/frame/staking/src/lib.rs +++ b/frame/staking/src/lib.rs @@ -228,8 +228,8 @@ //! validator, proportional to the value staked behind the validator (_i.e._ dividing the //! [`own`](Exposure::own) or [`others`](Exposure::others) by [`total`](Exposure::total) in //! [`Exposure`]). Note that payouts are made in pages with each page capped at -//! [`T::MaxNominatorRewardedPerPage`] nominators. The distribution of nominators across pages are -//! unsorted and depends on the election result provided by [`T::ElectionProvider`]. +//! [`Config::MaxNominatorRewardedPerPage`] nominators. The distribution of nominators across pages are +//! unsorted and depends on the election result provided by [`Config::ElectionProvider`]. //! //! All entities who receive a reward have the option to choose their reward destination through the //! [`Payee`] storage item (see From 514a8514bcd43594453ad1e997c4873243c9efb3 Mon Sep 17 00:00:00 2001 From: Ankan Date: Mon, 23 Jan 2023 23:47:47 +0100 Subject: [PATCH 056/162] fmt --- frame/staking/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index 980e6f6181b0a..8024d3e3d37c9 100644 --- a/frame/staking/src/lib.rs +++ b/frame/staking/src/lib.rs @@ -228,8 +228,8 @@ //! validator, proportional to the value staked behind the validator (_i.e._ dividing the //! [`own`](Exposure::own) or [`others`](Exposure::others) by [`total`](Exposure::total) in //! [`Exposure`]). Note that payouts are made in pages with each page capped at -//! [`Config::MaxNominatorRewardedPerPage`] nominators. The distribution of nominators across pages are -//! unsorted and depends on the election result provided by [`Config::ElectionProvider`]. +//! [`Config::MaxNominatorRewardedPerPage`] nominators. The distribution of nominators across pages +//! are unsorted and depends on the election result provided by [`Config::ElectionProvider`]. //! //! All entities who receive a reward have the option to choose their reward destination through the //! [`Payee`] storage item (see From 076a0c190753dcb74db9d3c2bfa6209bf183928f Mon Sep 17 00:00:00 2001 From: command-bot <> Date: Mon, 23 Jan 2023 23:46:29 +0000 Subject: [PATCH 057/162] ".git/.scripts/commands/bench/bench.sh" pallet dev pallet_staking --- frame/staking/src/weights.rs | 415 +++++++++++++++++++---------------- 1 file changed, 226 insertions(+), 189 deletions(-) diff --git a/frame/staking/src/weights.rs b/frame/staking/src/weights.rs index afb4fc0df6b68..dea9175460e0a 100644 --- a/frame/staking/src/weights.rs +++ b/frame/staking/src/weights.rs @@ -89,8 +89,8 @@ impl WeightInfo for SubstrateWeight { // Storage: Balances Locks (r:1 w:1) // Storage: Staking Payee (r:0 w:1) fn bond() -> Weight { - // Minimum execution time: 51_611 nanoseconds. - Weight::from_ref_time(52_566_000) + // Minimum execution time: 51_815 nanoseconds. + Weight::from_ref_time(52_367_000) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -100,8 +100,8 @@ impl WeightInfo for SubstrateWeight { // Storage: VoterList ListNodes (r:3 w:3) // Storage: VoterList ListBags (r:2 w:2) fn bond_extra() -> Weight { - // Minimum execution time: 92_297 nanoseconds. - Weight::from_ref_time(93_016_000) + // Minimum execution time: 91_792 nanoseconds. + Weight::from_ref_time(92_729_000) .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(7)) } @@ -115,8 +115,8 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking Bonded (r:1 w:0) // Storage: VoterList ListBags (r:2 w:2) fn unbond() -> Weight { - // Minimum execution time: 98_447 nanoseconds. - Weight::from_ref_time(99_317_000) + // Minimum execution time: 97_647 nanoseconds. + Weight::from_ref_time(98_731_000) .saturating_add(T::DbWeight::get().reads(12)) .saturating_add(T::DbWeight::get().writes(8)) } @@ -126,10 +126,10 @@ impl WeightInfo for SubstrateWeight { // Storage: System Account (r:1 w:1) /// The range of component `s` is `[0, 100]`. fn withdraw_unbonded_update(s: u32, ) -> Weight { - // Minimum execution time: 45_142 nanoseconds. - Weight::from_ref_time(46_003_517) - // Standard Error: 564 - .saturating_add(Weight::from_ref_time(60_400).saturating_mul(s.into())) + // Minimum execution time: 44_744 nanoseconds. + Weight::from_ref_time(45_658_968) + // Standard Error: 692 + .saturating_add(Weight::from_ref_time(65_958).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -149,10 +149,10 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking SpanSlash (r:0 w:2) /// The range of component `s` is `[0, 100]`. fn withdraw_unbonded_kill(s: u32, ) -> Weight { - // Minimum execution time: 86_176 nanoseconds. - Weight::from_ref_time(91_591_693) - // Standard Error: 2_162 - .saturating_add(Weight::from_ref_time(1_089_160).saturating_mul(s.into())) + // Minimum execution time: 86_013 nanoseconds. + Weight::from_ref_time(91_544_236) + // Standard Error: 2_273 + .saturating_add(Weight::from_ref_time(1_073_291).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(13)) .saturating_add(T::DbWeight::get().writes(12)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) @@ -169,8 +169,8 @@ impl WeightInfo for SubstrateWeight { // Storage: VoterList CounterForListNodes (r:1 w:1) // Storage: Staking CounterForValidators (r:1 w:1) fn validate() -> Weight { - // Minimum execution time: 65_754 nanoseconds. - Weight::from_ref_time(66_793_000) + // Minimum execution time: 66_579 nanoseconds. + Weight::from_ref_time(67_026_000) .saturating_add(T::DbWeight::get().reads(11)) .saturating_add(T::DbWeight::get().writes(5)) } @@ -178,10 +178,10 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking Nominators (r:1 w:1) /// The range of component `k` is `[1, 128]`. fn kick(k: u32, ) -> Weight { - // Minimum execution time: 44_020 nanoseconds. - Weight::from_ref_time(41_692_773) - // Standard Error: 12_148 - .saturating_add(Weight::from_ref_time(7_092_259).saturating_mul(k.into())) + // Minimum execution time: 40_716 nanoseconds. + Weight::from_ref_time(43_678_932) + // Standard Error: 15_099 + .saturating_add(Weight::from_ref_time(6_814_991).saturating_mul(k.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(k.into()))) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(k.into()))) @@ -199,10 +199,10 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking CounterForNominators (r:1 w:1) /// The range of component `n` is `[1, 16]`. fn nominate(n: u32, ) -> Weight { - // Minimum execution time: 72_131 nanoseconds. - Weight::from_ref_time(71_703_530) - // Standard Error: 6_947 - .saturating_add(Weight::from_ref_time(2_757_165).saturating_mul(n.into())) + // Minimum execution time: 71_258 nanoseconds. + Weight::from_ref_time(70_901_125) + // Standard Error: 6_183 + .saturating_add(Weight::from_ref_time(2_777_341).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(12)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(6)) @@ -215,58 +215,58 @@ impl WeightInfo for SubstrateWeight { // Storage: VoterList ListBags (r:1 w:1) // Storage: VoterList CounterForListNodes (r:1 w:1) fn chill() -> Weight { - // Minimum execution time: 66_151 nanoseconds. - Weight::from_ref_time(66_596_000) + // Minimum execution time: 66_052 nanoseconds. + Weight::from_ref_time(66_480_000) .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(6)) } // Storage: Staking Ledger (r:1 w:0) // Storage: Staking Payee (r:0 w:1) fn set_payee() -> Weight { - // Minimum execution time: 17_305 nanoseconds. - Weight::from_ref_time(17_506_000) + // Minimum execution time: 18_008 nanoseconds. + Weight::from_ref_time(18_360_000) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } // Storage: Staking Bonded (r:1 w:1) // Storage: Staking Ledger (r:2 w:2) fn set_controller() -> Weight { - // Minimum execution time: 24_482 nanoseconds. - Weight::from_ref_time(25_101_000) + // Minimum execution time: 25_979 nanoseconds. + Weight::from_ref_time(26_350_000) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(3)) } // Storage: Staking ValidatorCount (r:0 w:1) fn set_validator_count() -> Weight { - // Minimum execution time: 5_100 nanoseconds. - Weight::from_ref_time(5_274_000) + // Minimum execution time: 5_009 nanoseconds. + Weight::from_ref_time(5_248_000) .saturating_add(T::DbWeight::get().writes(1)) } // Storage: Staking ForceEra (r:0 w:1) fn force_no_eras() -> Weight { - // Minimum execution time: 19_788 nanoseconds. - Weight::from_ref_time(20_313_000) + // Minimum execution time: 19_493 nanoseconds. + Weight::from_ref_time(19_888_000) .saturating_add(T::DbWeight::get().writes(1)) } // Storage: Staking ForceEra (r:0 w:1) fn force_new_era() -> Weight { - // Minimum execution time: 19_499 nanoseconds. - Weight::from_ref_time(19_987_000) + // Minimum execution time: 19_425 nanoseconds. + Weight::from_ref_time(19_991_000) .saturating_add(T::DbWeight::get().writes(1)) } // Storage: Staking ForceEra (r:0 w:1) fn force_new_era_always() -> Weight { - // Minimum execution time: 19_846 nanoseconds. - Weight::from_ref_time(20_127_000) + // Minimum execution time: 19_690 nanoseconds. + Weight::from_ref_time(20_010_000) .saturating_add(T::DbWeight::get().writes(1)) } // Storage: Staking Invulnerables (r:0 w:1) /// The range of component `v` is `[0, 1000]`. fn set_invulnerables(v: u32, ) -> Weight { - // Minimum execution time: 5_301 nanoseconds. - Weight::from_ref_time(6_147_935) - // Standard Error: 32 - .saturating_add(Weight::from_ref_time(10_076).saturating_mul(v.into())) + // Minimum execution time: 5_375 nanoseconds. + Weight::from_ref_time(6_217_068) + // Standard Error: 43 + .saturating_add(Weight::from_ref_time(9_885).saturating_mul(v.into())) .saturating_add(T::DbWeight::get().writes(1)) } // Storage: Staking Bonded (r:1 w:1) @@ -284,10 +284,10 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking SpanSlash (r:0 w:2) /// The range of component `s` is `[0, 100]`. fn force_unstake(s: u32, ) -> Weight { - // Minimum execution time: 79_381 nanoseconds. - Weight::from_ref_time(85_216_285) - // Standard Error: 2_681 - .saturating_add(Weight::from_ref_time(1_100_353).saturating_mul(s.into())) + // Minimum execution time: 79_630 nanoseconds. + Weight::from_ref_time(85_354_738) + // Standard Error: 2_555 + .saturating_add(Weight::from_ref_time(1_086_827).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(11)) .saturating_add(T::DbWeight::get().writes(12)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) @@ -295,10 +295,10 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking UnappliedSlashes (r:1 w:1) /// The range of component `s` is `[1, 1000]`. fn cancel_deferred_slash(s: u32, ) -> Weight { - // Minimum execution time: 92_049 nanoseconds. - Weight::from_ref_time(894_164_159) - // Standard Error: 58_104 - .saturating_add(Weight::from_ref_time(4_961_170).saturating_mul(s.into())) + // Minimum execution time: 92_209 nanoseconds. + Weight::from_ref_time(901_022_610) + // Standard Error: 59_320 + .saturating_add(Weight::from_ref_time(4_943_518).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -316,10 +316,10 @@ impl WeightInfo for SubstrateWeight { // Storage: System Account (r:1 w:1) /// The range of component `n` is `[0, 256]`. fn payout_stakers_dead_controller(n: u32, ) -> Weight { - // Minimum execution time: 134_548 nanoseconds. - Weight::from_ref_time(195_909_318) - // Standard Error: 17_825 - .saturating_add(Weight::from_ref_time(22_179_182).saturating_mul(n.into())) + // Minimum execution time: 134_323 nanoseconds. + Weight::from_ref_time(200_066_020) + // Standard Error: 16_654 + .saturating_add(Weight::from_ref_time(21_841_097).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(11)) .saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(3)) @@ -340,17 +340,36 @@ impl WeightInfo for SubstrateWeight { // Storage: Balances Locks (r:1 w:1) /// The range of component `n` is `[0, 256]`. fn payout_stakers_alive_staked(n: u32, ) -> Weight { - // Minimum execution time: 167_574 nanoseconds. - Weight::from_ref_time(232_044_473) - // Standard Error: 25_865 - .saturating_add(Weight::from_ref_time(31_272_789).saturating_mul(n.into())) + // Minimum execution time: 166_885 nanoseconds. + Weight::from_ref_time(231_648_127) + // Standard Error: 30_392 + .saturating_add(Weight::from_ref_time(30_760_443).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(12)) .saturating_add(T::DbWeight::get().reads((5_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(4)) .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(n.into()))) } - fn payout_stakers_nominators_only(n: u32, ) -> Weight { - Weight::from_ref_time(n.into()) + // Storage: Staking CurrentEra (r:1 w:0) + // Storage: Staking ErasStakersOverview (r:1 w:0) + // Storage: Staking ErasValidatorReward (r:1 w:0) + // Storage: Staking Bonded (r:2 w:0) + // Storage: Staking Ledger (r:2 w:2) + // Storage: Staking ClaimedRewards (r:1 w:1) + // Storage: Staking ErasStakersPaged (r:1 w:0) + // Storage: Staking ErasRewardPoints (r:1 w:0) + // Storage: Staking Payee (r:2 w:0) + // Storage: Balances Locks (r:2 w:2) + // Storage: System Account (r:2 w:2) + /// The range of component `n` is `[1, 256]`. + fn payout_stakers_nominators_only(n: u32, ) -> Weight { + // Minimum execution time: 272_243 nanoseconds. + Weight::from_ref_time(228_003_618) + // Standard Error: 35_442 + .saturating_add(Weight::from_ref_time(34_057_392).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(11)) + .saturating_add(T::DbWeight::get().reads((5_u64).saturating_mul(n.into()))) + .saturating_add(T::DbWeight::get().writes(4)) + .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(n.into()))) } // Storage: Staking Ledger (r:1 w:1) // Storage: Balances Locks (r:1 w:1) @@ -360,10 +379,10 @@ impl WeightInfo for SubstrateWeight { // Storage: VoterList ListBags (r:2 w:2) /// The range of component `l` is `[1, 32]`. fn rebond(l: u32, ) -> Weight { - // Minimum execution time: 91_739 nanoseconds. - Weight::from_ref_time(93_123_333) - // Standard Error: 3_580 - .saturating_add(Weight::from_ref_time(69_425).saturating_mul(l.into())) + // Minimum execution time: 92_462 nanoseconds. + Weight::from_ref_time(93_684_047) + // Standard Error: 2_000 + .saturating_add(Weight::from_ref_time(51_643).saturating_mul(l.into())) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(8)) } @@ -382,10 +401,10 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking SpanSlash (r:0 w:1) /// The range of component `s` is `[1, 100]`. fn reap_stash(s: u32, ) -> Weight { - // Minimum execution time: 90_792 nanoseconds. - Weight::from_ref_time(93_893_087) - // Standard Error: 4_158 - .saturating_add(Weight::from_ref_time(1_084_858).saturating_mul(s.into())) + // Minimum execution time: 92_003 nanoseconds. + Weight::from_ref_time(93_936_550) + // Standard Error: 2_091 + .saturating_add(Weight::from_ref_time(1_088_847).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(12)) .saturating_add(T::DbWeight::get().writes(12)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) @@ -411,12 +430,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `v` is `[1, 10]`. /// The range of component `n` is `[0, 100]`. fn new_era(v: u32, n: u32, ) -> Weight { - // Minimum execution time: 506_210 nanoseconds. - Weight::from_ref_time(508_476_000) - // Standard Error: 1_787_036 - .saturating_add(Weight::from_ref_time(60_417_557).saturating_mul(v.into())) - // Standard Error: 178_068 - .saturating_add(Weight::from_ref_time(13_499_037).saturating_mul(n.into())) + // Minimum execution time: 504_224 nanoseconds. + Weight::from_ref_time(506_290_000) + // Standard Error: 1_802_746 + .saturating_add(Weight::from_ref_time(60_725_475).saturating_mul(v.into())) + // Standard Error: 179_633 + .saturating_add(Weight::from_ref_time(13_820_500).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(206)) .saturating_add(T::DbWeight::get().reads((5_u64).saturating_mul(v.into()))) .saturating_add(T::DbWeight::get().reads((4_u64).saturating_mul(n.into()))) @@ -434,12 +453,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `v` is `[500, 1000]`. /// The range of component `n` is `[500, 1000]`. fn get_npos_voters(v: u32, n: u32, ) -> Weight { - // Minimum execution time: 24_070_794 nanoseconds. - Weight::from_ref_time(24_294_007_000) - // Standard Error: 322_618 - .saturating_add(Weight::from_ref_time(3_570_673).saturating_mul(v.into())) - // Standard Error: 322_618 - .saturating_add(Weight::from_ref_time(2_900_021).saturating_mul(n.into())) + // Minimum execution time: 24_224_895 nanoseconds. + Weight::from_ref_time(24_374_544_000) + // Standard Error: 319_103 + .saturating_add(Weight::from_ref_time(3_422_743).saturating_mul(v.into())) + // Standard Error: 319_103 + .saturating_add(Weight::from_ref_time(2_914_359).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(201)) .saturating_add(T::DbWeight::get().reads((5_u64).saturating_mul(v.into()))) .saturating_add(T::DbWeight::get().reads((4_u64).saturating_mul(n.into()))) @@ -449,10 +468,10 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking Validators (r:501 w:0) /// The range of component `v` is `[500, 1000]`. fn get_npos_targets(v: u32, ) -> Weight { - // Minimum execution time: 4_776_351 nanoseconds. - Weight::from_ref_time(4_849_553_000) - // Standard Error: 55_132 - .saturating_add(Weight::from_ref_time(3_604_980).saturating_mul(v.into())) + // Minimum execution time: 4_765_318 nanoseconds. + Weight::from_ref_time(4_816_708_000) + // Standard Error: 54_677 + .saturating_add(Weight::from_ref_time(3_541_818).saturating_mul(v.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(v.into()))) } @@ -463,8 +482,8 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking MaxNominatorsCount (r:0 w:1) // Storage: Staking MinNominatorBond (r:0 w:1) fn set_staking_configs_all_set() -> Weight { - // Minimum execution time: 10_781 nanoseconds. - Weight::from_ref_time(11_034_000) + // Minimum execution time: 10_480 nanoseconds. + Weight::from_ref_time(10_914_000) .saturating_add(T::DbWeight::get().writes(6)) } // Storage: Staking MinCommission (r:0 w:1) @@ -474,8 +493,8 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking MaxNominatorsCount (r:0 w:1) // Storage: Staking MinNominatorBond (r:0 w:1) fn set_staking_configs_all_remove() -> Weight { - // Minimum execution time: 9_418 nanoseconds. - Weight::from_ref_time(10_150_000) + // Minimum execution time: 9_529 nanoseconds. + Weight::from_ref_time(10_159_000) .saturating_add(T::DbWeight::get().writes(6)) } // Storage: Staking Ledger (r:1 w:0) @@ -489,23 +508,23 @@ impl WeightInfo for SubstrateWeight { // Storage: VoterList ListBags (r:1 w:1) // Storage: VoterList CounterForListNodes (r:1 w:1) fn chill_other() -> Weight { - // Minimum execution time: 82_590 nanoseconds. - Weight::from_ref_time(83_718_000) + // Minimum execution time: 81_347 nanoseconds. + Weight::from_ref_time(81_957_000) .saturating_add(T::DbWeight::get().reads(11)) .saturating_add(T::DbWeight::get().writes(6)) } // Storage: Staking MinCommission (r:1 w:0) // Storage: Staking Validators (r:1 w:1) fn force_apply_min_commission() -> Weight { - // Minimum execution time: 19_367 nanoseconds. - Weight::from_ref_time(19_668_000) + // Minimum execution time: 19_153 nanoseconds. + Weight::from_ref_time(19_621_000) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } // Storage: Staking MinCommission (r:0 w:1) fn set_min_commission() -> Weight { - // Minimum execution time: 6_107 nanoseconds. - Weight::from_ref_time(6_449_000) + // Minimum execution time: 6_058 nanoseconds. + Weight::from_ref_time(6_278_000) .saturating_add(T::DbWeight::get().writes(1)) } } @@ -517,8 +536,8 @@ impl WeightInfo for () { // Storage: Balances Locks (r:1 w:1) // Storage: Staking Payee (r:0 w:1) fn bond() -> Weight { - // Minimum execution time: 51_611 nanoseconds. - Weight::from_ref_time(52_566_000) + // Minimum execution time: 51_815 nanoseconds. + Weight::from_ref_time(52_367_000) .saturating_add(RocksDbWeight::get().reads(3)) .saturating_add(RocksDbWeight::get().writes(4)) } @@ -528,8 +547,8 @@ impl WeightInfo for () { // Storage: VoterList ListNodes (r:3 w:3) // Storage: VoterList ListBags (r:2 w:2) fn bond_extra() -> Weight { - // Minimum execution time: 92_297 nanoseconds. - Weight::from_ref_time(93_016_000) + // Minimum execution time: 91_792 nanoseconds. + Weight::from_ref_time(92_729_000) .saturating_add(RocksDbWeight::get().reads(8)) .saturating_add(RocksDbWeight::get().writes(7)) } @@ -543,8 +562,8 @@ impl WeightInfo for () { // Storage: Staking Bonded (r:1 w:0) // Storage: VoterList ListBags (r:2 w:2) fn unbond() -> Weight { - // Minimum execution time: 98_447 nanoseconds. - Weight::from_ref_time(99_317_000) + // Minimum execution time: 97_647 nanoseconds. + Weight::from_ref_time(98_731_000) .saturating_add(RocksDbWeight::get().reads(12)) .saturating_add(RocksDbWeight::get().writes(8)) } @@ -554,10 +573,10 @@ impl WeightInfo for () { // Storage: System Account (r:1 w:1) /// The range of component `s` is `[0, 100]`. fn withdraw_unbonded_update(s: u32, ) -> Weight { - // Minimum execution time: 45_142 nanoseconds. - Weight::from_ref_time(46_003_517) - // Standard Error: 564 - .saturating_add(Weight::from_ref_time(60_400).saturating_mul(s.into())) + // Minimum execution time: 44_744 nanoseconds. + Weight::from_ref_time(45_658_968) + // Standard Error: 692 + .saturating_add(Weight::from_ref_time(65_958).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(4)) .saturating_add(RocksDbWeight::get().writes(3)) } @@ -577,10 +596,10 @@ impl WeightInfo for () { // Storage: Staking SpanSlash (r:0 w:2) /// The range of component `s` is `[0, 100]`. fn withdraw_unbonded_kill(s: u32, ) -> Weight { - // Minimum execution time: 86_176 nanoseconds. - Weight::from_ref_time(91_591_693) - // Standard Error: 2_162 - .saturating_add(Weight::from_ref_time(1_089_160).saturating_mul(s.into())) + // Minimum execution time: 86_013 nanoseconds. + Weight::from_ref_time(91_544_236) + // Standard Error: 2_273 + .saturating_add(Weight::from_ref_time(1_073_291).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(13)) .saturating_add(RocksDbWeight::get().writes(12)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(s.into()))) @@ -597,8 +616,8 @@ impl WeightInfo for () { // Storage: VoterList CounterForListNodes (r:1 w:1) // Storage: Staking CounterForValidators (r:1 w:1) fn validate() -> Weight { - // Minimum execution time: 65_754 nanoseconds. - Weight::from_ref_time(66_793_000) + // Minimum execution time: 66_579 nanoseconds. + Weight::from_ref_time(67_026_000) .saturating_add(RocksDbWeight::get().reads(11)) .saturating_add(RocksDbWeight::get().writes(5)) } @@ -606,10 +625,10 @@ impl WeightInfo for () { // Storage: Staking Nominators (r:1 w:1) /// The range of component `k` is `[1, 128]`. fn kick(k: u32, ) -> Weight { - // Minimum execution time: 44_020 nanoseconds. - Weight::from_ref_time(41_692_773) - // Standard Error: 12_148 - .saturating_add(Weight::from_ref_time(7_092_259).saturating_mul(k.into())) + // Minimum execution time: 40_716 nanoseconds. + Weight::from_ref_time(43_678_932) + // Standard Error: 15_099 + .saturating_add(Weight::from_ref_time(6_814_991).saturating_mul(k.into())) .saturating_add(RocksDbWeight::get().reads(1)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(k.into()))) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(k.into()))) @@ -627,10 +646,10 @@ impl WeightInfo for () { // Storage: Staking CounterForNominators (r:1 w:1) /// The range of component `n` is `[1, 16]`. fn nominate(n: u32, ) -> Weight { - // Minimum execution time: 72_131 nanoseconds. - Weight::from_ref_time(71_703_530) - // Standard Error: 6_947 - .saturating_add(Weight::from_ref_time(2_757_165).saturating_mul(n.into())) + // Minimum execution time: 71_258 nanoseconds. + Weight::from_ref_time(70_901_125) + // Standard Error: 6_183 + .saturating_add(Weight::from_ref_time(2_777_341).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(12)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes(6)) @@ -643,58 +662,58 @@ impl WeightInfo for () { // Storage: VoterList ListBags (r:1 w:1) // Storage: VoterList CounterForListNodes (r:1 w:1) fn chill() -> Weight { - // Minimum execution time: 66_151 nanoseconds. - Weight::from_ref_time(66_596_000) + // Minimum execution time: 66_052 nanoseconds. + Weight::from_ref_time(66_480_000) .saturating_add(RocksDbWeight::get().reads(8)) .saturating_add(RocksDbWeight::get().writes(6)) } // Storage: Staking Ledger (r:1 w:0) // Storage: Staking Payee (r:0 w:1) fn set_payee() -> Weight { - // Minimum execution time: 17_305 nanoseconds. - Weight::from_ref_time(17_506_000) + // Minimum execution time: 18_008 nanoseconds. + Weight::from_ref_time(18_360_000) .saturating_add(RocksDbWeight::get().reads(1)) .saturating_add(RocksDbWeight::get().writes(1)) } // Storage: Staking Bonded (r:1 w:1) // Storage: Staking Ledger (r:2 w:2) fn set_controller() -> Weight { - // Minimum execution time: 24_482 nanoseconds. - Weight::from_ref_time(25_101_000) + // Minimum execution time: 25_979 nanoseconds. + Weight::from_ref_time(26_350_000) .saturating_add(RocksDbWeight::get().reads(3)) .saturating_add(RocksDbWeight::get().writes(3)) } // Storage: Staking ValidatorCount (r:0 w:1) fn set_validator_count() -> Weight { - // Minimum execution time: 5_100 nanoseconds. - Weight::from_ref_time(5_274_000) + // Minimum execution time: 5_009 nanoseconds. + Weight::from_ref_time(5_248_000) .saturating_add(RocksDbWeight::get().writes(1)) } // Storage: Staking ForceEra (r:0 w:1) fn force_no_eras() -> Weight { - // Minimum execution time: 19_788 nanoseconds. - Weight::from_ref_time(20_313_000) + // Minimum execution time: 19_493 nanoseconds. + Weight::from_ref_time(19_888_000) .saturating_add(RocksDbWeight::get().writes(1)) } // Storage: Staking ForceEra (r:0 w:1) fn force_new_era() -> Weight { - // Minimum execution time: 19_499 nanoseconds. - Weight::from_ref_time(19_987_000) + // Minimum execution time: 19_425 nanoseconds. + Weight::from_ref_time(19_991_000) .saturating_add(RocksDbWeight::get().writes(1)) } // Storage: Staking ForceEra (r:0 w:1) fn force_new_era_always() -> Weight { - // Minimum execution time: 19_846 nanoseconds. - Weight::from_ref_time(20_127_000) + // Minimum execution time: 19_690 nanoseconds. + Weight::from_ref_time(20_010_000) .saturating_add(RocksDbWeight::get().writes(1)) } // Storage: Staking Invulnerables (r:0 w:1) /// The range of component `v` is `[0, 1000]`. fn set_invulnerables(v: u32, ) -> Weight { - // Minimum execution time: 5_301 nanoseconds. - Weight::from_ref_time(6_147_935) - // Standard Error: 32 - .saturating_add(Weight::from_ref_time(10_076).saturating_mul(v.into())) + // Minimum execution time: 5_375 nanoseconds. + Weight::from_ref_time(6_217_068) + // Standard Error: 43 + .saturating_add(Weight::from_ref_time(9_885).saturating_mul(v.into())) .saturating_add(RocksDbWeight::get().writes(1)) } // Storage: Staking Bonded (r:1 w:1) @@ -712,10 +731,10 @@ impl WeightInfo for () { // Storage: Staking SpanSlash (r:0 w:2) /// The range of component `s` is `[0, 100]`. fn force_unstake(s: u32, ) -> Weight { - // Minimum execution time: 79_381 nanoseconds. - Weight::from_ref_time(85_216_285) - // Standard Error: 2_681 - .saturating_add(Weight::from_ref_time(1_100_353).saturating_mul(s.into())) + // Minimum execution time: 79_630 nanoseconds. + Weight::from_ref_time(85_354_738) + // Standard Error: 2_555 + .saturating_add(Weight::from_ref_time(1_086_827).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(11)) .saturating_add(RocksDbWeight::get().writes(12)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(s.into()))) @@ -723,10 +742,10 @@ impl WeightInfo for () { // Storage: Staking UnappliedSlashes (r:1 w:1) /// The range of component `s` is `[1, 1000]`. fn cancel_deferred_slash(s: u32, ) -> Weight { - // Minimum execution time: 92_049 nanoseconds. - Weight::from_ref_time(894_164_159) - // Standard Error: 58_104 - .saturating_add(Weight::from_ref_time(4_961_170).saturating_mul(s.into())) + // Minimum execution time: 92_209 nanoseconds. + Weight::from_ref_time(901_022_610) + // Standard Error: 59_320 + .saturating_add(Weight::from_ref_time(4_943_518).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(1)) .saturating_add(RocksDbWeight::get().writes(1)) } @@ -744,10 +763,10 @@ impl WeightInfo for () { // Storage: System Account (r:1 w:1) /// The range of component `n` is `[0, 256]`. fn payout_stakers_dead_controller(n: u32, ) -> Weight { - // Minimum execution time: 134_548 nanoseconds. - Weight::from_ref_time(195_909_318) - // Standard Error: 17_825 - .saturating_add(Weight::from_ref_time(22_179_182).saturating_mul(n.into())) + // Minimum execution time: 134_323 nanoseconds. + Weight::from_ref_time(200_066_020) + // Standard Error: 16_654 + .saturating_add(Weight::from_ref_time(21_841_097).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(11)) .saturating_add(RocksDbWeight::get().reads((3_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes(3)) @@ -768,18 +787,36 @@ impl WeightInfo for () { // Storage: Balances Locks (r:1 w:1) /// The range of component `n` is `[0, 256]`. fn payout_stakers_alive_staked(n: u32, ) -> Weight { - // Minimum execution time: 167_574 nanoseconds. - Weight::from_ref_time(232_044_473) - // Standard Error: 25_865 - .saturating_add(Weight::from_ref_time(31_272_789).saturating_mul(n.into())) + // Minimum execution time: 166_885 nanoseconds. + Weight::from_ref_time(231_648_127) + // Standard Error: 30_392 + .saturating_add(Weight::from_ref_time(30_760_443).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(12)) .saturating_add(RocksDbWeight::get().reads((5_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes(4)) .saturating_add(RocksDbWeight::get().writes((3_u64).saturating_mul(n.into()))) } - fn payout_stakers_nominators_only(n: u32, ) -> Weight { - // Minimum execution time: 164_719 nanoseconds. - Weight::from_ref_time(n.into()) + // Storage: Staking CurrentEra (r:1 w:0) + // Storage: Staking ErasStakersOverview (r:1 w:0) + // Storage: Staking ErasValidatorReward (r:1 w:0) + // Storage: Staking Bonded (r:2 w:0) + // Storage: Staking Ledger (r:2 w:2) + // Storage: Staking ClaimedRewards (r:1 w:1) + // Storage: Staking ErasStakersPaged (r:1 w:0) + // Storage: Staking ErasRewardPoints (r:1 w:0) + // Storage: Staking Payee (r:2 w:0) + // Storage: Balances Locks (r:2 w:2) + // Storage: System Account (r:2 w:2) + /// The range of component `n` is `[1, 256]`. + fn payout_stakers_nominators_only(n: u32, ) -> Weight { + // Minimum execution time: 272_243 nanoseconds. + Weight::from_ref_time(228_003_618) + // Standard Error: 35_442 + .saturating_add(Weight::from_ref_time(34_057_392).saturating_mul(n.into())) + .saturating_add(RocksDbWeight::get().reads(11)) + .saturating_add(RocksDbWeight::get().reads((5_u64).saturating_mul(n.into()))) + .saturating_add(RocksDbWeight::get().writes(4)) + .saturating_add(RocksDbWeight::get().writes((3_u64).saturating_mul(n.into()))) } // Storage: Staking Ledger (r:1 w:1) // Storage: Balances Locks (r:1 w:1) @@ -789,10 +826,10 @@ impl WeightInfo for () { // Storage: VoterList ListBags (r:2 w:2) /// The range of component `l` is `[1, 32]`. fn rebond(l: u32, ) -> Weight { - // Minimum execution time: 91_739 nanoseconds. - Weight::from_ref_time(93_123_333) - // Standard Error: 3_580 - .saturating_add(Weight::from_ref_time(69_425).saturating_mul(l.into())) + // Minimum execution time: 92_462 nanoseconds. + Weight::from_ref_time(93_684_047) + // Standard Error: 2_000 + .saturating_add(Weight::from_ref_time(51_643).saturating_mul(l.into())) .saturating_add(RocksDbWeight::get().reads(9)) .saturating_add(RocksDbWeight::get().writes(8)) } @@ -811,10 +848,10 @@ impl WeightInfo for () { // Storage: Staking SpanSlash (r:0 w:1) /// The range of component `s` is `[1, 100]`. fn reap_stash(s: u32, ) -> Weight { - // Minimum execution time: 90_792 nanoseconds. - Weight::from_ref_time(93_893_087) - // Standard Error: 4_158 - .saturating_add(Weight::from_ref_time(1_084_858).saturating_mul(s.into())) + // Minimum execution time: 92_003 nanoseconds. + Weight::from_ref_time(93_936_550) + // Standard Error: 2_091 + .saturating_add(Weight::from_ref_time(1_088_847).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(12)) .saturating_add(RocksDbWeight::get().writes(12)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(s.into()))) @@ -840,12 +877,12 @@ impl WeightInfo for () { /// The range of component `v` is `[1, 10]`. /// The range of component `n` is `[0, 100]`. fn new_era(v: u32, n: u32, ) -> Weight { - // Minimum execution time: 506_210 nanoseconds. - Weight::from_ref_time(508_476_000) - // Standard Error: 1_787_036 - .saturating_add(Weight::from_ref_time(60_417_557).saturating_mul(v.into())) - // Standard Error: 178_068 - .saturating_add(Weight::from_ref_time(13_499_037).saturating_mul(n.into())) + // Minimum execution time: 504_224 nanoseconds. + Weight::from_ref_time(506_290_000) + // Standard Error: 1_802_746 + .saturating_add(Weight::from_ref_time(60_725_475).saturating_mul(v.into())) + // Standard Error: 179_633 + .saturating_add(Weight::from_ref_time(13_820_500).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(206)) .saturating_add(RocksDbWeight::get().reads((5_u64).saturating_mul(v.into()))) .saturating_add(RocksDbWeight::get().reads((4_u64).saturating_mul(n.into()))) @@ -863,12 +900,12 @@ impl WeightInfo for () { /// The range of component `v` is `[500, 1000]`. /// The range of component `n` is `[500, 1000]`. fn get_npos_voters(v: u32, n: u32, ) -> Weight { - // Minimum execution time: 24_070_794 nanoseconds. - Weight::from_ref_time(24_294_007_000) - // Standard Error: 322_618 - .saturating_add(Weight::from_ref_time(3_570_673).saturating_mul(v.into())) - // Standard Error: 322_618 - .saturating_add(Weight::from_ref_time(2_900_021).saturating_mul(n.into())) + // Minimum execution time: 24_224_895 nanoseconds. + Weight::from_ref_time(24_374_544_000) + // Standard Error: 319_103 + .saturating_add(Weight::from_ref_time(3_422_743).saturating_mul(v.into())) + // Standard Error: 319_103 + .saturating_add(Weight::from_ref_time(2_914_359).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(201)) .saturating_add(RocksDbWeight::get().reads((5_u64).saturating_mul(v.into()))) .saturating_add(RocksDbWeight::get().reads((4_u64).saturating_mul(n.into()))) @@ -878,10 +915,10 @@ impl WeightInfo for () { // Storage: Staking Validators (r:501 w:0) /// The range of component `v` is `[500, 1000]`. fn get_npos_targets(v: u32, ) -> Weight { - // Minimum execution time: 4_776_351 nanoseconds. - Weight::from_ref_time(4_849_553_000) - // Standard Error: 55_132 - .saturating_add(Weight::from_ref_time(3_604_980).saturating_mul(v.into())) + // Minimum execution time: 4_765_318 nanoseconds. + Weight::from_ref_time(4_816_708_000) + // Standard Error: 54_677 + .saturating_add(Weight::from_ref_time(3_541_818).saturating_mul(v.into())) .saturating_add(RocksDbWeight::get().reads(2)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(v.into()))) } @@ -892,8 +929,8 @@ impl WeightInfo for () { // Storage: Staking MaxNominatorsCount (r:0 w:1) // Storage: Staking MinNominatorBond (r:0 w:1) fn set_staking_configs_all_set() -> Weight { - // Minimum execution time: 10_781 nanoseconds. - Weight::from_ref_time(11_034_000) + // Minimum execution time: 10_480 nanoseconds. + Weight::from_ref_time(10_914_000) .saturating_add(RocksDbWeight::get().writes(6)) } // Storage: Staking MinCommission (r:0 w:1) @@ -903,8 +940,8 @@ impl WeightInfo for () { // Storage: Staking MaxNominatorsCount (r:0 w:1) // Storage: Staking MinNominatorBond (r:0 w:1) fn set_staking_configs_all_remove() -> Weight { - // Minimum execution time: 9_418 nanoseconds. - Weight::from_ref_time(10_150_000) + // Minimum execution time: 9_529 nanoseconds. + Weight::from_ref_time(10_159_000) .saturating_add(RocksDbWeight::get().writes(6)) } // Storage: Staking Ledger (r:1 w:0) @@ -918,23 +955,23 @@ impl WeightInfo for () { // Storage: VoterList ListBags (r:1 w:1) // Storage: VoterList CounterForListNodes (r:1 w:1) fn chill_other() -> Weight { - // Minimum execution time: 82_590 nanoseconds. - Weight::from_ref_time(83_718_000) + // Minimum execution time: 81_347 nanoseconds. + Weight::from_ref_time(81_957_000) .saturating_add(RocksDbWeight::get().reads(11)) .saturating_add(RocksDbWeight::get().writes(6)) } // Storage: Staking MinCommission (r:1 w:0) // Storage: Staking Validators (r:1 w:1) fn force_apply_min_commission() -> Weight { - // Minimum execution time: 19_367 nanoseconds. - Weight::from_ref_time(19_668_000) + // Minimum execution time: 19_153 nanoseconds. + Weight::from_ref_time(19_621_000) .saturating_add(RocksDbWeight::get().reads(2)) .saturating_add(RocksDbWeight::get().writes(1)) } // Storage: Staking MinCommission (r:0 w:1) fn set_min_commission() -> Weight { - // Minimum execution time: 6_107 nanoseconds. - Weight::from_ref_time(6_449_000) + // Minimum execution time: 6_058 nanoseconds. + Weight::from_ref_time(6_278_000) .saturating_add(RocksDbWeight::get().writes(1)) } } From cf0654ba3d4c46f676f78900d5821257f812b12b Mon Sep 17 00:00:00 2001 From: Ankan Date: Tue, 24 Jan 2023 00:01:21 +0100 Subject: [PATCH 058/162] fix rust doc --- frame/staking/src/pallet/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index d4fec3c17cdca..bc236f82de24d 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -205,7 +205,7 @@ pub mod pallet { /// /// A reward payout is restricted to a maximum of `MaxNominatorRewardedPerPage` nominators /// in a single call. This used to limit the i/o cost for the nominator payout. - /// See [`payout_stakers`] for more details. + /// See call `payout_stakers` for more details. #[pallet::constant] type MaxNominatorRewardedPerPage: Get; From 94a6dd5f5bdbd1a60111953c7511a37a8a45464c Mon Sep 17 00:00:00 2001 From: Ankan Date: Wed, 25 Jan 2023 20:48:28 +0100 Subject: [PATCH 059/162] handles errors --- frame/staking/src/tests.rs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index d61e47063cfb8..8f78fd13ce7b3 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -4004,15 +4004,35 @@ fn payout_stakers_handles_basic_errors() { 0 )); + // can call page 1 + assert_ok!(Staking::payout_stakers( + RuntimeOrigin::signed(1337), + 11, + expected_last_reward_era, + 1 + )); + // Can't claim again assert_noop!( Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, expected_start_reward_era, 0), Error::::AlreadyClaimed.with_weight(err_weight) ); + assert_noop!( Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, expected_last_reward_era, 0), Error::::AlreadyClaimed.with_weight(err_weight) ); + + assert_noop!( + Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, expected_last_reward_era, 1), + Error::::AlreadyClaimed.with_weight(err_weight) + ); + + // invalid page + assert_noop!( + Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, expected_last_reward_era, 2), + Error::::InvalidPage.with_weight(err_weight) + ); }); } From e49d721a0b4c38dd45bc12ab2fb1a54912e88e5f Mon Sep 17 00:00:00 2001 From: Ankan Date: Wed, 25 Jan 2023 21:02:11 +0100 Subject: [PATCH 060/162] commission test --- frame/staking/src/pallet/mod.rs | 1 - frame/staking/src/tests.rs | 54 +++++++++++++++++++++++++++++++-- 2 files changed, 52 insertions(+), 3 deletions(-) diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index bc236f82de24d..77f22d3aebbf5 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -684,7 +684,6 @@ pub mod pallet { >::get(&era, validator).page_count.max(1) } - // TODO(ank4n) add commission should only be paid in page 0 test /// Returns validator commission for this era and page. pub(crate) fn get_validator_commission( era: EraIndex, diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index 8f78fd13ce7b3..cf4036a958786 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -3745,8 +3745,7 @@ fn test_nominators_are_rewarded_for_all_exposure_page() { #[test] fn test_multi_page_payout_stakers() { - // Test that payout_stakers work in general, including that only the top - // `T::MaxNominatorRewardedPerPage` nominators are rewarded. + // Test that payout_stakers work in general and that it pays the correct amount of reward. ExtBuilder::default().has_stakers(false).build_and_execute(|| { let balance = 1000; // Track the exposure of the validator and all nominators. @@ -4036,6 +4035,57 @@ fn payout_stakers_handles_basic_errors() { }); } +#[test] +fn test_commission_paid_only_once() { + ExtBuilder::default().has_stakers(false).build_and_execute(|| { + let balance = 1; + let commission = 50; + // Create a validator: + bond_validator(11, 10, balance); + assert_ok!(Staking::validate( + RuntimeOrigin::signed(10), + ValidatorPrefs { commission: Perbill::from_percent(commission), blocked: false } + )); + assert_eq!(Validators::::count(), 1); + + // Create nominators, targeting stash of validators + for i in 0..200 { + let bond_amount = balance + i as Balance; + bond_nominator(1000 + i, 100 + i, bond_amount, vec![11]); + } + + mock::start_active_era(1); + Staking::reward_by_ids(vec![(11, 1)]); + + // Since `MaxNominatorRewardedPerPage = 64`, there are four pages of validator exposure. + assert_eq!(EraInfo::::get_page_count(1, &11), 4); + + // compute and ensure the reward amount is greater than zero. + let payout = current_total_payout_for_duration(reward_time_per_era()); + mock::start_active_era(2); + + let controller_balance_before_p0_payout = Balances::free_balance(&10); + // Payout rewards for first exposure page + assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, 1, 0)); + + let controller_balance_after_p0_payout = Balances::free_balance(&10); + + // half of the payout goes to validator since commission is 50% + assert_eq_error_rate!( + controller_balance_after_p0_payout, + controller_balance_before_p0_payout + payout / 2, + 1, + ); + + for i in 1..4 { + assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, 1, i)); + // no reward paid to validator for pages other than 0 + Balances::free_balance(&10); + } + + }); +} + #[test] fn payout_stakers_handles_weight_refund() { // Note: this test relies on the assumption that `payout_stakers_alive_staked` is solely used by From 2f40eea6ceb0ea67948125ed73af712fde75261e Mon Sep 17 00:00:00 2001 From: Ankan Date: Wed, 25 Jan 2023 21:07:09 +0100 Subject: [PATCH 061/162] some things to discuss --- frame/staking/src/lib.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index 8024d3e3d37c9..3eb6d1fa9fdf2 100644 --- a/frame/staking/src/lib.rs +++ b/frame/staking/src/lib.rs @@ -803,6 +803,8 @@ pub struct ExposureOverview { pub nominator_count: u32, /// Number of pages of backers. pub page_count: PageIndex, + // TODO(ank4n): to discuss: should we keep a snapshot of validator commission for each era? + // Seems more fair to calculate rewards according to validator's commission at that era. } impl Default for ExposureOverview { From 455294b52637c8b4b29bd3fe1d734763009b7985 Mon Sep 17 00:00:00 2001 From: Ankan Date: Wed, 25 Jan 2023 21:26:54 +0100 Subject: [PATCH 062/162] try state checks --- frame/staking/src/pallet/impls.rs | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index 90a36dedfb906..312fb172d5a15 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -1722,9 +1722,12 @@ impl Pallet { fn check_exposures() -> Result<(), &'static str> { // a check per validator to ensure the exposure struct is always sane. + // FIXME(ank4n): This will fail before the code goes live, so probably add this change after + // being in production? Not sure how to test this nicely. Ideally could run it for a while + // on a test chain and make sure this is correct before going to production. let era = Self::active_era().unwrap().index; - ErasStakers::::iter_prefix_values(era) - .map(|expo| { + ErasStakers::::iter_prefix(era) + .map(|key, expo| { ensure!( expo.total == expo.own + @@ -1734,6 +1737,25 @@ impl Pallet { .fold(Zero::zero(), |acc, x| acc + x), "wrong total exposure.", ); + // look at exposure pages + let mut total = Zero::zero(); + let mut own = Zero::zero(); + let page_count = EraInfo::::get_page_count(era, key); + for page in 0..page_count { + let page = EraInfo::::get_page(era, key, page); + let paged_exposure = EraInfo::::get_validator_exposure(era, key, page); + ensure!(paged_exposure.total == expo.total, "wrong total exposure in page."); + own += paged_exposure.own; + total = paged_exposure.own + + paged_exposure + .others + .iter() + .map(|e| e.value) + .fold(Zero::zero(), |acc, x| acc + x); + } + ensure!(total == expo.total, "wrong total exposure in pages."); + ensure!(own == expo.own, "wrong own exposure in pages."); + Ok(()) }) .collect::>() From 4e2b48278ab3449971460a3333e702464aeb2975 Mon Sep 17 00:00:00 2001 From: Ankan Date: Wed, 25 Jan 2023 21:29:52 +0100 Subject: [PATCH 063/162] fmt --- frame/staking/src/tests.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index cf4036a958786..a05090c8ab2fd 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -4082,7 +4082,6 @@ fn test_commission_paid_only_once() { // no reward paid to validator for pages other than 0 Balances::free_balance(&10); } - }); } From 478b47395529cb1d34d174df8a9f4ac144ae988e Mon Sep 17 00:00:00 2001 From: Ankan Date: Wed, 25 Jan 2023 21:39:29 +0100 Subject: [PATCH 064/162] Revert "try state checks" This reverts commit 455294b52637c8b4b29bd3fe1d734763009b7985. --- frame/staking/src/pallet/impls.rs | 26 ++------------------------ 1 file changed, 2 insertions(+), 24 deletions(-) diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index 312fb172d5a15..90a36dedfb906 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -1722,12 +1722,9 @@ impl Pallet { fn check_exposures() -> Result<(), &'static str> { // a check per validator to ensure the exposure struct is always sane. - // FIXME(ank4n): This will fail before the code goes live, so probably add this change after - // being in production? Not sure how to test this nicely. Ideally could run it for a while - // on a test chain and make sure this is correct before going to production. let era = Self::active_era().unwrap().index; - ErasStakers::::iter_prefix(era) - .map(|key, expo| { + ErasStakers::::iter_prefix_values(era) + .map(|expo| { ensure!( expo.total == expo.own + @@ -1737,25 +1734,6 @@ impl Pallet { .fold(Zero::zero(), |acc, x| acc + x), "wrong total exposure.", ); - // look at exposure pages - let mut total = Zero::zero(); - let mut own = Zero::zero(); - let page_count = EraInfo::::get_page_count(era, key); - for page in 0..page_count { - let page = EraInfo::::get_page(era, key, page); - let paged_exposure = EraInfo::::get_validator_exposure(era, key, page); - ensure!(paged_exposure.total == expo.total, "wrong total exposure in page."); - own += paged_exposure.own; - total = paged_exposure.own + - paged_exposure - .others - .iter() - .map(|e| e.value) - .fold(Zero::zero(), |acc, x| acc + x); - } - ensure!(total == expo.total, "wrong total exposure in pages."); - ensure!(own == expo.own, "wrong own exposure in pages."); - Ok(()) }) .collect::>() From ddfcd188fdd15076c3773adf4f4b9330a969ac5f Mon Sep 17 00:00:00 2001 From: Ankan Date: Wed, 25 Jan 2023 21:46:01 +0100 Subject: [PATCH 065/162] cleanup era overview in history depth eras --- frame/staking/src/pallet/impls.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index 90a36dedfb906..8ac0b12eff194 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -676,6 +676,8 @@ impl Pallet { >::remove_prefix(era_index, None); #[allow(deprecated)] >::remove_prefix(era_index, None); + #[allow(deprecated)] + >::remove_prefix(era_index, None); >::remove(era_index); >::remove(era_index); From fed66ce040b52b6893067a166fc21f199e7c3337 Mon Sep 17 00:00:00 2001 From: Ankan Date: Sat, 28 Jan 2023 22:17:18 +0100 Subject: [PATCH 066/162] todos --- frame/staking/src/lib.rs | 2 - frame/staking/src/pallet/mod.rs | 1 + frame/staking/src/weights.rs | 1977 ++++++++++++------------------- 3 files changed, 735 insertions(+), 1245 deletions(-) diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index 3eb6d1fa9fdf2..8024d3e3d37c9 100644 --- a/frame/staking/src/lib.rs +++ b/frame/staking/src/lib.rs @@ -803,8 +803,6 @@ pub struct ExposureOverview { pub nominator_count: u32, /// Number of pages of backers. pub page_count: PageIndex, - // TODO(ank4n): to discuss: should we keep a snapshot of validator commission for each era? - // Seems more fair to calculate rewards according to validator's commission at that era. } impl Default for ExposureOverview { diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index 77f22d3aebbf5..c9220f672d949 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -206,6 +206,7 @@ pub mod pallet { /// A reward payout is restricted to a maximum of `MaxNominatorRewardedPerPage` nominators /// in a single call. This used to limit the i/o cost for the nominator payout. /// See call `payout_stakers` for more details. + /// // TODO(ank4n) keep old one and create new one. #[pallet::constant] type MaxNominatorRewardedPerPage: Get; diff --git a/frame/staking/src/weights.rs b/frame/staking/src/weights.rs index af2afa2b538d6..dea9175460e0a 100644 --- a/frame/staking/src/weights.rs +++ b/frame/staking/src/weights.rs @@ -18,25 +18,25 @@ //! Autogenerated weights for pallet_staking //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-01-25, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! DATE: 2023-01-23, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// ./target/production/substrate +// /home/benchbot/cargo_target_dir/production/substrate // benchmark // pallet -// --chain=dev // --steps=50 // --repeat=20 -// --pallet=pallet_staking // --extrinsic=* // --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=./frame/staking/src/weights.rs +// --json-file=/var/lib/gitlab-runner/builds/zyw4fam_/0/parity/mirrors/substrate/.git/.artifacts/bench.json +// --pallet=pallet_staking +// --chain=dev // --header=./HEADER-APACHE2 +// --output=./frame/staking/src/weights.rs // --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] @@ -68,6 +68,7 @@ pub trait WeightInfo { fn cancel_deferred_slash(s: u32, ) -> Weight; fn payout_stakers_dead_controller(n: u32, ) -> Weight; fn payout_stakers_alive_staked(n: u32, ) -> Weight; + fn payout_stakers_nominators_only(n: u32, ) -> Weight; fn rebond(l: u32, ) -> Weight; fn reap_stash(s: u32, ) -> Weight; fn new_era(v: u32, n: u32, ) -> Weight; @@ -83,1404 +84,894 @@ pub trait WeightInfo { /// Weights for pallet_staking using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - /// Storage: Staking Bonded (r:1 w:1) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: Staking Ledger (r:1 w:1) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: Staking CurrentEra (r:1 w:0) - /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Staking Payee (r:0 w:1) - /// Proof: Staking Payee (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) + // Storage: Staking Bonded (r:1 w:1) + // Storage: Staking Ledger (r:1 w:1) + // Storage: Balances Locks (r:1 w:1) + // Storage: Staking Payee (r:0 w:1) fn bond() -> Weight { - // Proof Size summary in bytes: - // Measured: `1079` - // Estimated: `10386` - // Minimum execution time: 40_015 nanoseconds. - Weight::from_parts(40_601_000, 10386) - .saturating_add(T::DbWeight::get().reads(4_u64)) - .saturating_add(T::DbWeight::get().writes(4_u64)) - } - /// Storage: Staking Bonded (r:1 w:0) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: Staking Ledger (r:1 w:1) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: VoterList ListNodes (r:3 w:3) - /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) - /// Storage: VoterList ListBags (r:2 w:2) - /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) + // Minimum execution time: 51_815 nanoseconds. + Weight::from_ref_time(52_367_000) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(4)) + } + // Storage: Staking Bonded (r:1 w:0) + // Storage: Staking Ledger (r:1 w:1) + // Storage: Balances Locks (r:1 w:1) + // Storage: VoterList ListNodes (r:3 w:3) + // Storage: VoterList ListBags (r:2 w:2) fn bond_extra() -> Weight { - // Proof Size summary in bytes: - // Measured: `2252` - // Estimated: `22888` - // Minimum execution time: 74_781 nanoseconds. - Weight::from_parts(75_188_000, 22888) - .saturating_add(T::DbWeight::get().reads(8_u64)) - .saturating_add(T::DbWeight::get().writes(7_u64)) - } - /// Storage: Staking Ledger (r:1 w:1) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: Staking Nominators (r:1 w:0) - /// Proof: Staking Nominators (max_values: None, max_size: Some(558), added: 3033, mode: MaxEncodedLen) - /// Storage: Staking MinNominatorBond (r:1 w:0) - /// Proof: Staking MinNominatorBond (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - /// Storage: Staking CurrentEra (r:1 w:0) - /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: VoterList ListNodes (r:3 w:3) - /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) - /// Storage: Staking Bonded (r:1 w:0) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: VoterList ListBags (r:2 w:2) - /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) + // Minimum execution time: 91_792 nanoseconds. + Weight::from_ref_time(92_729_000) + .saturating_add(T::DbWeight::get().reads(8)) + .saturating_add(T::DbWeight::get().writes(7)) + } + // Storage: Staking Ledger (r:1 w:1) + // Storage: Staking Nominators (r:1 w:0) + // Storage: Staking MinNominatorBond (r:1 w:0) + // Storage: Staking CurrentEra (r:1 w:0) + // Storage: Balances Locks (r:1 w:1) + // Storage: System Account (r:1 w:1) + // Storage: VoterList ListNodes (r:3 w:3) + // Storage: Staking Bonded (r:1 w:0) + // Storage: VoterList ListBags (r:2 w:2) fn unbond() -> Weight { - // Proof Size summary in bytes: - // Measured: `2457` - // Estimated: `29534` - // Minimum execution time: 81_299 nanoseconds. - Weight::from_parts(82_242_000, 29534) - .saturating_add(T::DbWeight::get().reads(12_u64)) - .saturating_add(T::DbWeight::get().writes(8_u64)) - } - /// Storage: Staking Ledger (r:1 w:1) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: Staking CurrentEra (r:1 w:0) - /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + // Minimum execution time: 97_647 nanoseconds. + Weight::from_ref_time(98_731_000) + .saturating_add(T::DbWeight::get().reads(12)) + .saturating_add(T::DbWeight::get().writes(8)) + } + // Storage: Staking Ledger (r:1 w:1) + // Storage: Staking CurrentEra (r:1 w:0) + // Storage: Balances Locks (r:1 w:1) + // Storage: System Account (r:1 w:1) /// The range of component `s` is `[0, 100]`. fn withdraw_unbonded_update(s: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `1085` - // Estimated: `10442` - // Minimum execution time: 31_479 nanoseconds. - Weight::from_parts(32_410_035, 10442) - // Standard Error: 313 - .saturating_add(Weight::from_ref_time(9_090).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(4_u64)) - .saturating_add(T::DbWeight::get().writes(3_u64)) - } - /// Storage: Staking Ledger (r:1 w:1) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: Staking CurrentEra (r:1 w:0) - /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking Bonded (r:1 w:1) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: Staking SlashingSpans (r:1 w:1) - /// Proof Skipped: Staking SlashingSpans (max_values: None, max_size: None, mode: Measured) - /// Storage: Staking Validators (r:1 w:0) - /// Proof: Staking Validators (max_values: None, max_size: Some(45), added: 2520, mode: MaxEncodedLen) - /// Storage: Staking Nominators (r:1 w:1) - /// Proof: Staking Nominators (max_values: None, max_size: Some(558), added: 3033, mode: MaxEncodedLen) - /// Storage: Staking CounterForNominators (r:1 w:1) - /// Proof: Staking CounterForNominators (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: VoterList ListNodes (r:2 w:2) - /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) - /// Storage: VoterList ListBags (r:1 w:1) - /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) - /// Storage: VoterList CounterForListNodes (r:1 w:1) - /// Proof: VoterList CounterForListNodes (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Staking Payee (r:0 w:1) - /// Proof: Staking Payee (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) - /// Storage: Staking SpanSlash (r:0 w:100) - /// Proof: Staking SpanSlash (max_values: None, max_size: Some(76), added: 2551, mode: MaxEncodedLen) + // Minimum execution time: 44_744 nanoseconds. + Weight::from_ref_time(45_658_968) + // Standard Error: 692 + .saturating_add(Weight::from_ref_time(65_958).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(3)) + } + // Storage: Staking Ledger (r:1 w:1) + // Storage: Staking CurrentEra (r:1 w:0) + // Storage: Staking Bonded (r:1 w:1) + // Storage: Staking SlashingSpans (r:1 w:0) + // Storage: Staking Validators (r:1 w:0) + // Storage: Staking Nominators (r:1 w:1) + // Storage: Staking CounterForNominators (r:1 w:1) + // Storage: VoterList ListNodes (r:2 w:2) + // Storage: VoterList ListBags (r:1 w:1) + // Storage: VoterList CounterForListNodes (r:1 w:1) + // Storage: System Account (r:1 w:1) + // Storage: Balances Locks (r:1 w:1) + // Storage: Staking Payee (r:0 w:1) + // Storage: Staking SpanSlash (r:0 w:2) /// The range of component `s` is `[0, 100]`. fn withdraw_unbonded_kill(s: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `2486 + s * (4 ±0)` - // Estimated: `32303 + s * (4 ±0)` - // Minimum execution time: 71_968 nanoseconds. - Weight::from_parts(76_631_804, 32303) - // Standard Error: 1_613 - .saturating_add(Weight::from_ref_time(1_058_968).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(13_u64)) - .saturating_add(T::DbWeight::get().writes(12_u64)) + // Minimum execution time: 86_013 nanoseconds. + Weight::from_ref_time(91_544_236) + // Standard Error: 2_273 + .saturating_add(Weight::from_ref_time(1_073_291).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(13)) + .saturating_add(T::DbWeight::get().writes(12)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) - .saturating_add(Weight::from_proof_size(4).saturating_mul(s.into())) } - /// Storage: Staking Ledger (r:1 w:0) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: Staking MinValidatorBond (r:1 w:0) - /// Proof: Staking MinValidatorBond (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - /// Storage: Staking MinCommission (r:1 w:0) - /// Proof: Staking MinCommission (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking Validators (r:1 w:1) - /// Proof: Staking Validators (max_values: None, max_size: Some(45), added: 2520, mode: MaxEncodedLen) - /// Storage: Staking MaxValidatorsCount (r:1 w:0) - /// Proof: Staking MaxValidatorsCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking Nominators (r:1 w:0) - /// Proof: Staking Nominators (max_values: None, max_size: Some(558), added: 3033, mode: MaxEncodedLen) - /// Storage: Staking Bonded (r:1 w:0) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: VoterList ListNodes (r:1 w:1) - /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) - /// Storage: VoterList ListBags (r:1 w:1) - /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) - /// Storage: VoterList CounterForListNodes (r:1 w:1) - /// Proof: VoterList CounterForListNodes (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking CounterForValidators (r:1 w:1) - /// Proof: Staking CounterForValidators (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + // Storage: Staking Ledger (r:1 w:0) + // Storage: Staking MinValidatorBond (r:1 w:0) + // Storage: Staking MinCommission (r:1 w:0) + // Storage: Staking Validators (r:1 w:1) + // Storage: Staking MaxValidatorsCount (r:1 w:0) + // Storage: Staking Nominators (r:1 w:0) + // Storage: Staking Bonded (r:1 w:0) + // Storage: VoterList ListNodes (r:1 w:1) + // Storage: VoterList ListBags (r:1 w:1) + // Storage: VoterList CounterForListNodes (r:1 w:1) + // Storage: Staking CounterForValidators (r:1 w:1) fn validate() -> Weight { - // Proof Size summary in bytes: - // Measured: `1446` - // Estimated: `19359` - // Minimum execution time: 51_963 nanoseconds. - Weight::from_parts(52_418_000, 19359) - .saturating_add(T::DbWeight::get().reads(11_u64)) - .saturating_add(T::DbWeight::get().writes(5_u64)) + // Minimum execution time: 66_579 nanoseconds. + Weight::from_ref_time(67_026_000) + .saturating_add(T::DbWeight::get().reads(11)) + .saturating_add(T::DbWeight::get().writes(5)) } - /// Storage: Staking Ledger (r:1 w:0) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: Staking Nominators (r:128 w:128) - /// Proof: Staking Nominators (max_values: None, max_size: Some(558), added: 3033, mode: MaxEncodedLen) + // Storage: Staking Ledger (r:1 w:0) + // Storage: Staking Nominators (r:1 w:1) /// The range of component `k` is `[1, 128]`. fn kick(k: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `1292 + k * (601 ±0)` - // Estimated: `3566 + k * (3033 ±0)` - // Minimum execution time: 25_685 nanoseconds. - Weight::from_parts(25_290_286, 3566) - // Standard Error: 5_164 - .saturating_add(Weight::from_ref_time(6_445_608).saturating_mul(k.into())) - .saturating_add(T::DbWeight::get().reads(1_u64)) + // Minimum execution time: 40_716 nanoseconds. + Weight::from_ref_time(43_678_932) + // Standard Error: 15_099 + .saturating_add(Weight::from_ref_time(6_814_991).saturating_mul(k.into())) + .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(k.into()))) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(k.into()))) - .saturating_add(Weight::from_proof_size(3033).saturating_mul(k.into())) } - /// Storage: Staking Ledger (r:1 w:0) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: Staking MinNominatorBond (r:1 w:0) - /// Proof: Staking MinNominatorBond (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - /// Storage: Staking Nominators (r:1 w:1) - /// Proof: Staking Nominators (max_values: None, max_size: Some(558), added: 3033, mode: MaxEncodedLen) - /// Storage: Staking MaxNominatorsCount (r:1 w:0) - /// Proof: Staking MaxNominatorsCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking Validators (r:17 w:0) - /// Proof: Staking Validators (max_values: None, max_size: Some(45), added: 2520, mode: MaxEncodedLen) - /// Storage: Staking CurrentEra (r:1 w:0) - /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking Bonded (r:1 w:0) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: VoterList ListNodes (r:2 w:2) - /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) - /// Storage: VoterList ListBags (r:1 w:1) - /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) - /// Storage: VoterList CounterForListNodes (r:1 w:1) - /// Proof: VoterList CounterForListNodes (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking CounterForNominators (r:1 w:1) - /// Proof: Staking CounterForNominators (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + // Storage: Staking Ledger (r:1 w:0) + // Storage: Staking MinNominatorBond (r:1 w:0) + // Storage: Staking Nominators (r:1 w:1) + // Storage: Staking MaxNominatorsCount (r:1 w:0) + // Storage: Staking Validators (r:2 w:0) + // Storage: Staking CurrentEra (r:1 w:0) + // Storage: Staking Bonded (r:1 w:0) + // Storage: VoterList ListNodes (r:2 w:2) + // Storage: VoterList ListBags (r:1 w:1) + // Storage: VoterList CounterForListNodes (r:1 w:1) + // Storage: Staking CounterForNominators (r:1 w:1) /// The range of component `n` is `[1, 16]`. fn nominate(n: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `1984 + n * (105 ±0)` - // Estimated: `21988 + n * (2520 ±0)` - // Minimum execution time: 59_542 nanoseconds. - Weight::from_parts(57_558_678, 21988) - // Standard Error: 10_364 - .saturating_add(Weight::from_ref_time(2_759_713).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(12_u64)) + // Minimum execution time: 71_258 nanoseconds. + Weight::from_ref_time(70_901_125) + // Standard Error: 6_183 + .saturating_add(Weight::from_ref_time(2_777_341).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(12)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) - .saturating_add(T::DbWeight::get().writes(6_u64)) - .saturating_add(Weight::from_proof_size(2520).saturating_mul(n.into())) - } - /// Storage: Staking Ledger (r:1 w:0) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: Staking Validators (r:1 w:0) - /// Proof: Staking Validators (max_values: None, max_size: Some(45), added: 2520, mode: MaxEncodedLen) - /// Storage: Staking Nominators (r:1 w:1) - /// Proof: Staking Nominators (max_values: None, max_size: Some(558), added: 3033, mode: MaxEncodedLen) - /// Storage: Staking CounterForNominators (r:1 w:1) - /// Proof: Staking CounterForNominators (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: VoterList ListNodes (r:2 w:2) - /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) - /// Storage: VoterList ListBags (r:1 w:1) - /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) - /// Storage: VoterList CounterForListNodes (r:1 w:1) - /// Proof: VoterList CounterForListNodes (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + .saturating_add(T::DbWeight::get().writes(6)) + } + // Storage: Staking Ledger (r:1 w:0) + // Storage: Staking Validators (r:1 w:0) + // Storage: Staking Nominators (r:1 w:1) + // Storage: Staking CounterForNominators (r:1 w:1) + // Storage: VoterList ListNodes (r:2 w:2) + // Storage: VoterList ListBags (r:1 w:1) + // Storage: VoterList CounterForListNodes (r:1 w:1) fn chill() -> Weight { - // Proof Size summary in bytes: - // Measured: `1876` - // Estimated: `17932` - // Minimum execution time: 52_132 nanoseconds. - Weight::from_parts(52_648_000, 17932) - .saturating_add(T::DbWeight::get().reads(8_u64)) - .saturating_add(T::DbWeight::get().writes(6_u64)) + // Minimum execution time: 66_052 nanoseconds. + Weight::from_ref_time(66_480_000) + .saturating_add(T::DbWeight::get().reads(8)) + .saturating_add(T::DbWeight::get().writes(6)) } - /// Storage: Staking Ledger (r:1 w:0) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: Staking Payee (r:0 w:1) - /// Proof: Staking Payee (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) + // Storage: Staking Ledger (r:1 w:0) + // Storage: Staking Payee (r:0 w:1) fn set_payee() -> Weight { - // Proof Size summary in bytes: - // Measured: `840` - // Estimated: `3566` - // Minimum execution time: 13_399 nanoseconds. - Weight::from_parts(13_567_000, 3566) - .saturating_add(T::DbWeight::get().reads(1_u64)) - .saturating_add(T::DbWeight::get().writes(1_u64)) + // Minimum execution time: 18_008 nanoseconds. + Weight::from_ref_time(18_360_000) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: Staking Bonded (r:1 w:1) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: Staking Ledger (r:2 w:2) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) + // Storage: Staking Bonded (r:1 w:1) + // Storage: Staking Ledger (r:2 w:2) fn set_controller() -> Weight { - // Proof Size summary in bytes: - // Measured: `939` - // Estimated: `9679` - // Minimum execution time: 20_425 nanoseconds. - Weight::from_parts(20_713_000, 9679) - .saturating_add(T::DbWeight::get().reads(3_u64)) - .saturating_add(T::DbWeight::get().writes(3_u64)) + // Minimum execution time: 25_979 nanoseconds. + Weight::from_ref_time(26_350_000) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(3)) } - /// Storage: Staking ValidatorCount (r:0 w:1) - /// Proof: Staking ValidatorCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + // Storage: Staking ValidatorCount (r:0 w:1) fn set_validator_count() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 3_069 nanoseconds. - Weight::from_ref_time(3_176_000) - .saturating_add(T::DbWeight::get().writes(1_u64)) + // Minimum execution time: 5_009 nanoseconds. + Weight::from_ref_time(5_248_000) + .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: Staking ForceEra (r:0 w:1) - /// Proof: Staking ForceEra (max_values: Some(1), max_size: Some(1), added: 496, mode: MaxEncodedLen) + // Storage: Staking ForceEra (r:0 w:1) fn force_no_eras() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 11_386 nanoseconds. - Weight::from_ref_time(11_672_000) - .saturating_add(T::DbWeight::get().writes(1_u64)) + // Minimum execution time: 19_493 nanoseconds. + Weight::from_ref_time(19_888_000) + .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: Staking ForceEra (r:0 w:1) - /// Proof: Staking ForceEra (max_values: Some(1), max_size: Some(1), added: 496, mode: MaxEncodedLen) + // Storage: Staking ForceEra (r:0 w:1) fn force_new_era() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 11_591 nanoseconds. - Weight::from_ref_time(11_799_000) - .saturating_add(T::DbWeight::get().writes(1_u64)) + // Minimum execution time: 19_425 nanoseconds. + Weight::from_ref_time(19_991_000) + .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: Staking ForceEra (r:0 w:1) - /// Proof: Staking ForceEra (max_values: Some(1), max_size: Some(1), added: 496, mode: MaxEncodedLen) + // Storage: Staking ForceEra (r:0 w:1) fn force_new_era_always() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 11_553 nanoseconds. - Weight::from_ref_time(11_871_000) - .saturating_add(T::DbWeight::get().writes(1_u64)) + // Minimum execution time: 19_690 nanoseconds. + Weight::from_ref_time(20_010_000) + .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: Staking Invulnerables (r:0 w:1) - /// Proof Skipped: Staking Invulnerables (max_values: Some(1), max_size: None, mode: Measured) + // Storage: Staking Invulnerables (r:0 w:1) /// The range of component `v` is `[0, 1000]`. fn set_invulnerables(v: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 3_292 nanoseconds. - Weight::from_ref_time(3_754_352) - // Standard Error: 40 - .saturating_add(Weight::from_ref_time(9_838).saturating_mul(v.into())) - .saturating_add(T::DbWeight::get().writes(1_u64)) - } - /// Storage: Staking Bonded (r:1 w:1) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: Staking SlashingSpans (r:1 w:1) - /// Proof Skipped: Staking SlashingSpans (max_values: None, max_size: None, mode: Measured) - /// Storage: Staking Validators (r:1 w:0) - /// Proof: Staking Validators (max_values: None, max_size: Some(45), added: 2520, mode: MaxEncodedLen) - /// Storage: Staking Nominators (r:1 w:1) - /// Proof: Staking Nominators (max_values: None, max_size: Some(558), added: 3033, mode: MaxEncodedLen) - /// Storage: Staking CounterForNominators (r:1 w:1) - /// Proof: Staking CounterForNominators (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: VoterList ListNodes (r:2 w:2) - /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) - /// Storage: VoterList ListBags (r:1 w:1) - /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) - /// Storage: VoterList CounterForListNodes (r:1 w:1) - /// Proof: VoterList CounterForListNodes (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Staking Ledger (r:0 w:1) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: Staking Payee (r:0 w:1) - /// Proof: Staking Payee (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) - /// Storage: Staking SpanSlash (r:0 w:100) - /// Proof: Staking SpanSlash (max_values: None, max_size: Some(76), added: 2551, mode: MaxEncodedLen) + // Minimum execution time: 5_375 nanoseconds. + Weight::from_ref_time(6_217_068) + // Standard Error: 43 + .saturating_add(Weight::from_ref_time(9_885).saturating_mul(v.into())) + .saturating_add(T::DbWeight::get().writes(1)) + } + // Storage: Staking Bonded (r:1 w:1) + // Storage: Staking SlashingSpans (r:1 w:0) + // Storage: Staking Validators (r:1 w:0) + // Storage: Staking Nominators (r:1 w:1) + // Storage: Staking CounterForNominators (r:1 w:1) + // Storage: VoterList ListNodes (r:2 w:2) + // Storage: VoterList ListBags (r:1 w:1) + // Storage: VoterList CounterForListNodes (r:1 w:1) + // Storage: System Account (r:1 w:1) + // Storage: Balances Locks (r:1 w:1) + // Storage: Staking Ledger (r:0 w:1) + // Storage: Staking Payee (r:0 w:1) + // Storage: Staking SpanSlash (r:0 w:2) /// The range of component `s` is `[0, 100]`. fn force_unstake(s: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `2178 + s * (4 ±0)` - // Estimated: `27930 + s * (4 ±0)` - // Minimum execution time: 65_307 nanoseconds. - Weight::from_parts(70_227_980, 27930) - // Standard Error: 2_113 - .saturating_add(Weight::from_ref_time(1_059_856).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(11_u64)) - .saturating_add(T::DbWeight::get().writes(12_u64)) + // Minimum execution time: 79_630 nanoseconds. + Weight::from_ref_time(85_354_738) + // Standard Error: 2_555 + .saturating_add(Weight::from_ref_time(1_086_827).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(11)) + .saturating_add(T::DbWeight::get().writes(12)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) - .saturating_add(Weight::from_proof_size(4).saturating_mul(s.into())) } - /// Storage: Staking UnappliedSlashes (r:1 w:1) - /// Proof Skipped: Staking UnappliedSlashes (max_values: None, max_size: None, mode: Measured) + // Storage: Staking UnappliedSlashes (r:1 w:1) /// The range of component `s` is `[1, 1000]`. fn cancel_deferred_slash(s: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `66671` - // Estimated: `69146` - // Minimum execution time: 89_123 nanoseconds. - Weight::from_parts(890_989_741, 69146) - // Standard Error: 58_282 - .saturating_add(Weight::from_ref_time(4_920_413).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(1_u64)) - .saturating_add(T::DbWeight::get().writes(1_u64)) - } - /// Storage: Staking CurrentEra (r:1 w:0) - /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking ErasValidatorReward (r:1 w:0) - /// Proof: Staking ErasValidatorReward (max_values: None, max_size: Some(28), added: 2503, mode: MaxEncodedLen) - /// Storage: Staking Bonded (r:257 w:0) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: Staking Ledger (r:1 w:1) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: Staking ErasStakersClipped (r:1 w:0) - /// Proof Skipped: Staking ErasStakersClipped (max_values: None, max_size: None, mode: Measured) - /// Storage: Staking ErasRewardPoints (r:1 w:0) - /// Proof Skipped: Staking ErasRewardPoints (max_values: None, max_size: None, mode: Measured) - /// Storage: Staking ErasValidatorPrefs (r:1 w:0) - /// Proof: Staking ErasValidatorPrefs (max_values: None, max_size: Some(57), added: 2532, mode: MaxEncodedLen) - /// Storage: Staking Payee (r:257 w:0) - /// Proof: Staking Payee (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) - /// Storage: System Account (r:257 w:257) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + // Minimum execution time: 92_209 nanoseconds. + Weight::from_ref_time(901_022_610) + // Standard Error: 59_320 + .saturating_add(Weight::from_ref_time(4_943_518).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + // Storage: Staking CurrentEra (r:1 w:0) + // Storage: Staking ErasStakersOverview (r:1 w:0) + // Storage: Staking ErasValidatorReward (r:1 w:0) + // Storage: Staking Bonded (r:1 w:0) + // Storage: Staking Ledger (r:1 w:1) + // Storage: Staking ClaimedRewards (r:1 w:1) + // Storage: Staking ErasStakersPaged (r:1 w:0) + // Storage: Staking ErasStakersClipped (r:1 w:0) + // Storage: Staking ErasRewardPoints (r:1 w:0) + // Storage: Staking ErasValidatorPrefs (r:1 w:0) + // Storage: Staking Payee (r:1 w:0) + // Storage: System Account (r:1 w:1) /// The range of component `n` is `[0, 256]`. fn payout_stakers_dead_controller(n: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `20345 + n * (143 ±0)` - // Estimated: `54756 + n * (8024 ±1)` - // Minimum execution time: 73_652 nanoseconds. - Weight::from_parts(127_839_483, 54756) - // Standard Error: 14_195 - .saturating_add(Weight::from_ref_time(21_932_079).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(9_u64)) + // Minimum execution time: 134_323 nanoseconds. + Weight::from_ref_time(200_066_020) + // Standard Error: 16_654 + .saturating_add(Weight::from_ref_time(21_841_097).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(11)) .saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(n.into()))) - .saturating_add(T::DbWeight::get().writes(2_u64)) + .saturating_add(T::DbWeight::get().writes(3)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(n.into()))) - .saturating_add(Weight::from_proof_size(8024).saturating_mul(n.into())) } - /// Storage: Staking CurrentEra (r:1 w:0) - /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking ErasValidatorReward (r:1 w:0) - /// Proof: Staking ErasValidatorReward (max_values: None, max_size: Some(28), added: 2503, mode: MaxEncodedLen) - /// Storage: Staking Bonded (r:257 w:0) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: Staking Ledger (r:257 w:257) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: Staking ErasStakersClipped (r:1 w:0) - /// Proof Skipped: Staking ErasStakersClipped (max_values: None, max_size: None, mode: Measured) - /// Storage: Staking ErasRewardPoints (r:1 w:0) - /// Proof Skipped: Staking ErasRewardPoints (max_values: None, max_size: None, mode: Measured) - /// Storage: Staking ErasValidatorPrefs (r:1 w:0) - /// Proof: Staking ErasValidatorPrefs (max_values: None, max_size: Some(57), added: 2532, mode: MaxEncodedLen) - /// Storage: Staking Payee (r:257 w:0) - /// Proof: Staking Payee (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) - /// Storage: System Account (r:257 w:257) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:257 w:257) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + // Storage: Staking CurrentEra (r:1 w:0) + // Storage: Staking ErasStakersOverview (r:1 w:0) + // Storage: Staking ErasValidatorReward (r:1 w:0) + // Storage: Staking Bonded (r:1 w:0) + // Storage: Staking Ledger (r:1 w:1) + // Storage: Staking ClaimedRewards (r:1 w:1) + // Storage: Staking ErasStakersPaged (r:1 w:0) + // Storage: Staking ErasStakersClipped (r:1 w:0) + // Storage: Staking ErasRewardPoints (r:1 w:0) + // Storage: Staking ErasValidatorPrefs (r:1 w:0) + // Storage: Staking Payee (r:1 w:0) + // Storage: System Account (r:1 w:1) + // Storage: Balances Locks (r:1 w:1) /// The range of component `n` is `[0, 256]`. fn payout_stakers_alive_staked(n: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `35099 + n * (465 ±0)` - // Estimated: `83594 + n * (16026 ±0)` - // Minimum execution time: 94_560 nanoseconds. - Weight::from_parts(154_033_219, 83594) - // Standard Error: 26_663 - .saturating_add(Weight::from_ref_time(31_269_223).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(10_u64)) + // Minimum execution time: 166_885 nanoseconds. + Weight::from_ref_time(231_648_127) + // Standard Error: 30_392 + .saturating_add(Weight::from_ref_time(30_760_443).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(12)) .saturating_add(T::DbWeight::get().reads((5_u64).saturating_mul(n.into()))) - .saturating_add(T::DbWeight::get().writes(3_u64)) + .saturating_add(T::DbWeight::get().writes(4)) .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(n.into()))) - .saturating_add(Weight::from_proof_size(16026).saturating_mul(n.into())) } - /// Storage: Staking Ledger (r:1 w:1) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: VoterList ListNodes (r:3 w:3) - /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) - /// Storage: Staking Bonded (r:1 w:0) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: VoterList ListBags (r:2 w:2) - /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) + // Storage: Staking CurrentEra (r:1 w:0) + // Storage: Staking ErasStakersOverview (r:1 w:0) + // Storage: Staking ErasValidatorReward (r:1 w:0) + // Storage: Staking Bonded (r:2 w:0) + // Storage: Staking Ledger (r:2 w:2) + // Storage: Staking ClaimedRewards (r:1 w:1) + // Storage: Staking ErasStakersPaged (r:1 w:0) + // Storage: Staking ErasRewardPoints (r:1 w:0) + // Storage: Staking Payee (r:2 w:0) + // Storage: Balances Locks (r:2 w:2) + // Storage: System Account (r:2 w:2) + /// The range of component `n` is `[1, 256]`. + fn payout_stakers_nominators_only(n: u32, ) -> Weight { + // Minimum execution time: 272_243 nanoseconds. + Weight::from_ref_time(228_003_618) + // Standard Error: 35_442 + .saturating_add(Weight::from_ref_time(34_057_392).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(11)) + .saturating_add(T::DbWeight::get().reads((5_u64).saturating_mul(n.into()))) + .saturating_add(T::DbWeight::get().writes(4)) + .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(n.into()))) + } + // Storage: Staking Ledger (r:1 w:1) + // Storage: Balances Locks (r:1 w:1) + // Storage: System Account (r:1 w:1) + // Storage: VoterList ListNodes (r:3 w:3) + // Storage: Staking Bonded (r:1 w:0) + // Storage: VoterList ListBags (r:2 w:2) /// The range of component `l` is `[1, 32]`. fn rebond(l: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `2253 + l * (7 ±0)` - // Estimated: `25491` - // Minimum execution time: 74_764 nanoseconds. - Weight::from_parts(75_814_067, 25491) - // Standard Error: 1_217 - .saturating_add(Weight::from_ref_time(64_725).saturating_mul(l.into())) - .saturating_add(T::DbWeight::get().reads(9_u64)) - .saturating_add(T::DbWeight::get().writes(8_u64)) - } - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: Staking Bonded (r:1 w:1) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: Staking Ledger (r:1 w:1) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: Staking SlashingSpans (r:1 w:1) - /// Proof Skipped: Staking SlashingSpans (max_values: None, max_size: None, mode: Measured) - /// Storage: Staking Validators (r:1 w:0) - /// Proof: Staking Validators (max_values: None, max_size: Some(45), added: 2520, mode: MaxEncodedLen) - /// Storage: Staking Nominators (r:1 w:1) - /// Proof: Staking Nominators (max_values: None, max_size: Some(558), added: 3033, mode: MaxEncodedLen) - /// Storage: Staking CounterForNominators (r:1 w:1) - /// Proof: Staking CounterForNominators (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: VoterList ListNodes (r:2 w:2) - /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) - /// Storage: VoterList ListBags (r:1 w:1) - /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) - /// Storage: VoterList CounterForListNodes (r:1 w:1) - /// Proof: VoterList CounterForListNodes (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Staking Payee (r:0 w:1) - /// Proof: Staking Payee (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) - /// Storage: Staking SpanSlash (r:0 w:100) - /// Proof: Staking SpanSlash (max_values: None, max_size: Some(76), added: 2551, mode: MaxEncodedLen) + // Minimum execution time: 92_462 nanoseconds. + Weight::from_ref_time(93_684_047) + // Standard Error: 2_000 + .saturating_add(Weight::from_ref_time(51_643).saturating_mul(l.into())) + .saturating_add(T::DbWeight::get().reads(9)) + .saturating_add(T::DbWeight::get().writes(8)) + } + // Storage: System Account (r:1 w:1) + // Storage: Staking Bonded (r:1 w:1) + // Storage: Staking Ledger (r:1 w:1) + // Storage: Staking SlashingSpans (r:1 w:1) + // Storage: Staking Validators (r:1 w:0) + // Storage: Staking Nominators (r:1 w:1) + // Storage: Staking CounterForNominators (r:1 w:1) + // Storage: VoterList ListNodes (r:2 w:2) + // Storage: VoterList ListBags (r:1 w:1) + // Storage: VoterList CounterForListNodes (r:1 w:1) + // Storage: Balances Locks (r:1 w:1) + // Storage: Staking Payee (r:0 w:1) + // Storage: Staking SpanSlash (r:0 w:1) /// The range of component `s` is `[1, 100]`. fn reap_stash(s: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `2486 + s * (4 ±0)` - // Estimated: `31810 + s * (4 ±0)` - // Minimum execution time: 77_611 nanoseconds. - Weight::from_parts(79_760_034, 31810) - // Standard Error: 1_597 - .saturating_add(Weight::from_ref_time(1_039_268).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(12_u64)) - .saturating_add(T::DbWeight::get().writes(12_u64)) + // Minimum execution time: 92_003 nanoseconds. + Weight::from_ref_time(93_936_550) + // Standard Error: 2_091 + .saturating_add(Weight::from_ref_time(1_088_847).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(12)) + .saturating_add(T::DbWeight::get().writes(12)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) - .saturating_add(Weight::from_proof_size(4).saturating_mul(s.into())) } - /// Storage: VoterList CounterForListNodes (r:1 w:0) - /// Proof: VoterList CounterForListNodes (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: VoterList ListBags (r:200 w:0) - /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) - /// Storage: VoterList ListNodes (r:110 w:0) - /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) - /// Storage: Staking Nominators (r:110 w:0) - /// Proof: Staking Nominators (max_values: None, max_size: Some(558), added: 3033, mode: MaxEncodedLen) - /// Storage: Staking Validators (r:11 w:0) - /// Proof: Staking Validators (max_values: None, max_size: Some(45), added: 2520, mode: MaxEncodedLen) - /// Storage: Staking Bonded (r:110 w:0) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: Staking Ledger (r:110 w:0) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: Staking CounterForValidators (r:1 w:0) - /// Proof: Staking CounterForValidators (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking ValidatorCount (r:1 w:0) - /// Proof: Staking ValidatorCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking MinimumValidatorCount (r:1 w:0) - /// Proof: Staking MinimumValidatorCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking CurrentEra (r:1 w:1) - /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking ErasStakersClipped (r:0 w:10) - /// Proof Skipped: Staking ErasStakersClipped (max_values: None, max_size: None, mode: Measured) - /// Storage: Staking ErasValidatorPrefs (r:0 w:10) - /// Proof: Staking ErasValidatorPrefs (max_values: None, max_size: Some(57), added: 2532, mode: MaxEncodedLen) - /// Storage: Staking ErasStakers (r:0 w:10) - /// Proof Skipped: Staking ErasStakers (max_values: None, max_size: None, mode: Measured) - /// Storage: Staking ErasTotalStake (r:0 w:1) - /// Proof: Staking ErasTotalStake (max_values: None, max_size: Some(28), added: 2503, mode: MaxEncodedLen) - /// Storage: Staking ErasStartSessionIndex (r:0 w:1) - /// Proof: Staking ErasStartSessionIndex (max_values: None, max_size: Some(16), added: 2491, mode: MaxEncodedLen) - /// Storage: Staking MinimumActiveStake (r:0 w:1) - /// Proof: Staking MinimumActiveStake (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) + // Storage: VoterList CounterForListNodes (r:1 w:0) + // Storage: VoterList ListBags (r:200 w:0) + // Storage: VoterList ListNodes (r:101 w:0) + // Storage: Staking Nominators (r:101 w:0) + // Storage: Staking Validators (r:2 w:0) + // Storage: Staking Bonded (r:101 w:0) + // Storage: Staking Ledger (r:101 w:0) + // Storage: Staking CounterForValidators (r:1 w:0) + // Storage: Staking ValidatorCount (r:1 w:0) + // Storage: Staking MinimumValidatorCount (r:1 w:0) + // Storage: Staking CurrentEra (r:1 w:1) + // Storage: Staking ErasValidatorPrefs (r:0 w:1) + // Storage: Staking ErasStakersPaged (r:0 w:1) + // Storage: Staking ErasStakersOverview (r:0 w:1) + // Storage: Staking ErasStakers (r:0 w:1) + // Storage: Staking ErasTotalStake (r:0 w:1) + // Storage: Staking ErasStartSessionIndex (r:0 w:1) + // Storage: Staking MinimumActiveStake (r:0 w:1) /// The range of component `v` is `[1, 10]`. /// The range of component `n` is `[0, 100]`. fn new_era(v: u32, n: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `0 + v * (3662 ±0) + n * (816 ±0)` - // Estimated: `528203 + v * (16743 ±0) + n * (12947 ±0)` - // Minimum execution time: 489_824 nanoseconds. - Weight::from_parts(491_687_000, 528203) - // Standard Error: 1_787_577 - .saturating_add(Weight::from_ref_time(58_719_498).saturating_mul(v.into())) - // Standard Error: 178_122 - .saturating_add(Weight::from_ref_time(13_273_555).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(206_u64)) + // Minimum execution time: 504_224 nanoseconds. + Weight::from_ref_time(506_290_000) + // Standard Error: 1_802_746 + .saturating_add(Weight::from_ref_time(60_725_475).saturating_mul(v.into())) + // Standard Error: 179_633 + .saturating_add(Weight::from_ref_time(13_820_500).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(206)) .saturating_add(T::DbWeight::get().reads((5_u64).saturating_mul(v.into()))) .saturating_add(T::DbWeight::get().reads((4_u64).saturating_mul(n.into()))) - .saturating_add(T::DbWeight::get().writes(4_u64)) - .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(v.into()))) - .saturating_add(Weight::from_proof_size(16743).saturating_mul(v.into())) - .saturating_add(Weight::from_proof_size(12947).saturating_mul(n.into())) - } - /// Storage: VoterList CounterForListNodes (r:1 w:0) - /// Proof: VoterList CounterForListNodes (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: VoterList ListBags (r:200 w:0) - /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) - /// Storage: VoterList ListNodes (r:2000 w:0) - /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) - /// Storage: Staking Nominators (r:2000 w:0) - /// Proof: Staking Nominators (max_values: None, max_size: Some(558), added: 3033, mode: MaxEncodedLen) - /// Storage: Staking Validators (r:1000 w:0) - /// Proof: Staking Validators (max_values: None, max_size: Some(45), added: 2520, mode: MaxEncodedLen) - /// Storage: Staking Bonded (r:2000 w:0) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: Staking Ledger (r:2000 w:0) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: Staking MinimumActiveStake (r:0 w:1) - /// Proof: Staking MinimumActiveStake (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) + .saturating_add(T::DbWeight::get().writes(3)) + .saturating_add(T::DbWeight::get().writes((4_u64).saturating_mul(v.into()))) + } + // Storage: VoterList CounterForListNodes (r:1 w:0) + // Storage: VoterList ListBags (r:200 w:0) + // Storage: VoterList ListNodes (r:1500 w:0) + // Storage: Staking Nominators (r:1500 w:0) + // Storage: Staking Validators (r:500 w:0) + // Storage: Staking Bonded (r:1500 w:0) + // Storage: Staking Ledger (r:1500 w:0) + // Storage: Staking MinimumActiveStake (r:0 w:1) /// The range of component `v` is `[500, 1000]`. /// The range of component `n` is `[500, 1000]`. fn get_npos_voters(v: u32, n: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `3167 + v * (459 ±0) + n * (1007 ±0)` - // Estimated: `511899 + v * (14295 ±0) + n * (11775 ±0)` - // Minimum execution time: 23_373_467 nanoseconds. - Weight::from_parts(23_497_257_000, 511899) - // Standard Error: 299_205 - .saturating_add(Weight::from_ref_time(3_434_000).saturating_mul(v.into())) - // Standard Error: 299_205 - .saturating_add(Weight::from_ref_time(2_568_954).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(201_u64)) + // Minimum execution time: 24_224_895 nanoseconds. + Weight::from_ref_time(24_374_544_000) + // Standard Error: 319_103 + .saturating_add(Weight::from_ref_time(3_422_743).saturating_mul(v.into())) + // Standard Error: 319_103 + .saturating_add(Weight::from_ref_time(2_914_359).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(201)) .saturating_add(T::DbWeight::get().reads((5_u64).saturating_mul(v.into()))) .saturating_add(T::DbWeight::get().reads((4_u64).saturating_mul(n.into()))) - .saturating_add(T::DbWeight::get().writes(1_u64)) - .saturating_add(Weight::from_proof_size(14295).saturating_mul(v.into())) - .saturating_add(Weight::from_proof_size(11775).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: Staking CounterForValidators (r:1 w:0) - /// Proof: Staking CounterForValidators (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking Validators (r:1001 w:0) - /// Proof: Staking Validators (max_values: None, max_size: Some(45), added: 2520, mode: MaxEncodedLen) + // Storage: Staking CounterForValidators (r:1 w:0) + // Storage: Staking Validators (r:501 w:0) /// The range of component `v` is `[500, 1000]`. fn get_npos_targets(v: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `983 + v * (50 ±0)` - // Estimated: `3019 + v * (2520 ±0)` - // Minimum execution time: 3_882_120 nanoseconds. - Weight::from_parts(3_951_993_000, 3019) - // Standard Error: 46_729 - .saturating_add(Weight::from_ref_time(2_856_043).saturating_mul(v.into())) - .saturating_add(T::DbWeight::get().reads(2_u64)) + // Minimum execution time: 4_765_318 nanoseconds. + Weight::from_ref_time(4_816_708_000) + // Standard Error: 54_677 + .saturating_add(Weight::from_ref_time(3_541_818).saturating_mul(v.into())) + .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(v.into()))) - .saturating_add(Weight::from_proof_size(2520).saturating_mul(v.into())) } - /// Storage: Staking MinCommission (r:0 w:1) - /// Proof: Staking MinCommission (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking MinValidatorBond (r:0 w:1) - /// Proof: Staking MinValidatorBond (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - /// Storage: Staking MaxValidatorsCount (r:0 w:1) - /// Proof: Staking MaxValidatorsCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking ChillThreshold (r:0 w:1) - /// Proof: Staking ChillThreshold (max_values: Some(1), max_size: Some(1), added: 496, mode: MaxEncodedLen) - /// Storage: Staking MaxNominatorsCount (r:0 w:1) - /// Proof: Staking MaxNominatorsCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking MinNominatorBond (r:0 w:1) - /// Proof: Staking MinNominatorBond (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) + // Storage: Staking MinCommission (r:0 w:1) + // 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_configs_all_set() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 8_427 nanoseconds. - Weight::from_ref_time(8_794_000) - .saturating_add(T::DbWeight::get().writes(6_u64)) - } - /// Storage: Staking MinCommission (r:0 w:1) - /// Proof: Staking MinCommission (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking MinValidatorBond (r:0 w:1) - /// Proof: Staking MinValidatorBond (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - /// Storage: Staking MaxValidatorsCount (r:0 w:1) - /// Proof: Staking MaxValidatorsCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking ChillThreshold (r:0 w:1) - /// Proof: Staking ChillThreshold (max_values: Some(1), max_size: Some(1), added: 496, mode: MaxEncodedLen) - /// Storage: Staking MaxNominatorsCount (r:0 w:1) - /// Proof: Staking MaxNominatorsCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking MinNominatorBond (r:0 w:1) - /// Proof: Staking MinNominatorBond (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) + // Minimum execution time: 10_480 nanoseconds. + Weight::from_ref_time(10_914_000) + .saturating_add(T::DbWeight::get().writes(6)) + } + // Storage: Staking MinCommission (r:0 w:1) + // 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_configs_all_remove() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 7_620 nanoseconds. - Weight::from_ref_time(7_901_000) - .saturating_add(T::DbWeight::get().writes(6_u64)) - } - /// Storage: Staking Ledger (r:1 w:0) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: Staking Nominators (r:1 w:1) - /// Proof: Staking Nominators (max_values: None, max_size: Some(558), added: 3033, mode: MaxEncodedLen) - /// Storage: Staking ChillThreshold (r:1 w:0) - /// Proof: Staking ChillThreshold (max_values: Some(1), max_size: Some(1), added: 496, mode: MaxEncodedLen) - /// Storage: Staking MaxNominatorsCount (r:1 w:0) - /// Proof: Staking MaxNominatorsCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking CounterForNominators (r:1 w:1) - /// Proof: Staking CounterForNominators (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking MinNominatorBond (r:1 w:0) - /// Proof: Staking MinNominatorBond (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - /// Storage: Staking Validators (r:1 w:0) - /// Proof: Staking Validators (max_values: None, max_size: Some(45), added: 2520, mode: MaxEncodedLen) - /// Storage: VoterList ListNodes (r:2 w:2) - /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) - /// Storage: VoterList ListBags (r:1 w:1) - /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) - /// Storage: VoterList CounterForListNodes (r:1 w:1) - /// Proof: VoterList CounterForListNodes (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + // Minimum execution time: 9_529 nanoseconds. + Weight::from_ref_time(10_159_000) + .saturating_add(T::DbWeight::get().writes(6)) + } + // Storage: Staking Ledger (r:1 w:0) + // Storage: Staking Nominators (r:1 w:1) + // Storage: Staking ChillThreshold (r:1 w:0) + // Storage: Staking MaxNominatorsCount (r:1 w:0) + // Storage: Staking CounterForNominators (r:1 w:1) + // Storage: Staking MinNominatorBond (r:1 w:0) + // Storage: Staking Validators (r:1 w:0) + // Storage: VoterList ListNodes (r:2 w:2) + // Storage: VoterList ListBags (r:1 w:1) + // Storage: VoterList CounterForListNodes (r:1 w:1) fn chill_other() -> Weight { - // Proof Size summary in bytes: - // Measured: `2031` - // Estimated: `19438` - // Minimum execution time: 66_188 nanoseconds. - Weight::from_parts(66_767_000, 19438) - .saturating_add(T::DbWeight::get().reads(11_u64)) - .saturating_add(T::DbWeight::get().writes(6_u64)) + // Minimum execution time: 81_347 nanoseconds. + Weight::from_ref_time(81_957_000) + .saturating_add(T::DbWeight::get().reads(11)) + .saturating_add(T::DbWeight::get().writes(6)) } - /// Storage: Staking MinCommission (r:1 w:0) - /// Proof: Staking MinCommission (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking Validators (r:1 w:1) - /// Proof: Staking Validators (max_values: None, max_size: Some(45), added: 2520, mode: MaxEncodedLen) + // Storage: Staking MinCommission (r:1 w:0) + // Storage: Staking Validators (r:1 w:1) fn force_apply_min_commission() -> Weight { - // Proof Size summary in bytes: - // Measured: `694` - // Estimated: `3019` - // Minimum execution time: 14_703 nanoseconds. - Weight::from_parts(15_031_000, 3019) - .saturating_add(T::DbWeight::get().reads(2_u64)) - .saturating_add(T::DbWeight::get().writes(1_u64)) + // Minimum execution time: 19_153 nanoseconds. + Weight::from_ref_time(19_621_000) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: Staking MinCommission (r:0 w:1) - /// Proof: Staking MinCommission (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + // Storage: Staking MinCommission (r:0 w:1) fn set_min_commission() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 4_518 nanoseconds. - Weight::from_ref_time(4_656_000) - .saturating_add(T::DbWeight::get().writes(1_u64)) + // Minimum execution time: 6_058 nanoseconds. + Weight::from_ref_time(6_278_000) + .saturating_add(T::DbWeight::get().writes(1)) } } // For backwards compatibility and tests impl WeightInfo for () { - /// Storage: Staking Bonded (r:1 w:1) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: Staking Ledger (r:1 w:1) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: Staking CurrentEra (r:1 w:0) - /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Staking Payee (r:0 w:1) - /// Proof: Staking Payee (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) + // Storage: Staking Bonded (r:1 w:1) + // Storage: Staking Ledger (r:1 w:1) + // Storage: Balances Locks (r:1 w:1) + // Storage: Staking Payee (r:0 w:1) fn bond() -> Weight { - // Proof Size summary in bytes: - // Measured: `1079` - // Estimated: `10386` - // Minimum execution time: 40_015 nanoseconds. - Weight::from_parts(40_601_000, 10386) - .saturating_add(RocksDbWeight::get().reads(4_u64)) - .saturating_add(RocksDbWeight::get().writes(4_u64)) - } - /// Storage: Staking Bonded (r:1 w:0) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: Staking Ledger (r:1 w:1) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: VoterList ListNodes (r:3 w:3) - /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) - /// Storage: VoterList ListBags (r:2 w:2) - /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) + // Minimum execution time: 51_815 nanoseconds. + Weight::from_ref_time(52_367_000) + .saturating_add(RocksDbWeight::get().reads(3)) + .saturating_add(RocksDbWeight::get().writes(4)) + } + // Storage: Staking Bonded (r:1 w:0) + // Storage: Staking Ledger (r:1 w:1) + // Storage: Balances Locks (r:1 w:1) + // Storage: VoterList ListNodes (r:3 w:3) + // Storage: VoterList ListBags (r:2 w:2) fn bond_extra() -> Weight { - // Proof Size summary in bytes: - // Measured: `2252` - // Estimated: `22888` - // Minimum execution time: 74_781 nanoseconds. - Weight::from_parts(75_188_000, 22888) - .saturating_add(RocksDbWeight::get().reads(8_u64)) - .saturating_add(RocksDbWeight::get().writes(7_u64)) - } - /// Storage: Staking Ledger (r:1 w:1) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: Staking Nominators (r:1 w:0) - /// Proof: Staking Nominators (max_values: None, max_size: Some(558), added: 3033, mode: MaxEncodedLen) - /// Storage: Staking MinNominatorBond (r:1 w:0) - /// Proof: Staking MinNominatorBond (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - /// Storage: Staking CurrentEra (r:1 w:0) - /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: VoterList ListNodes (r:3 w:3) - /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) - /// Storage: Staking Bonded (r:1 w:0) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: VoterList ListBags (r:2 w:2) - /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) + // Minimum execution time: 91_792 nanoseconds. + Weight::from_ref_time(92_729_000) + .saturating_add(RocksDbWeight::get().reads(8)) + .saturating_add(RocksDbWeight::get().writes(7)) + } + // Storage: Staking Ledger (r:1 w:1) + // Storage: Staking Nominators (r:1 w:0) + // Storage: Staking MinNominatorBond (r:1 w:0) + // Storage: Staking CurrentEra (r:1 w:0) + // Storage: Balances Locks (r:1 w:1) + // Storage: System Account (r:1 w:1) + // Storage: VoterList ListNodes (r:3 w:3) + // Storage: Staking Bonded (r:1 w:0) + // Storage: VoterList ListBags (r:2 w:2) fn unbond() -> Weight { - // Proof Size summary in bytes: - // Measured: `2457` - // Estimated: `29534` - // Minimum execution time: 81_299 nanoseconds. - Weight::from_parts(82_242_000, 29534) - .saturating_add(RocksDbWeight::get().reads(12_u64)) - .saturating_add(RocksDbWeight::get().writes(8_u64)) - } - /// Storage: Staking Ledger (r:1 w:1) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: Staking CurrentEra (r:1 w:0) - /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + // Minimum execution time: 97_647 nanoseconds. + Weight::from_ref_time(98_731_000) + .saturating_add(RocksDbWeight::get().reads(12)) + .saturating_add(RocksDbWeight::get().writes(8)) + } + // Storage: Staking Ledger (r:1 w:1) + // Storage: Staking CurrentEra (r:1 w:0) + // Storage: Balances Locks (r:1 w:1) + // Storage: System Account (r:1 w:1) /// The range of component `s` is `[0, 100]`. fn withdraw_unbonded_update(s: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `1085` - // Estimated: `10442` - // Minimum execution time: 31_479 nanoseconds. - Weight::from_parts(32_410_035, 10442) - // Standard Error: 313 - .saturating_add(Weight::from_ref_time(9_090).saturating_mul(s.into())) - .saturating_add(RocksDbWeight::get().reads(4_u64)) - .saturating_add(RocksDbWeight::get().writes(3_u64)) - } - /// Storage: Staking Ledger (r:1 w:1) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: Staking CurrentEra (r:1 w:0) - /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking Bonded (r:1 w:1) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: Staking SlashingSpans (r:1 w:1) - /// Proof Skipped: Staking SlashingSpans (max_values: None, max_size: None, mode: Measured) - /// Storage: Staking Validators (r:1 w:0) - /// Proof: Staking Validators (max_values: None, max_size: Some(45), added: 2520, mode: MaxEncodedLen) - /// Storage: Staking Nominators (r:1 w:1) - /// Proof: Staking Nominators (max_values: None, max_size: Some(558), added: 3033, mode: MaxEncodedLen) - /// Storage: Staking CounterForNominators (r:1 w:1) - /// Proof: Staking CounterForNominators (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: VoterList ListNodes (r:2 w:2) - /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) - /// Storage: VoterList ListBags (r:1 w:1) - /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) - /// Storage: VoterList CounterForListNodes (r:1 w:1) - /// Proof: VoterList CounterForListNodes (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Staking Payee (r:0 w:1) - /// Proof: Staking Payee (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) - /// Storage: Staking SpanSlash (r:0 w:100) - /// Proof: Staking SpanSlash (max_values: None, max_size: Some(76), added: 2551, mode: MaxEncodedLen) + // Minimum execution time: 44_744 nanoseconds. + Weight::from_ref_time(45_658_968) + // Standard Error: 692 + .saturating_add(Weight::from_ref_time(65_958).saturating_mul(s.into())) + .saturating_add(RocksDbWeight::get().reads(4)) + .saturating_add(RocksDbWeight::get().writes(3)) + } + // Storage: Staking Ledger (r:1 w:1) + // Storage: Staking CurrentEra (r:1 w:0) + // Storage: Staking Bonded (r:1 w:1) + // Storage: Staking SlashingSpans (r:1 w:0) + // Storage: Staking Validators (r:1 w:0) + // Storage: Staking Nominators (r:1 w:1) + // Storage: Staking CounterForNominators (r:1 w:1) + // Storage: VoterList ListNodes (r:2 w:2) + // Storage: VoterList ListBags (r:1 w:1) + // Storage: VoterList CounterForListNodes (r:1 w:1) + // Storage: System Account (r:1 w:1) + // Storage: Balances Locks (r:1 w:1) + // Storage: Staking Payee (r:0 w:1) + // Storage: Staking SpanSlash (r:0 w:2) /// The range of component `s` is `[0, 100]`. fn withdraw_unbonded_kill(s: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `2486 + s * (4 ±0)` - // Estimated: `32303 + s * (4 ±0)` - // Minimum execution time: 71_968 nanoseconds. - Weight::from_parts(76_631_804, 32303) - // Standard Error: 1_613 - .saturating_add(Weight::from_ref_time(1_058_968).saturating_mul(s.into())) - .saturating_add(RocksDbWeight::get().reads(13_u64)) - .saturating_add(RocksDbWeight::get().writes(12_u64)) + // Minimum execution time: 86_013 nanoseconds. + Weight::from_ref_time(91_544_236) + // Standard Error: 2_273 + .saturating_add(Weight::from_ref_time(1_073_291).saturating_mul(s.into())) + .saturating_add(RocksDbWeight::get().reads(13)) + .saturating_add(RocksDbWeight::get().writes(12)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(s.into()))) - .saturating_add(Weight::from_proof_size(4).saturating_mul(s.into())) } - /// Storage: Staking Ledger (r:1 w:0) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: Staking MinValidatorBond (r:1 w:0) - /// Proof: Staking MinValidatorBond (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - /// Storage: Staking MinCommission (r:1 w:0) - /// Proof: Staking MinCommission (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking Validators (r:1 w:1) - /// Proof: Staking Validators (max_values: None, max_size: Some(45), added: 2520, mode: MaxEncodedLen) - /// Storage: Staking MaxValidatorsCount (r:1 w:0) - /// Proof: Staking MaxValidatorsCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking Nominators (r:1 w:0) - /// Proof: Staking Nominators (max_values: None, max_size: Some(558), added: 3033, mode: MaxEncodedLen) - /// Storage: Staking Bonded (r:1 w:0) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: VoterList ListNodes (r:1 w:1) - /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) - /// Storage: VoterList ListBags (r:1 w:1) - /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) - /// Storage: VoterList CounterForListNodes (r:1 w:1) - /// Proof: VoterList CounterForListNodes (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking CounterForValidators (r:1 w:1) - /// Proof: Staking CounterForValidators (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + // Storage: Staking Ledger (r:1 w:0) + // Storage: Staking MinValidatorBond (r:1 w:0) + // Storage: Staking MinCommission (r:1 w:0) + // Storage: Staking Validators (r:1 w:1) + // Storage: Staking MaxValidatorsCount (r:1 w:0) + // Storage: Staking Nominators (r:1 w:0) + // Storage: Staking Bonded (r:1 w:0) + // Storage: VoterList ListNodes (r:1 w:1) + // Storage: VoterList ListBags (r:1 w:1) + // Storage: VoterList CounterForListNodes (r:1 w:1) + // Storage: Staking CounterForValidators (r:1 w:1) fn validate() -> Weight { - // Proof Size summary in bytes: - // Measured: `1446` - // Estimated: `19359` - // Minimum execution time: 51_963 nanoseconds. - Weight::from_parts(52_418_000, 19359) - .saturating_add(RocksDbWeight::get().reads(11_u64)) - .saturating_add(RocksDbWeight::get().writes(5_u64)) + // Minimum execution time: 66_579 nanoseconds. + Weight::from_ref_time(67_026_000) + .saturating_add(RocksDbWeight::get().reads(11)) + .saturating_add(RocksDbWeight::get().writes(5)) } - /// Storage: Staking Ledger (r:1 w:0) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: Staking Nominators (r:128 w:128) - /// Proof: Staking Nominators (max_values: None, max_size: Some(558), added: 3033, mode: MaxEncodedLen) + // Storage: Staking Ledger (r:1 w:0) + // Storage: Staking Nominators (r:1 w:1) /// The range of component `k` is `[1, 128]`. fn kick(k: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `1292 + k * (601 ±0)` - // Estimated: `3566 + k * (3033 ±0)` - // Minimum execution time: 25_685 nanoseconds. - Weight::from_parts(25_290_286, 3566) - // Standard Error: 5_164 - .saturating_add(Weight::from_ref_time(6_445_608).saturating_mul(k.into())) - .saturating_add(RocksDbWeight::get().reads(1_u64)) + // Minimum execution time: 40_716 nanoseconds. + Weight::from_ref_time(43_678_932) + // Standard Error: 15_099 + .saturating_add(Weight::from_ref_time(6_814_991).saturating_mul(k.into())) + .saturating_add(RocksDbWeight::get().reads(1)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(k.into()))) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(k.into()))) - .saturating_add(Weight::from_proof_size(3033).saturating_mul(k.into())) } - /// Storage: Staking Ledger (r:1 w:0) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: Staking MinNominatorBond (r:1 w:0) - /// Proof: Staking MinNominatorBond (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - /// Storage: Staking Nominators (r:1 w:1) - /// Proof: Staking Nominators (max_values: None, max_size: Some(558), added: 3033, mode: MaxEncodedLen) - /// Storage: Staking MaxNominatorsCount (r:1 w:0) - /// Proof: Staking MaxNominatorsCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking Validators (r:17 w:0) - /// Proof: Staking Validators (max_values: None, max_size: Some(45), added: 2520, mode: MaxEncodedLen) - /// Storage: Staking CurrentEra (r:1 w:0) - /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking Bonded (r:1 w:0) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: VoterList ListNodes (r:2 w:2) - /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) - /// Storage: VoterList ListBags (r:1 w:1) - /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) - /// Storage: VoterList CounterForListNodes (r:1 w:1) - /// Proof: VoterList CounterForListNodes (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking CounterForNominators (r:1 w:1) - /// Proof: Staking CounterForNominators (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + // Storage: Staking Ledger (r:1 w:0) + // Storage: Staking MinNominatorBond (r:1 w:0) + // Storage: Staking Nominators (r:1 w:1) + // Storage: Staking MaxNominatorsCount (r:1 w:0) + // Storage: Staking Validators (r:2 w:0) + // Storage: Staking CurrentEra (r:1 w:0) + // Storage: Staking Bonded (r:1 w:0) + // Storage: VoterList ListNodes (r:2 w:2) + // Storage: VoterList ListBags (r:1 w:1) + // Storage: VoterList CounterForListNodes (r:1 w:1) + // Storage: Staking CounterForNominators (r:1 w:1) /// The range of component `n` is `[1, 16]`. fn nominate(n: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `1984 + n * (105 ±0)` - // Estimated: `21988 + n * (2520 ±0)` - // Minimum execution time: 59_542 nanoseconds. - Weight::from_parts(57_558_678, 21988) - // Standard Error: 10_364 - .saturating_add(Weight::from_ref_time(2_759_713).saturating_mul(n.into())) - .saturating_add(RocksDbWeight::get().reads(12_u64)) + // Minimum execution time: 71_258 nanoseconds. + Weight::from_ref_time(70_901_125) + // Standard Error: 6_183 + .saturating_add(Weight::from_ref_time(2_777_341).saturating_mul(n.into())) + .saturating_add(RocksDbWeight::get().reads(12)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(n.into()))) - .saturating_add(RocksDbWeight::get().writes(6_u64)) - .saturating_add(Weight::from_proof_size(2520).saturating_mul(n.into())) - } - /// Storage: Staking Ledger (r:1 w:0) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: Staking Validators (r:1 w:0) - /// Proof: Staking Validators (max_values: None, max_size: Some(45), added: 2520, mode: MaxEncodedLen) - /// Storage: Staking Nominators (r:1 w:1) - /// Proof: Staking Nominators (max_values: None, max_size: Some(558), added: 3033, mode: MaxEncodedLen) - /// Storage: Staking CounterForNominators (r:1 w:1) - /// Proof: Staking CounterForNominators (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: VoterList ListNodes (r:2 w:2) - /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) - /// Storage: VoterList ListBags (r:1 w:1) - /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) - /// Storage: VoterList CounterForListNodes (r:1 w:1) - /// Proof: VoterList CounterForListNodes (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + .saturating_add(RocksDbWeight::get().writes(6)) + } + // Storage: Staking Ledger (r:1 w:0) + // Storage: Staking Validators (r:1 w:0) + // Storage: Staking Nominators (r:1 w:1) + // Storage: Staking CounterForNominators (r:1 w:1) + // Storage: VoterList ListNodes (r:2 w:2) + // Storage: VoterList ListBags (r:1 w:1) + // Storage: VoterList CounterForListNodes (r:1 w:1) fn chill() -> Weight { - // Proof Size summary in bytes: - // Measured: `1876` - // Estimated: `17932` - // Minimum execution time: 52_132 nanoseconds. - Weight::from_parts(52_648_000, 17932) - .saturating_add(RocksDbWeight::get().reads(8_u64)) - .saturating_add(RocksDbWeight::get().writes(6_u64)) + // Minimum execution time: 66_052 nanoseconds. + Weight::from_ref_time(66_480_000) + .saturating_add(RocksDbWeight::get().reads(8)) + .saturating_add(RocksDbWeight::get().writes(6)) } - /// Storage: Staking Ledger (r:1 w:0) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: Staking Payee (r:0 w:1) - /// Proof: Staking Payee (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) + // Storage: Staking Ledger (r:1 w:0) + // Storage: Staking Payee (r:0 w:1) fn set_payee() -> Weight { - // Proof Size summary in bytes: - // Measured: `840` - // Estimated: `3566` - // Minimum execution time: 13_399 nanoseconds. - Weight::from_parts(13_567_000, 3566) - .saturating_add(RocksDbWeight::get().reads(1_u64)) - .saturating_add(RocksDbWeight::get().writes(1_u64)) + // Minimum execution time: 18_008 nanoseconds. + Weight::from_ref_time(18_360_000) + .saturating_add(RocksDbWeight::get().reads(1)) + .saturating_add(RocksDbWeight::get().writes(1)) } - /// Storage: Staking Bonded (r:1 w:1) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: Staking Ledger (r:2 w:2) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) + // Storage: Staking Bonded (r:1 w:1) + // Storage: Staking Ledger (r:2 w:2) fn set_controller() -> Weight { - // Proof Size summary in bytes: - // Measured: `939` - // Estimated: `9679` - // Minimum execution time: 20_425 nanoseconds. - Weight::from_parts(20_713_000, 9679) - .saturating_add(RocksDbWeight::get().reads(3_u64)) - .saturating_add(RocksDbWeight::get().writes(3_u64)) + // Minimum execution time: 25_979 nanoseconds. + Weight::from_ref_time(26_350_000) + .saturating_add(RocksDbWeight::get().reads(3)) + .saturating_add(RocksDbWeight::get().writes(3)) } - /// Storage: Staking ValidatorCount (r:0 w:1) - /// Proof: Staking ValidatorCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + // Storage: Staking ValidatorCount (r:0 w:1) fn set_validator_count() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 3_069 nanoseconds. - Weight::from_ref_time(3_176_000) - .saturating_add(RocksDbWeight::get().writes(1_u64)) + // Minimum execution time: 5_009 nanoseconds. + Weight::from_ref_time(5_248_000) + .saturating_add(RocksDbWeight::get().writes(1)) } - /// Storage: Staking ForceEra (r:0 w:1) - /// Proof: Staking ForceEra (max_values: Some(1), max_size: Some(1), added: 496, mode: MaxEncodedLen) + // Storage: Staking ForceEra (r:0 w:1) fn force_no_eras() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 11_386 nanoseconds. - Weight::from_ref_time(11_672_000) - .saturating_add(RocksDbWeight::get().writes(1_u64)) + // Minimum execution time: 19_493 nanoseconds. + Weight::from_ref_time(19_888_000) + .saturating_add(RocksDbWeight::get().writes(1)) } - /// Storage: Staking ForceEra (r:0 w:1) - /// Proof: Staking ForceEra (max_values: Some(1), max_size: Some(1), added: 496, mode: MaxEncodedLen) + // Storage: Staking ForceEra (r:0 w:1) fn force_new_era() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 11_591 nanoseconds. - Weight::from_ref_time(11_799_000) - .saturating_add(RocksDbWeight::get().writes(1_u64)) + // Minimum execution time: 19_425 nanoseconds. + Weight::from_ref_time(19_991_000) + .saturating_add(RocksDbWeight::get().writes(1)) } - /// Storage: Staking ForceEra (r:0 w:1) - /// Proof: Staking ForceEra (max_values: Some(1), max_size: Some(1), added: 496, mode: MaxEncodedLen) + // Storage: Staking ForceEra (r:0 w:1) fn force_new_era_always() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 11_553 nanoseconds. - Weight::from_ref_time(11_871_000) - .saturating_add(RocksDbWeight::get().writes(1_u64)) + // Minimum execution time: 19_690 nanoseconds. + Weight::from_ref_time(20_010_000) + .saturating_add(RocksDbWeight::get().writes(1)) } - /// Storage: Staking Invulnerables (r:0 w:1) - /// Proof Skipped: Staking Invulnerables (max_values: Some(1), max_size: None, mode: Measured) + // Storage: Staking Invulnerables (r:0 w:1) /// The range of component `v` is `[0, 1000]`. fn set_invulnerables(v: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 3_292 nanoseconds. - Weight::from_ref_time(3_754_352) - // Standard Error: 40 - .saturating_add(Weight::from_ref_time(9_838).saturating_mul(v.into())) - .saturating_add(RocksDbWeight::get().writes(1_u64)) - } - /// Storage: Staking Bonded (r:1 w:1) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: Staking SlashingSpans (r:1 w:1) - /// Proof Skipped: Staking SlashingSpans (max_values: None, max_size: None, mode: Measured) - /// Storage: Staking Validators (r:1 w:0) - /// Proof: Staking Validators (max_values: None, max_size: Some(45), added: 2520, mode: MaxEncodedLen) - /// Storage: Staking Nominators (r:1 w:1) - /// Proof: Staking Nominators (max_values: None, max_size: Some(558), added: 3033, mode: MaxEncodedLen) - /// Storage: Staking CounterForNominators (r:1 w:1) - /// Proof: Staking CounterForNominators (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: VoterList ListNodes (r:2 w:2) - /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) - /// Storage: VoterList ListBags (r:1 w:1) - /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) - /// Storage: VoterList CounterForListNodes (r:1 w:1) - /// Proof: VoterList CounterForListNodes (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Staking Ledger (r:0 w:1) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: Staking Payee (r:0 w:1) - /// Proof: Staking Payee (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) - /// Storage: Staking SpanSlash (r:0 w:100) - /// Proof: Staking SpanSlash (max_values: None, max_size: Some(76), added: 2551, mode: MaxEncodedLen) + // Minimum execution time: 5_375 nanoseconds. + Weight::from_ref_time(6_217_068) + // Standard Error: 43 + .saturating_add(Weight::from_ref_time(9_885).saturating_mul(v.into())) + .saturating_add(RocksDbWeight::get().writes(1)) + } + // Storage: Staking Bonded (r:1 w:1) + // Storage: Staking SlashingSpans (r:1 w:0) + // Storage: Staking Validators (r:1 w:0) + // Storage: Staking Nominators (r:1 w:1) + // Storage: Staking CounterForNominators (r:1 w:1) + // Storage: VoterList ListNodes (r:2 w:2) + // Storage: VoterList ListBags (r:1 w:1) + // Storage: VoterList CounterForListNodes (r:1 w:1) + // Storage: System Account (r:1 w:1) + // Storage: Balances Locks (r:1 w:1) + // Storage: Staking Ledger (r:0 w:1) + // Storage: Staking Payee (r:0 w:1) + // Storage: Staking SpanSlash (r:0 w:2) /// The range of component `s` is `[0, 100]`. fn force_unstake(s: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `2178 + s * (4 ±0)` - // Estimated: `27930 + s * (4 ±0)` - // Minimum execution time: 65_307 nanoseconds. - Weight::from_parts(70_227_980, 27930) - // Standard Error: 2_113 - .saturating_add(Weight::from_ref_time(1_059_856).saturating_mul(s.into())) - .saturating_add(RocksDbWeight::get().reads(11_u64)) - .saturating_add(RocksDbWeight::get().writes(12_u64)) + // Minimum execution time: 79_630 nanoseconds. + Weight::from_ref_time(85_354_738) + // Standard Error: 2_555 + .saturating_add(Weight::from_ref_time(1_086_827).saturating_mul(s.into())) + .saturating_add(RocksDbWeight::get().reads(11)) + .saturating_add(RocksDbWeight::get().writes(12)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(s.into()))) - .saturating_add(Weight::from_proof_size(4).saturating_mul(s.into())) } - /// Storage: Staking UnappliedSlashes (r:1 w:1) - /// Proof Skipped: Staking UnappliedSlashes (max_values: None, max_size: None, mode: Measured) + // Storage: Staking UnappliedSlashes (r:1 w:1) /// The range of component `s` is `[1, 1000]`. fn cancel_deferred_slash(s: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `66671` - // Estimated: `69146` - // Minimum execution time: 89_123 nanoseconds. - Weight::from_parts(890_989_741, 69146) - // Standard Error: 58_282 - .saturating_add(Weight::from_ref_time(4_920_413).saturating_mul(s.into())) - .saturating_add(RocksDbWeight::get().reads(1_u64)) - .saturating_add(RocksDbWeight::get().writes(1_u64)) - } - /// Storage: Staking CurrentEra (r:1 w:0) - /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking ErasValidatorReward (r:1 w:0) - /// Proof: Staking ErasValidatorReward (max_values: None, max_size: Some(28), added: 2503, mode: MaxEncodedLen) - /// Storage: Staking Bonded (r:257 w:0) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: Staking Ledger (r:1 w:1) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: Staking ErasStakersClipped (r:1 w:0) - /// Proof Skipped: Staking ErasStakersClipped (max_values: None, max_size: None, mode: Measured) - /// Storage: Staking ErasRewardPoints (r:1 w:0) - /// Proof Skipped: Staking ErasRewardPoints (max_values: None, max_size: None, mode: Measured) - /// Storage: Staking ErasValidatorPrefs (r:1 w:0) - /// Proof: Staking ErasValidatorPrefs (max_values: None, max_size: Some(57), added: 2532, mode: MaxEncodedLen) - /// Storage: Staking Payee (r:257 w:0) - /// Proof: Staking Payee (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) - /// Storage: System Account (r:257 w:257) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + // Minimum execution time: 92_209 nanoseconds. + Weight::from_ref_time(901_022_610) + // Standard Error: 59_320 + .saturating_add(Weight::from_ref_time(4_943_518).saturating_mul(s.into())) + .saturating_add(RocksDbWeight::get().reads(1)) + .saturating_add(RocksDbWeight::get().writes(1)) + } + // Storage: Staking CurrentEra (r:1 w:0) + // Storage: Staking ErasStakersOverview (r:1 w:0) + // Storage: Staking ErasValidatorReward (r:1 w:0) + // Storage: Staking Bonded (r:1 w:0) + // Storage: Staking Ledger (r:1 w:1) + // Storage: Staking ClaimedRewards (r:1 w:1) + // Storage: Staking ErasStakersPaged (r:1 w:0) + // Storage: Staking ErasStakersClipped (r:1 w:0) + // Storage: Staking ErasRewardPoints (r:1 w:0) + // Storage: Staking ErasValidatorPrefs (r:1 w:0) + // Storage: Staking Payee (r:1 w:0) + // Storage: System Account (r:1 w:1) /// The range of component `n` is `[0, 256]`. fn payout_stakers_dead_controller(n: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `20345 + n * (143 ±0)` - // Estimated: `54756 + n * (8024 ±1)` - // Minimum execution time: 73_652 nanoseconds. - Weight::from_parts(127_839_483, 54756) - // Standard Error: 14_195 - .saturating_add(Weight::from_ref_time(21_932_079).saturating_mul(n.into())) - .saturating_add(RocksDbWeight::get().reads(9_u64)) + // Minimum execution time: 134_323 nanoseconds. + Weight::from_ref_time(200_066_020) + // Standard Error: 16_654 + .saturating_add(Weight::from_ref_time(21_841_097).saturating_mul(n.into())) + .saturating_add(RocksDbWeight::get().reads(11)) .saturating_add(RocksDbWeight::get().reads((3_u64).saturating_mul(n.into()))) - .saturating_add(RocksDbWeight::get().writes(2_u64)) + .saturating_add(RocksDbWeight::get().writes(3)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(n.into()))) - .saturating_add(Weight::from_proof_size(8024).saturating_mul(n.into())) } - /// Storage: Staking CurrentEra (r:1 w:0) - /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking ErasValidatorReward (r:1 w:0) - /// Proof: Staking ErasValidatorReward (max_values: None, max_size: Some(28), added: 2503, mode: MaxEncodedLen) - /// Storage: Staking Bonded (r:257 w:0) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: Staking Ledger (r:257 w:257) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: Staking ErasStakersClipped (r:1 w:0) - /// Proof Skipped: Staking ErasStakersClipped (max_values: None, max_size: None, mode: Measured) - /// Storage: Staking ErasRewardPoints (r:1 w:0) - /// Proof Skipped: Staking ErasRewardPoints (max_values: None, max_size: None, mode: Measured) - /// Storage: Staking ErasValidatorPrefs (r:1 w:0) - /// Proof: Staking ErasValidatorPrefs (max_values: None, max_size: Some(57), added: 2532, mode: MaxEncodedLen) - /// Storage: Staking Payee (r:257 w:0) - /// Proof: Staking Payee (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) - /// Storage: System Account (r:257 w:257) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:257 w:257) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + // Storage: Staking CurrentEra (r:1 w:0) + // Storage: Staking ErasStakersOverview (r:1 w:0) + // Storage: Staking ErasValidatorReward (r:1 w:0) + // Storage: Staking Bonded (r:1 w:0) + // Storage: Staking Ledger (r:1 w:1) + // Storage: Staking ClaimedRewards (r:1 w:1) + // Storage: Staking ErasStakersPaged (r:1 w:0) + // Storage: Staking ErasStakersClipped (r:1 w:0) + // Storage: Staking ErasRewardPoints (r:1 w:0) + // Storage: Staking ErasValidatorPrefs (r:1 w:0) + // Storage: Staking Payee (r:1 w:0) + // Storage: System Account (r:1 w:1) + // Storage: Balances Locks (r:1 w:1) /// The range of component `n` is `[0, 256]`. fn payout_stakers_alive_staked(n: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `35099 + n * (465 ±0)` - // Estimated: `83594 + n * (16026 ±0)` - // Minimum execution time: 94_560 nanoseconds. - Weight::from_parts(154_033_219, 83594) - // Standard Error: 26_663 - .saturating_add(Weight::from_ref_time(31_269_223).saturating_mul(n.into())) - .saturating_add(RocksDbWeight::get().reads(10_u64)) + // Minimum execution time: 166_885 nanoseconds. + Weight::from_ref_time(231_648_127) + // Standard Error: 30_392 + .saturating_add(Weight::from_ref_time(30_760_443).saturating_mul(n.into())) + .saturating_add(RocksDbWeight::get().reads(12)) + .saturating_add(RocksDbWeight::get().reads((5_u64).saturating_mul(n.into()))) + .saturating_add(RocksDbWeight::get().writes(4)) + .saturating_add(RocksDbWeight::get().writes((3_u64).saturating_mul(n.into()))) + } + // Storage: Staking CurrentEra (r:1 w:0) + // Storage: Staking ErasStakersOverview (r:1 w:0) + // Storage: Staking ErasValidatorReward (r:1 w:0) + // Storage: Staking Bonded (r:2 w:0) + // Storage: Staking Ledger (r:2 w:2) + // Storage: Staking ClaimedRewards (r:1 w:1) + // Storage: Staking ErasStakersPaged (r:1 w:0) + // Storage: Staking ErasRewardPoints (r:1 w:0) + // Storage: Staking Payee (r:2 w:0) + // Storage: Balances Locks (r:2 w:2) + // Storage: System Account (r:2 w:2) + /// The range of component `n` is `[1, 256]`. + fn payout_stakers_nominators_only(n: u32, ) -> Weight { + // Minimum execution time: 272_243 nanoseconds. + Weight::from_ref_time(228_003_618) + // Standard Error: 35_442 + .saturating_add(Weight::from_ref_time(34_057_392).saturating_mul(n.into())) + .saturating_add(RocksDbWeight::get().reads(11)) .saturating_add(RocksDbWeight::get().reads((5_u64).saturating_mul(n.into()))) - .saturating_add(RocksDbWeight::get().writes(3_u64)) + .saturating_add(RocksDbWeight::get().writes(4)) .saturating_add(RocksDbWeight::get().writes((3_u64).saturating_mul(n.into()))) - .saturating_add(Weight::from_proof_size(16026).saturating_mul(n.into())) } - /// Storage: Staking Ledger (r:1 w:1) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: VoterList ListNodes (r:3 w:3) - /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) - /// Storage: Staking Bonded (r:1 w:0) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: VoterList ListBags (r:2 w:2) - /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) + // Storage: Staking Ledger (r:1 w:1) + // Storage: Balances Locks (r:1 w:1) + // Storage: System Account (r:1 w:1) + // Storage: VoterList ListNodes (r:3 w:3) + // Storage: Staking Bonded (r:1 w:0) + // Storage: VoterList ListBags (r:2 w:2) /// The range of component `l` is `[1, 32]`. fn rebond(l: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `2253 + l * (7 ±0)` - // Estimated: `25491` - // Minimum execution time: 74_764 nanoseconds. - Weight::from_parts(75_814_067, 25491) - // Standard Error: 1_217 - .saturating_add(Weight::from_ref_time(64_725).saturating_mul(l.into())) - .saturating_add(RocksDbWeight::get().reads(9_u64)) - .saturating_add(RocksDbWeight::get().writes(8_u64)) - } - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: Staking Bonded (r:1 w:1) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: Staking Ledger (r:1 w:1) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: Staking SlashingSpans (r:1 w:1) - /// Proof Skipped: Staking SlashingSpans (max_values: None, max_size: None, mode: Measured) - /// Storage: Staking Validators (r:1 w:0) - /// Proof: Staking Validators (max_values: None, max_size: Some(45), added: 2520, mode: MaxEncodedLen) - /// Storage: Staking Nominators (r:1 w:1) - /// Proof: Staking Nominators (max_values: None, max_size: Some(558), added: 3033, mode: MaxEncodedLen) - /// Storage: Staking CounterForNominators (r:1 w:1) - /// Proof: Staking CounterForNominators (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: VoterList ListNodes (r:2 w:2) - /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) - /// Storage: VoterList ListBags (r:1 w:1) - /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) - /// Storage: VoterList CounterForListNodes (r:1 w:1) - /// Proof: VoterList CounterForListNodes (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Staking Payee (r:0 w:1) - /// Proof: Staking Payee (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) - /// Storage: Staking SpanSlash (r:0 w:100) - /// Proof: Staking SpanSlash (max_values: None, max_size: Some(76), added: 2551, mode: MaxEncodedLen) + // Minimum execution time: 92_462 nanoseconds. + Weight::from_ref_time(93_684_047) + // Standard Error: 2_000 + .saturating_add(Weight::from_ref_time(51_643).saturating_mul(l.into())) + .saturating_add(RocksDbWeight::get().reads(9)) + .saturating_add(RocksDbWeight::get().writes(8)) + } + // Storage: System Account (r:1 w:1) + // Storage: Staking Bonded (r:1 w:1) + // Storage: Staking Ledger (r:1 w:1) + // Storage: Staking SlashingSpans (r:1 w:1) + // Storage: Staking Validators (r:1 w:0) + // Storage: Staking Nominators (r:1 w:1) + // Storage: Staking CounterForNominators (r:1 w:1) + // Storage: VoterList ListNodes (r:2 w:2) + // Storage: VoterList ListBags (r:1 w:1) + // Storage: VoterList CounterForListNodes (r:1 w:1) + // Storage: Balances Locks (r:1 w:1) + // Storage: Staking Payee (r:0 w:1) + // Storage: Staking SpanSlash (r:0 w:1) /// The range of component `s` is `[1, 100]`. fn reap_stash(s: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `2486 + s * (4 ±0)` - // Estimated: `31810 + s * (4 ±0)` - // Minimum execution time: 77_611 nanoseconds. - Weight::from_parts(79_760_034, 31810) - // Standard Error: 1_597 - .saturating_add(Weight::from_ref_time(1_039_268).saturating_mul(s.into())) - .saturating_add(RocksDbWeight::get().reads(12_u64)) - .saturating_add(RocksDbWeight::get().writes(12_u64)) + // Minimum execution time: 92_003 nanoseconds. + Weight::from_ref_time(93_936_550) + // Standard Error: 2_091 + .saturating_add(Weight::from_ref_time(1_088_847).saturating_mul(s.into())) + .saturating_add(RocksDbWeight::get().reads(12)) + .saturating_add(RocksDbWeight::get().writes(12)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(s.into()))) - .saturating_add(Weight::from_proof_size(4).saturating_mul(s.into())) } - /// Storage: VoterList CounterForListNodes (r:1 w:0) - /// Proof: VoterList CounterForListNodes (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: VoterList ListBags (r:200 w:0) - /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) - /// Storage: VoterList ListNodes (r:110 w:0) - /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) - /// Storage: Staking Nominators (r:110 w:0) - /// Proof: Staking Nominators (max_values: None, max_size: Some(558), added: 3033, mode: MaxEncodedLen) - /// Storage: Staking Validators (r:11 w:0) - /// Proof: Staking Validators (max_values: None, max_size: Some(45), added: 2520, mode: MaxEncodedLen) - /// Storage: Staking Bonded (r:110 w:0) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: Staking Ledger (r:110 w:0) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: Staking CounterForValidators (r:1 w:0) - /// Proof: Staking CounterForValidators (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking ValidatorCount (r:1 w:0) - /// Proof: Staking ValidatorCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking MinimumValidatorCount (r:1 w:0) - /// Proof: Staking MinimumValidatorCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking CurrentEra (r:1 w:1) - /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking ErasStakersClipped (r:0 w:10) - /// Proof Skipped: Staking ErasStakersClipped (max_values: None, max_size: None, mode: Measured) - /// Storage: Staking ErasValidatorPrefs (r:0 w:10) - /// Proof: Staking ErasValidatorPrefs (max_values: None, max_size: Some(57), added: 2532, mode: MaxEncodedLen) - /// Storage: Staking ErasStakers (r:0 w:10) - /// Proof Skipped: Staking ErasStakers (max_values: None, max_size: None, mode: Measured) - /// Storage: Staking ErasTotalStake (r:0 w:1) - /// Proof: Staking ErasTotalStake (max_values: None, max_size: Some(28), added: 2503, mode: MaxEncodedLen) - /// Storage: Staking ErasStartSessionIndex (r:0 w:1) - /// Proof: Staking ErasStartSessionIndex (max_values: None, max_size: Some(16), added: 2491, mode: MaxEncodedLen) - /// Storage: Staking MinimumActiveStake (r:0 w:1) - /// Proof: Staking MinimumActiveStake (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) + // Storage: VoterList CounterForListNodes (r:1 w:0) + // Storage: VoterList ListBags (r:200 w:0) + // Storage: VoterList ListNodes (r:101 w:0) + // Storage: Staking Nominators (r:101 w:0) + // Storage: Staking Validators (r:2 w:0) + // Storage: Staking Bonded (r:101 w:0) + // Storage: Staking Ledger (r:101 w:0) + // Storage: Staking CounterForValidators (r:1 w:0) + // Storage: Staking ValidatorCount (r:1 w:0) + // Storage: Staking MinimumValidatorCount (r:1 w:0) + // Storage: Staking CurrentEra (r:1 w:1) + // Storage: Staking ErasValidatorPrefs (r:0 w:1) + // Storage: Staking ErasStakersPaged (r:0 w:1) + // Storage: Staking ErasStakersOverview (r:0 w:1) + // Storage: Staking ErasStakers (r:0 w:1) + // Storage: Staking ErasTotalStake (r:0 w:1) + // Storage: Staking ErasStartSessionIndex (r:0 w:1) + // Storage: Staking MinimumActiveStake (r:0 w:1) /// The range of component `v` is `[1, 10]`. /// The range of component `n` is `[0, 100]`. fn new_era(v: u32, n: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `0 + v * (3662 ±0) + n * (816 ±0)` - // Estimated: `528203 + v * (16743 ±0) + n * (12947 ±0)` - // Minimum execution time: 489_824 nanoseconds. - Weight::from_parts(491_687_000, 528203) - // Standard Error: 1_787_577 - .saturating_add(Weight::from_ref_time(58_719_498).saturating_mul(v.into())) - // Standard Error: 178_122 - .saturating_add(Weight::from_ref_time(13_273_555).saturating_mul(n.into())) - .saturating_add(RocksDbWeight::get().reads(206_u64)) + // Minimum execution time: 504_224 nanoseconds. + Weight::from_ref_time(506_290_000) + // Standard Error: 1_802_746 + .saturating_add(Weight::from_ref_time(60_725_475).saturating_mul(v.into())) + // Standard Error: 179_633 + .saturating_add(Weight::from_ref_time(13_820_500).saturating_mul(n.into())) + .saturating_add(RocksDbWeight::get().reads(206)) .saturating_add(RocksDbWeight::get().reads((5_u64).saturating_mul(v.into()))) .saturating_add(RocksDbWeight::get().reads((4_u64).saturating_mul(n.into()))) - .saturating_add(RocksDbWeight::get().writes(4_u64)) - .saturating_add(RocksDbWeight::get().writes((3_u64).saturating_mul(v.into()))) - .saturating_add(Weight::from_proof_size(16743).saturating_mul(v.into())) - .saturating_add(Weight::from_proof_size(12947).saturating_mul(n.into())) - } - /// Storage: VoterList CounterForListNodes (r:1 w:0) - /// Proof: VoterList CounterForListNodes (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: VoterList ListBags (r:200 w:0) - /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) - /// Storage: VoterList ListNodes (r:2000 w:0) - /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) - /// Storage: Staking Nominators (r:2000 w:0) - /// Proof: Staking Nominators (max_values: None, max_size: Some(558), added: 3033, mode: MaxEncodedLen) - /// Storage: Staking Validators (r:1000 w:0) - /// Proof: Staking Validators (max_values: None, max_size: Some(45), added: 2520, mode: MaxEncodedLen) - /// Storage: Staking Bonded (r:2000 w:0) - /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: Staking Ledger (r:2000 w:0) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: Staking MinimumActiveStake (r:0 w:1) - /// Proof: Staking MinimumActiveStake (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) + .saturating_add(RocksDbWeight::get().writes(3)) + .saturating_add(RocksDbWeight::get().writes((4_u64).saturating_mul(v.into()))) + } + // Storage: VoterList CounterForListNodes (r:1 w:0) + // Storage: VoterList ListBags (r:200 w:0) + // Storage: VoterList ListNodes (r:1500 w:0) + // Storage: Staking Nominators (r:1500 w:0) + // Storage: Staking Validators (r:500 w:0) + // Storage: Staking Bonded (r:1500 w:0) + // Storage: Staking Ledger (r:1500 w:0) + // Storage: Staking MinimumActiveStake (r:0 w:1) /// The range of component `v` is `[500, 1000]`. /// The range of component `n` is `[500, 1000]`. fn get_npos_voters(v: u32, n: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `3167 + v * (459 ±0) + n * (1007 ±0)` - // Estimated: `511899 + v * (14295 ±0) + n * (11775 ±0)` - // Minimum execution time: 23_373_467 nanoseconds. - Weight::from_parts(23_497_257_000, 511899) - // Standard Error: 299_205 - .saturating_add(Weight::from_ref_time(3_434_000).saturating_mul(v.into())) - // Standard Error: 299_205 - .saturating_add(Weight::from_ref_time(2_568_954).saturating_mul(n.into())) - .saturating_add(RocksDbWeight::get().reads(201_u64)) + // Minimum execution time: 24_224_895 nanoseconds. + Weight::from_ref_time(24_374_544_000) + // Standard Error: 319_103 + .saturating_add(Weight::from_ref_time(3_422_743).saturating_mul(v.into())) + // Standard Error: 319_103 + .saturating_add(Weight::from_ref_time(2_914_359).saturating_mul(n.into())) + .saturating_add(RocksDbWeight::get().reads(201)) .saturating_add(RocksDbWeight::get().reads((5_u64).saturating_mul(v.into()))) .saturating_add(RocksDbWeight::get().reads((4_u64).saturating_mul(n.into()))) - .saturating_add(RocksDbWeight::get().writes(1_u64)) - .saturating_add(Weight::from_proof_size(14295).saturating_mul(v.into())) - .saturating_add(Weight::from_proof_size(11775).saturating_mul(n.into())) + .saturating_add(RocksDbWeight::get().writes(1)) } - /// Storage: Staking CounterForValidators (r:1 w:0) - /// Proof: Staking CounterForValidators (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking Validators (r:1001 w:0) - /// Proof: Staking Validators (max_values: None, max_size: Some(45), added: 2520, mode: MaxEncodedLen) + // Storage: Staking CounterForValidators (r:1 w:0) + // Storage: Staking Validators (r:501 w:0) /// The range of component `v` is `[500, 1000]`. fn get_npos_targets(v: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `983 + v * (50 ±0)` - // Estimated: `3019 + v * (2520 ±0)` - // Minimum execution time: 3_882_120 nanoseconds. - Weight::from_parts(3_951_993_000, 3019) - // Standard Error: 46_729 - .saturating_add(Weight::from_ref_time(2_856_043).saturating_mul(v.into())) - .saturating_add(RocksDbWeight::get().reads(2_u64)) + // Minimum execution time: 4_765_318 nanoseconds. + Weight::from_ref_time(4_816_708_000) + // Standard Error: 54_677 + .saturating_add(Weight::from_ref_time(3_541_818).saturating_mul(v.into())) + .saturating_add(RocksDbWeight::get().reads(2)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(v.into()))) - .saturating_add(Weight::from_proof_size(2520).saturating_mul(v.into())) } - /// Storage: Staking MinCommission (r:0 w:1) - /// Proof: Staking MinCommission (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking MinValidatorBond (r:0 w:1) - /// Proof: Staking MinValidatorBond (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - /// Storage: Staking MaxValidatorsCount (r:0 w:1) - /// Proof: Staking MaxValidatorsCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking ChillThreshold (r:0 w:1) - /// Proof: Staking ChillThreshold (max_values: Some(1), max_size: Some(1), added: 496, mode: MaxEncodedLen) - /// Storage: Staking MaxNominatorsCount (r:0 w:1) - /// Proof: Staking MaxNominatorsCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking MinNominatorBond (r:0 w:1) - /// Proof: Staking MinNominatorBond (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) + // Storage: Staking MinCommission (r:0 w:1) + // 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_configs_all_set() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 8_427 nanoseconds. - Weight::from_ref_time(8_794_000) - .saturating_add(RocksDbWeight::get().writes(6_u64)) - } - /// Storage: Staking MinCommission (r:0 w:1) - /// Proof: Staking MinCommission (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking MinValidatorBond (r:0 w:1) - /// Proof: Staking MinValidatorBond (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - /// Storage: Staking MaxValidatorsCount (r:0 w:1) - /// Proof: Staking MaxValidatorsCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking ChillThreshold (r:0 w:1) - /// Proof: Staking ChillThreshold (max_values: Some(1), max_size: Some(1), added: 496, mode: MaxEncodedLen) - /// Storage: Staking MaxNominatorsCount (r:0 w:1) - /// Proof: Staking MaxNominatorsCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking MinNominatorBond (r:0 w:1) - /// Proof: Staking MinNominatorBond (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) + // Minimum execution time: 10_480 nanoseconds. + Weight::from_ref_time(10_914_000) + .saturating_add(RocksDbWeight::get().writes(6)) + } + // Storage: Staking MinCommission (r:0 w:1) + // 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_configs_all_remove() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 7_620 nanoseconds. - Weight::from_ref_time(7_901_000) - .saturating_add(RocksDbWeight::get().writes(6_u64)) - } - /// Storage: Staking Ledger (r:1 w:0) - /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) - /// Storage: Staking Nominators (r:1 w:1) - /// Proof: Staking Nominators (max_values: None, max_size: Some(558), added: 3033, mode: MaxEncodedLen) - /// Storage: Staking ChillThreshold (r:1 w:0) - /// Proof: Staking ChillThreshold (max_values: Some(1), max_size: Some(1), added: 496, mode: MaxEncodedLen) - /// Storage: Staking MaxNominatorsCount (r:1 w:0) - /// Proof: Staking MaxNominatorsCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking CounterForNominators (r:1 w:1) - /// Proof: Staking CounterForNominators (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking MinNominatorBond (r:1 w:0) - /// Proof: Staking MinNominatorBond (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - /// Storage: Staking Validators (r:1 w:0) - /// Proof: Staking Validators (max_values: None, max_size: Some(45), added: 2520, mode: MaxEncodedLen) - /// Storage: VoterList ListNodes (r:2 w:2) - /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) - /// Storage: VoterList ListBags (r:1 w:1) - /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) - /// Storage: VoterList CounterForListNodes (r:1 w:1) - /// Proof: VoterList CounterForListNodes (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + // Minimum execution time: 9_529 nanoseconds. + Weight::from_ref_time(10_159_000) + .saturating_add(RocksDbWeight::get().writes(6)) + } + // Storage: Staking Ledger (r:1 w:0) + // Storage: Staking Nominators (r:1 w:1) + // Storage: Staking ChillThreshold (r:1 w:0) + // Storage: Staking MaxNominatorsCount (r:1 w:0) + // Storage: Staking CounterForNominators (r:1 w:1) + // Storage: Staking MinNominatorBond (r:1 w:0) + // Storage: Staking Validators (r:1 w:0) + // Storage: VoterList ListNodes (r:2 w:2) + // Storage: VoterList ListBags (r:1 w:1) + // Storage: VoterList CounterForListNodes (r:1 w:1) fn chill_other() -> Weight { - // Proof Size summary in bytes: - // Measured: `2031` - // Estimated: `19438` - // Minimum execution time: 66_188 nanoseconds. - Weight::from_parts(66_767_000, 19438) - .saturating_add(RocksDbWeight::get().reads(11_u64)) - .saturating_add(RocksDbWeight::get().writes(6_u64)) + // Minimum execution time: 81_347 nanoseconds. + Weight::from_ref_time(81_957_000) + .saturating_add(RocksDbWeight::get().reads(11)) + .saturating_add(RocksDbWeight::get().writes(6)) } - /// Storage: Staking MinCommission (r:1 w:0) - /// Proof: Staking MinCommission (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Staking Validators (r:1 w:1) - /// Proof: Staking Validators (max_values: None, max_size: Some(45), added: 2520, mode: MaxEncodedLen) + // Storage: Staking MinCommission (r:1 w:0) + // Storage: Staking Validators (r:1 w:1) fn force_apply_min_commission() -> Weight { - // Proof Size summary in bytes: - // Measured: `694` - // Estimated: `3019` - // Minimum execution time: 14_703 nanoseconds. - Weight::from_parts(15_031_000, 3019) - .saturating_add(RocksDbWeight::get().reads(2_u64)) - .saturating_add(RocksDbWeight::get().writes(1_u64)) + // Minimum execution time: 19_153 nanoseconds. + Weight::from_ref_time(19_621_000) + .saturating_add(RocksDbWeight::get().reads(2)) + .saturating_add(RocksDbWeight::get().writes(1)) } - /// Storage: Staking MinCommission (r:0 w:1) - /// Proof: Staking MinCommission (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + // Storage: Staking MinCommission (r:0 w:1) fn set_min_commission() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 4_518 nanoseconds. - Weight::from_ref_time(4_656_000) - .saturating_add(RocksDbWeight::get().writes(1_u64)) + // Minimum execution time: 6_058 nanoseconds. + Weight::from_ref_time(6_278_000) + .saturating_add(RocksDbWeight::get().writes(1)) } } From aeec8258e951b695b2aa0cca67c934f6294b4418 Mon Sep 17 00:00:00 2001 From: Ankan Date: Tue, 31 Jan 2023 14:19:58 +0100 Subject: [PATCH 067/162] remove store --- frame/staking/src/tests.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index 8e6f9ed4d7e34..f322b54be06e2 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -2449,7 +2449,7 @@ fn slash_in_old_span_does_not_deselect() { ); // the validator doesn't get chilled again - assert!(::Validators::iter().any(|(stash, _)| stash == 11)); + assert!(Validators::::iter().any(|(stash, _)| stash == 11)); // but we are still forcing a new era assert_eq!(Staking::force_era(), Forcing::ForceNew); @@ -2466,7 +2466,7 @@ fn slash_in_old_span_does_not_deselect() { ); // the validator doesn't get chilled again - assert!(::Validators::iter().any(|(stash, _)| stash == 11)); + assert!(Validators::::iter().any(|(stash, _)| stash == 11)); // but it's disabled assert!(is_disabled(10)); @@ -3209,7 +3209,7 @@ fn remove_multi_deferred() { &[Perbill::from_percent(25)], ); - assert_eq!(::UnappliedSlashes::get(&4).len(), 5); + assert_eq!(UnappliedSlashes::::get(&4).len(), 5); // fails if list is not sorted assert_noop!( @@ -3229,7 +3229,7 @@ fn remove_multi_deferred() { assert_ok!(Staking::cancel_deferred_slash(RuntimeOrigin::root(), 4, vec![0, 2, 4])); - let slashes = ::UnappliedSlashes::get(&4); + let slashes = UnappliedSlashes::::get(&4); assert_eq!(slashes.len(), 2); assert_eq!(slashes[0].validator, 21); assert_eq!(slashes[1].validator, 42); @@ -3284,7 +3284,7 @@ fn slash_kicks_validators_not_nominators_and_disables_nominator_for_kicked_valid assert_eq!(Balances::free_balance(101), 2000 - nominator_slash_amount_11); // check that validator was chilled. - assert!(::Validators::iter().all(|(stash, _)| stash != 11)); + assert!(Validators::::iter().all(|(stash, _)| stash != 11)); // actually re-bond the slashed validator assert_ok!(Staking::validate(RuntimeOrigin::signed(10), Default::default())); @@ -3630,7 +3630,7 @@ fn zero_slash_keeps_nominators() { assert_eq!(Balances::free_balance(101), 2000); // 11 is still removed.. - assert!(::Validators::iter().all(|(stash, _)| stash != 11)); + assert!(Validators::::iter().all(|(stash, _)| stash != 11)); // but their nominations are kept. assert_eq!(Staking::nominators(101).unwrap().targets, vec![11, 21]); }); From a85e4514c4862807667768fc1546b476074b4928 Mon Sep 17 00:00:00 2001 From: Ankan Date: Tue, 31 Jan 2023 14:29:48 +0100 Subject: [PATCH 068/162] [Revert] keep the same name of page size --- bin/node/runtime/src/lib.rs | 4 +-- frame/babe/src/mock.rs | 2 +- frame/fast-unstake/src/mock.rs | 2 +- frame/grandpa/src/mock.rs | 2 +- .../nomination-pools/benchmarking/src/mock.rs | 2 +- .../nomination-pools/test-staking/src/mock.rs | 2 +- frame/offences/benchmarking/src/mock.rs | 2 +- frame/root-offences/src/mock.rs | 2 +- frame/session/benchmarking/src/mock.rs | 2 +- frame/staking/README.md | 2 +- frame/staking/src/benchmarking.rs | 20 ++++++------- frame/staking/src/lib.rs | 6 ++-- frame/staking/src/mock.rs | 4 +-- frame/staking/src/pallet/impls.rs | 2 +- frame/staking/src/pallet/mod.rs | 28 +++++++++---------- frame/staking/src/tests.rs | 14 ++++++---- 16 files changed, 49 insertions(+), 47 deletions(-) diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 2c3461eccb7b3..bd8a395d15243 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -541,7 +541,7 @@ parameter_types! { pub const BondingDuration: sp_staking::EraIndex = 24 * 28; pub const SlashDeferDuration: sp_staking::EraIndex = 24 * 7; // 1/4 the bonding duration. pub const RewardCurve: &'static PiecewiseLinear<'static> = &REWARD_CURVE; - pub const MaxNominatorRewardedPerPage: u32 = 256; + pub const MaxNominatorRewardedPerValidator: u32 = 256; pub const OffendingValidatorsThreshold: Perbill = Perbill::from_percent(17); pub OffchainRepeat: BlockNumber = 5; pub HistoryDepth: u32 = 84; @@ -574,7 +574,7 @@ impl pallet_staking::Config for Runtime { type SessionInterface = Self; type EraPayout = pallet_staking::ConvertCurve; type NextNewSession = Session; - type MaxNominatorRewardedPerPage = MaxNominatorRewardedPerPage; + type MaxNominatorRewardedPerValidator = MaxNominatorRewardedPerValidator; type OffendingValidatorsThreshold = OffendingValidatorsThreshold; type ElectionProvider = ElectionProviderMultiPhase; type GenesisElectionProvider = onchain::OnChainExecution; diff --git a/frame/babe/src/mock.rs b/frame/babe/src/mock.rs index f7fd36abe67d3..abae1b7e33157 100644 --- a/frame/babe/src/mock.rs +++ b/frame/babe/src/mock.rs @@ -194,7 +194,7 @@ impl pallet_staking::Config for Test { type SessionInterface = Self; type UnixTime = pallet_timestamp::Pallet; type EraPayout = pallet_staking::ConvertCurve; - type MaxNominatorRewardedPerPage = ConstU32<64>; + type MaxNominatorRewardedPerValidator = ConstU32<64>; type OffendingValidatorsThreshold = OffendingValidatorsThreshold; type NextNewSession = Session; type ElectionProvider = onchain::OnChainExecution; diff --git a/frame/fast-unstake/src/mock.rs b/frame/fast-unstake/src/mock.rs index f74836f1a234d..38cf41fdebe8b 100644 --- a/frame/fast-unstake/src/mock.rs +++ b/frame/fast-unstake/src/mock.rs @@ -146,7 +146,7 @@ impl pallet_staking::Config for Runtime { type EraPayout = pallet_staking::ConvertCurve; type NextNewSession = (); type HistoryDepth = ConstU32<84>; - type MaxNominatorRewardedPerPage = ConstU32<64>; + type MaxNominatorRewardedPerValidator = ConstU32<64>; type OffendingValidatorsThreshold = (); type ElectionProvider = MockElection; type GenesisElectionProvider = Self::ElectionProvider; diff --git a/frame/grandpa/src/mock.rs b/frame/grandpa/src/mock.rs index addfc8cfa86d1..c618705af0651 100644 --- a/frame/grandpa/src/mock.rs +++ b/frame/grandpa/src/mock.rs @@ -198,7 +198,7 @@ impl pallet_staking::Config for Test { type SessionInterface = Self; type UnixTime = pallet_timestamp::Pallet; type EraPayout = pallet_staking::ConvertCurve; - type MaxNominatorRewardedPerPage = ConstU32<64>; + type MaxNominatorRewardedPerValidator = ConstU32<64>; type OffendingValidatorsThreshold = OffendingValidatorsThreshold; type NextNewSession = Session; type ElectionProvider = onchain::OnChainExecution; diff --git a/frame/nomination-pools/benchmarking/src/mock.rs b/frame/nomination-pools/benchmarking/src/mock.rs index 03ba816db917a..06a66838594c7 100644 --- a/frame/nomination-pools/benchmarking/src/mock.rs +++ b/frame/nomination-pools/benchmarking/src/mock.rs @@ -107,7 +107,7 @@ impl pallet_staking::Config for Runtime { type SessionInterface = (); type EraPayout = pallet_staking::ConvertCurve; type NextNewSession = (); - type MaxNominatorRewardedPerPage = ConstU32<64>; + type MaxNominatorRewardedPerValidator = ConstU32<64>; type OffendingValidatorsThreshold = (); type ElectionProvider = frame_election_provider_support::NoElection<(AccountId, BlockNumber, Staking, ())>; diff --git a/frame/nomination-pools/test-staking/src/mock.rs b/frame/nomination-pools/test-staking/src/mock.rs index e69130aa17070..c67aec0134b07 100644 --- a/frame/nomination-pools/test-staking/src/mock.rs +++ b/frame/nomination-pools/test-staking/src/mock.rs @@ -121,7 +121,7 @@ impl pallet_staking::Config for Runtime { type SessionInterface = (); type EraPayout = pallet_staking::ConvertCurve; type NextNewSession = (); - type MaxNominatorRewardedPerPage = ConstU32<64>; + type MaxNominatorRewardedPerValidator = ConstU32<64>; type OffendingValidatorsThreshold = (); type ElectionProvider = frame_election_provider_support::NoElection<(AccountId, BlockNumber, Staking, ())>; diff --git a/frame/offences/benchmarking/src/mock.rs b/frame/offences/benchmarking/src/mock.rs index bcaad06f4fa97..592e821a81d8c 100644 --- a/frame/offences/benchmarking/src/mock.rs +++ b/frame/offences/benchmarking/src/mock.rs @@ -170,7 +170,7 @@ impl pallet_staking::Config for Test { type SessionInterface = Self; type EraPayout = pallet_staking::ConvertCurve; type NextNewSession = Session; - type MaxNominatorRewardedPerPage = ConstU32<64>; + type MaxNominatorRewardedPerValidator = ConstU32<64>; type OffendingValidatorsThreshold = (); type ElectionProvider = onchain::OnChainExecution; type GenesisElectionProvider = Self::ElectionProvider; diff --git a/frame/root-offences/src/mock.rs b/frame/root-offences/src/mock.rs index 871b3632f1ec2..273fbf614169d 100644 --- a/frame/root-offences/src/mock.rs +++ b/frame/root-offences/src/mock.rs @@ -184,7 +184,7 @@ impl pallet_staking::Config for Test { type SessionInterface = Self; type EraPayout = pallet_staking::ConvertCurve; type NextNewSession = Session; - type MaxNominatorRewardedPerPage = ConstU32<64>; + type MaxNominatorRewardedPerValidator = ConstU32<64>; type OffendingValidatorsThreshold = OffendingValidatorsThreshold; type ElectionProvider = onchain::OnChainExecution; type GenesisElectionProvider = Self::ElectionProvider; diff --git a/frame/session/benchmarking/src/mock.rs b/frame/session/benchmarking/src/mock.rs index 04e8668f7e61d..0699640bc092a 100644 --- a/frame/session/benchmarking/src/mock.rs +++ b/frame/session/benchmarking/src/mock.rs @@ -172,7 +172,7 @@ impl pallet_staking::Config for Test { type SessionInterface = Self; type EraPayout = pallet_staking::ConvertCurve; type NextNewSession = Session; - type MaxNominatorRewardedPerPage = ConstU32<64>; + type MaxNominatorRewardedPerValidator = ConstU32<64>; type OffendingValidatorsThreshold = (); type ElectionProvider = onchain::OnChainExecution; type GenesisElectionProvider = Self::ElectionProvider; diff --git a/frame/staking/README.md b/frame/staking/README.md index 094b102b38955..2958ecf8dc2fb 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. Rewards are paged to maximum of [`Config::MaxNominatorRewardedPerPage`] +validator as well as its nominators. Rewards are paged to maximum of [`Config::MaxNominatorRewardedPerValidator`] nominators per call. Each page of staker payout needs to be called separately to ensure all nominators are paid. This is to limit the i/o cost to mutate storage for each nominator's account. diff --git a/frame/staking/src/benchmarking.rs b/frame/staking/src/benchmarking.rs index 5f3a47e81227f..9d492fad5e9c2 100644 --- a/frame/staking/src/benchmarking.rs +++ b/frame/staking/src/benchmarking.rs @@ -546,10 +546,10 @@ benchmarks! { } payout_stakers_dead_controller { - let n in 0 .. T::MaxNominatorRewardedPerPage::get() as u32; + let n in 0 .. T::MaxNominatorRewardedPerValidator::get() as u32; let (validator, nominators) = create_validator_with_nominators::( n, - T::MaxNominatorRewardedPerPage::get() as u32, + T::MaxNominatorRewardedPerValidator::get() as u32, true, RewardDestination::Controller, )?; @@ -579,10 +579,10 @@ benchmarks! { } payout_stakers_alive_staked { - let n in 0 .. T::MaxNominatorRewardedPerPage::get() as u32; + let n in 0 .. T::MaxNominatorRewardedPerValidator::get() as u32; let (validator, nominators) = create_validator_with_nominators::( n, - T::MaxNominatorRewardedPerPage::get() as u32, + T::MaxNominatorRewardedPerValidator::get() as u32, false, RewardDestination::Staked, )?; @@ -615,10 +615,10 @@ benchmarks! { } payout_stakers_nominators_only { - let n in 1 .. T::MaxNominatorRewardedPerPage::get() as u32; - // create nominators between MaxNominatorRewardedPerPage+1 .. =2 * MaxNominatorRewardedPerPage - let nominator_lower_bound = T::MaxNominatorRewardedPerPage::get(); - let nominator_upper_bound = 2 * T::MaxNominatorRewardedPerPage::get(); + let n in 1 .. T::MaxNominatorRewardedPerValidator::get() as u32; + // create nominators between MaxNominatorRewardedPerValidator+1 .. =2 * MaxNominatorRewardedPerValidator + let nominator_lower_bound = T::MaxNominatorRewardedPerValidator::get(); + let nominator_upper_bound = 2 * T::MaxNominatorRewardedPerValidator::get(); let (validator, nominators) = create_validator_with_nominators::( nominator_lower_bound + n, @@ -1025,7 +1025,7 @@ mod tests { let (validator_stash, nominators) = create_validator_with_nominators::( n, - <::MaxNominatorRewardedPerPage as Get<_>>::get(), + <::MaxNominatorRewardedPerValidator as Get<_>>::get(), false, RewardDestination::Staked, ) @@ -1055,7 +1055,7 @@ mod tests { let (validator_stash, _nominators) = create_validator_with_nominators::( n, - <::MaxNominatorRewardedPerPage as Get<_>>::get(), + <::MaxNominatorRewardedPerValidator as Get<_>>::get(), false, RewardDestination::Staked, ) diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index 8024d3e3d37c9..39e9dd0f48075 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::MaxNominatorRewardedPerPage`] +//! validator as well as its nominators. Only the [`Config::MaxNominatorRewardedPerValidator`] //! biggest stakers can claim their reward. This is to limit the i/o cost to mutate storage for each //! nominator's account. //! @@ -228,8 +228,8 @@ //! validator, proportional to the value staked behind the validator (_i.e._ dividing the //! [`own`](Exposure::own) or [`others`](Exposure::others) by [`total`](Exposure::total) in //! [`Exposure`]). Note that payouts are made in pages with each page capped at -//! [`Config::MaxNominatorRewardedPerPage`] nominators. The distribution of nominators across pages -//! are unsorted and depends on the election result provided by [`Config::ElectionProvider`]. +//! [`Config::MaxNominatorRewardedPerValidator`] nominators. The distribution of nominators across +//! pages are unsorted and depends on the election result provided by [`Config::ElectionProvider`]. //! //! All entities who receive a reward have the option to choose their reward destination through the //! [`Payee`] storage item (see diff --git a/frame/staking/src/mock.rs b/frame/staking/src/mock.rs index 1b737599e3080..edf8d29645a55 100644 --- a/frame/staking/src/mock.rs +++ b/frame/staking/src/mock.rs @@ -232,7 +232,7 @@ parameter_types! { pub static BagThresholds: &'static [sp_npos_elections::VoteWeight] = &THRESHOLDS; pub static MaxNominations: u32 = 16; pub static HistoryDepth: u32 = 80; - pub static MaxNominatorRewardedPerPage: u32 = 64; + pub static MaxNominatorRewardedPerValidator: u32 = 64; pub static MaxUnlockingChunks: u32 = 32; pub static RewardOnUnbalanceWasCalled: bool = false; pub static LedgerSlashPerEra: (BalanceOf, BTreeMap>) = (Zero::zero(), BTreeMap::new()); @@ -295,7 +295,7 @@ impl crate::pallet::pallet::Config for Test { type SessionInterface = Self; type EraPayout = ConvertCurve; type NextNewSession = Session; - type MaxNominatorRewardedPerPage = MaxNominatorRewardedPerPage; + type MaxNominatorRewardedPerValidator = MaxNominatorRewardedPerValidator; type OffendingValidatorsThreshold = OffendingValidatorsThreshold; type ElectionProvider = onchain::OnChainExecution; type GenesisElectionProvider = Self::ElectionProvider; diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index 8ac0b12eff194..acb995ed24320 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -259,7 +259,7 @@ impl Pallet { } T::Reward::on_unbalanced(total_imbalance); - debug_assert!(nominator_payout_count <= T::MaxNominatorRewardedPerPage::get()); + debug_assert!(nominator_payout_count <= T::MaxNominatorRewardedPerValidator::get()); let payout_weight = if page == 0 { T::WeightInfo::payout_stakers_alive_staked(nominator_payout_count) diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index c9220f672d949..d50ce25d7afa6 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -203,12 +203,12 @@ pub mod pallet { /// The maximum number of nominators rewarded for each validator. /// - /// A reward payout is restricted to a maximum of `MaxNominatorRewardedPerPage` nominators - /// in a single call. This used to limit the i/o cost for the nominator payout. + /// A reward payout is restricted to a maximum of `MaxNominatorRewardedPerValidator` + /// nominators in a single call. This used to limit the i/o cost for the nominator payout. /// See call `payout_stakers` for more details. /// // TODO(ank4n) keep old one and create new one. #[pallet::constant] - type MaxNominatorRewardedPerPage: Get; + type MaxNominatorRewardedPerValidator: Get; /// The fraction of the validator set that is safe to be offending. /// After the threshold is reached a new era will be forced. @@ -445,7 +445,7 @@ pub mod pallet { /// New `Exposure`s are stored in a paged manner in `ErasStakersPaged` instead. /// /// This is similar to [`ErasStakers`] but number of nominators exposed is reduced to the - /// `T::MaxNominatorRewardedPerPage` biggest stakers. + /// `T::MaxNominatorRewardedPerValidator` 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. /// @@ -719,7 +719,7 @@ pub mod pallet { >::insert(era, &validator, &exposure); let (exposure_overview, exposure_pages) = - exposure.as_pages(T::MaxNominatorRewardedPerPage::get()); + exposure.as_pages(T::MaxNominatorRewardedPerValidator::get()); >::insert(era, &validator, &exposure_overview); exposure_pages.iter().enumerate().for_each(|(page, paged_exposure)| { @@ -1660,21 +1660,21 @@ pub mod pallet { /// - `validator_stash` is the stash account of the validator. /// - `era` may be any era between `[current_era - history_depth; current_era]`. /// - `page` is the page index of nominators to pay out with value between 0 and - /// `num_nominators / T::MaxNominatorRewardedPerPage`. + /// `num_nominators / T::MaxNominatorRewardedPerValidator`. /// /// The origin of this call must be _Signed_. Any account can call this function, even if /// it is not one of the stakers. /// - /// If a validator has more than `T::MaxMaxNominatorRewardedPerPage` nominators backing + /// If a validator has more than `T::MaxMaxNominatorRewardedPerValidator` nominators backing /// them, then the list of nominators is paged, with each page being capped at - /// `T::MaxNominatorRewardedPerPage`. If a validator has more than one page of nominators, - /// the call needs to be made for each page separately in order for all the nominators - /// backing a validator receive the reward. The nominators are not sorted across pages and - /// so it should not be assumed the highest staker would be on the topmost page and vice - /// versa. If rewards are not claimed in `${HistoryDepth}` eras, they are lost. + /// `T::MaxNominatorRewardedPerValidator`. If a validator has more than one page of + /// nominators, the call needs to be made for each page separately in order for all the + /// nominators backing a validator receive the reward. The nominators are not sorted across + /// pages and so it should not be assumed the highest staker would be on the topmost page + /// and vice versa. If rewards are not claimed in `${HistoryDepth}` eras, they are lost. /// /// # - /// - Time complexity: at most O(MaxNominatorRewardedPerPage). + /// - Time complexity: at most O(MaxNominatorRewardedPerValidator). /// - Contains a limited number of reads and writes. /// ----------- /// N is the Number of payouts for the validator (including the validator) @@ -1687,7 +1687,7 @@ pub mod pallet { /// # #[pallet::call_index(18)] #[pallet::weight(T::WeightInfo::payout_stakers_alive_staked( - T::MaxNominatorRewardedPerPage::get() + T::MaxNominatorRewardedPerValidator::get() ))] pub fn payout_stakers( origin: OriginFor, diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index f322b54be06e2..db7096856be7c 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -2195,7 +2195,8 @@ fn reward_validator_slashing_validator_does_not_overflow() { let _ = Balances::make_free_balance_be(&11, stake); let exposure = Exposure:: { total: stake, own: stake, others: vec![] }; - let (exposure_overview, _) = exposure.clone().as_pages(MaxNominatorRewardedPerPage::get()); + let (exposure_overview, _) = + exposure.clone().as_pages(MaxNominatorRewardedPerValidator::get()); let reward = EraRewardPoints:: { total: 1, individual: vec![(11, 1)].into_iter().collect(), @@ -3700,7 +3701,7 @@ fn six_session_delay() { fn test_nominators_are_rewarded_for_all_exposure_page() { ExtBuilder::default().build_and_execute(|| { // 3 pages of exposure - let nominator_count = 2 * MaxNominatorRewardedPerPage::get() + 1; + let nominator_count = 2 * MaxNominatorRewardedPerValidator::get() + 1; for i in 0..nominator_count { let stash = 10_000 + i as AccountId; @@ -3765,7 +3766,7 @@ fn test_multi_page_payout_stakers() { mock::start_active_era(1); Staking::reward_by_ids(vec![(11, 1)]); - // Since `MaxNominatorRewardedPerPage = 64`, there are two pages of validator exposure. + // Since `MaxNominatorRewardedPerValidator = 64`, there are two pages of validator exposure. assert_eq!(EraInfo::::get_page_count(1, &11), 2); // compute and ensure the reward amount is greater than zero. @@ -4057,7 +4058,8 @@ fn test_commission_paid_only_once() { mock::start_active_era(1); Staking::reward_by_ids(vec![(11, 1)]); - // Since `MaxNominatorRewardedPerPage = 64`, there are four pages of validator exposure. + // Since `MaxNominatorRewardedPerValidator = 64`, there are four pages of validator + // exposure. assert_eq!(EraInfo::::get_page_count(1, &11), 4); // compute and ensure the reward amount is greater than zero. @@ -4090,7 +4092,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 = MaxNominatorRewardedPerPage::get(); + let max_nom_rewarded = MaxNominatorRewardedPerValidator::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; @@ -5940,7 +5942,7 @@ fn test_validator_exposure_is_backward_compatible_with_non_paged_rewards_payout( ExtBuilder::default().has_stakers(false).build_and_execute(|| { // case 1: exposure exist in clipped. // set page cap to 10 - MaxNominatorRewardedPerPage::set(10); + MaxNominatorRewardedPerValidator::set(10); bond_validator(11, 10, 1000); let mut expected_individual_exposures: Vec> = vec![]; let mut total_exposure: Balance = 0; From b83213061187d1dcd8d9cd99f33b2abc74cd8de2 Mon Sep 17 00:00:00 2001 From: Ankan Date: Tue, 31 Jan 2023 14:36:27 +0100 Subject: [PATCH 069/162] consume exposure --- frame/staking/src/lib.rs | 4 ++-- frame/staking/src/pallet/mod.rs | 4 ++-- frame/staking/src/tests.rs | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index 39e9dd0f48075..9b75b0b7d4f34 100644 --- a/frame/staking/src/lib.rs +++ b/frame/staking/src/lib.rs @@ -736,8 +736,8 @@ impl { /// Splits an `Exposure` into `ExposureOverview` and multiple chunks of `IndividualExposure` /// with each chunk having maximum of `page_size` elements. - fn as_pages( - &self, + fn into_pages( + self, page_size: u32, ) -> (ExposureOverview, Vec>) { let individual_chunks = self.others.chunks(page_size as usize); diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index d50ce25d7afa6..d3d5839697c5c 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -206,7 +206,7 @@ pub mod pallet { /// A reward payout is restricted to a maximum of `MaxNominatorRewardedPerValidator` /// nominators in a single call. This used to limit the i/o cost for the nominator payout. /// See call `payout_stakers` for more details. - /// // TODO(ank4n) keep old one and create new one. + // TODO(ank4n): Should we change this name? Breaking changes! #[pallet::constant] type MaxNominatorRewardedPerValidator: Get; @@ -719,7 +719,7 @@ pub mod pallet { >::insert(era, &validator, &exposure); let (exposure_overview, exposure_pages) = - exposure.as_pages(T::MaxNominatorRewardedPerValidator::get()); + exposure.into_pages(T::MaxNominatorRewardedPerValidator::get()); >::insert(era, &validator, &exposure_overview); exposure_pages.iter().enumerate().for_each(|(page, paged_exposure)| { diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index db7096856be7c..9c017a53c145b 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -2196,7 +2196,7 @@ fn reward_validator_slashing_validator_does_not_overflow() { let exposure = Exposure:: { total: stake, own: stake, others: vec![] }; let (exposure_overview, _) = - exposure.clone().as_pages(MaxNominatorRewardedPerValidator::get()); + exposure.clone().into_pages(MaxNominatorRewardedPerValidator::get()); let reward = EraRewardPoints:: { total: 1, individual: vec![(11, 1)].into_iter().collect(), @@ -5789,7 +5789,7 @@ fn can_page_exposure() { let (exposure_overview, exposure_page): ( ExposureOverview, Vec>, - ) = exposure.clone().as_pages(3); + ) = exposure.clone().into_pages(3); // then // 7 pages of nominators. From 5d215c6099eededdba1167377aea5aea2e3457fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Sat, 28 Jan 2023 20:10:40 +0100 Subject: [PATCH 070/162] sc-finality-grandpa: Warp proof generation can not expect justifications (#13249) When a node is running with `--blocks-pruning` it will also prunes justifications. So, the warp proof generation can not use `expect` for unwrapping the justification. --- client/cli/src/params/pruning_params.rs | 1 + client/finality-grandpa/src/warp_proof.rs | 6 +----- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/client/cli/src/params/pruning_params.rs b/client/cli/src/params/pruning_params.rs index fd01ba67bab7d..66282fd08848c 100644 --- a/client/cli/src/params/pruning_params.rs +++ b/client/cli/src/params/pruning_params.rs @@ -49,6 +49,7 @@ pub struct PruningParams { /// [default: 256] #[arg(alias = "pruning", long, value_name = "PRUNING_MODE")] pub state_pruning: Option, + /// Specify the blocks pruning mode. /// /// This mode specifies when the block's body (including justifications) diff --git a/client/finality-grandpa/src/warp_proof.rs b/client/finality-grandpa/src/warp_proof.rs index c65a705d3e844..1169083ea1d51 100644 --- a/client/finality-grandpa/src/warp_proof.rs +++ b/client/finality-grandpa/src/warp_proof.rs @@ -135,11 +135,7 @@ impl WarpSyncProof { let justification = blockchain .justifications(header.hash())? .and_then(|just| just.into_justification(GRANDPA_ENGINE_ID)) - .expect( - "header is last in set and contains standard change signal; \ - must have justification; \ - qed.", - ); + .ok_or_else(|| Error::MissingData)?; let justification = GrandpaJustification::::decode(&mut &justification[..])?; From d7e4a566766aff791f0fd94de7873df2cf9fe449 Mon Sep 17 00:00:00 2001 From: Qinxuan Chen Date: Sun, 29 Jan 2023 03:43:32 +0800 Subject: [PATCH 071/162] update criterion to v0.4.0 (#13142) --- Cargo.lock | 129 ++++++++++++++--------------- bin/node/cli/Cargo.toml | 2 +- bin/node/executor/Cargo.toml | 2 +- client/db/Cargo.toml | 2 +- client/executor/Cargo.toml | 2 +- client/tracing/Cargo.toml | 2 +- client/transaction-pool/Cargo.toml | 2 +- frame/system/Cargo.toml | 2 +- primitives/api/test/Cargo.toml | 2 +- primitives/arithmetic/Cargo.toml | 2 +- primitives/core/Cargo.toml | 4 +- primitives/core/benches/bench.rs | 5 +- primitives/trie/Cargo.toml | 4 +- 13 files changed, 78 insertions(+), 82 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6aafb0e175d98..c075f065fdd90 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -167,6 +167,12 @@ dependencies = [ "libc", ] +[[package]] +name = "anes" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" + [[package]] name = "ansi_term" version = "0.12.1" @@ -705,10 +711,7 @@ version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223" dependencies = [ - "lazy_static", "memchr", - "regex-automata", - "serde", ] [[package]] @@ -914,6 +917,33 @@ dependencies = [ "winapi", ] +[[package]] +name = "ciborium" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0c137568cc60b904a7724001b35ce2630fd00d5d84805fbb608ab89509d788f" +dependencies = [ + "ciborium-io", + "ciborium-ll", + "serde", +] + +[[package]] +name = "ciborium-io" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "346de753af073cc87b52b2083a506b38ac176a44cfb05497b622e27be899b369" + +[[package]] +name = "ciborium-ll" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "213030a2b5a4e0c0892b6652260cf6ccac84827b83a85a534e178e3906c4cf1b" +dependencies = [ + "ciborium-io", + "half", +] + [[package]] name = "cid" version = "0.8.6" @@ -967,13 +997,14 @@ dependencies = [ [[package]] name = "clap" -version = "2.34.0" +version = "3.2.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" +checksum = "71655c45cb9845d3270c9d6df84ebe72b4dad3c2ba3f7023ad47c144e4e473a5" dependencies = [ "bitflags", + "clap_lex 0.2.4", + "indexmap", "textwrap", - "unicode-width", ] [[package]] @@ -984,7 +1015,7 @@ checksum = "a7db700bc935f9e43e88d00b0850dae18a63773cfbec6d8e070fccf7fef89a39" dependencies = [ "bitflags", "clap_derive", - "clap_lex", + "clap_lex 0.3.0", "is-terminal", "once_cell", "strsim", @@ -1013,6 +1044,15 @@ dependencies = [ "syn", ] +[[package]] +name = "clap_lex" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5" +dependencies = [ + "os_str_bytes", +] + [[package]] name = "clap_lex" version = "0.3.0" @@ -1243,15 +1283,16 @@ dependencies = [ [[package]] name = "criterion" -version = "0.3.6" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b01d6de93b2b6c65e17c634a26653a29d107b3c98c607c765bf38d041531cd8f" +checksum = "e7c76e09c1aae2bc52b3d2f29e13c6572553b30c4aa1b8a49fd70de6412654cb" dependencies = [ + "anes", "atty", "cast", - "clap 2.34.0", + "ciborium", + "clap 3.2.23", "criterion-plot", - "csv", "futures", "itertools", "lazy_static", @@ -1261,7 +1302,6 @@ dependencies = [ "rayon", "regex", "serde", - "serde_cbor", "serde_derive", "serde_json", "tinytemplate", @@ -1271,9 +1311,9 @@ dependencies = [ [[package]] name = "criterion-plot" -version = "0.4.5" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2673cc8207403546f45f5fd319a974b1e6983ad1a3ee7e6041650013be041876" +checksum = "6b50826342786a51a89e2da3a28f1c32b06e387201bc2d19791f622c673706b1" dependencies = [ "cast", "itertools", @@ -1380,28 +1420,6 @@ dependencies = [ "subtle", ] -[[package]] -name = "csv" -version = "1.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22813a6dc45b335f9bade10bf7271dc477e81113e89eb251a0bc2a8a81c536e1" -dependencies = [ - "bstr 0.2.17", - "csv-core", - "itoa 0.4.8", - "ryu", - "serde", -] - -[[package]] -name = "csv-core" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b2466559f260f48ad25fe6317b3c8dac77b5bdb5763ac7d9d6103530663bc90" -dependencies = [ - "memchr", -] - [[package]] name = "ctor" version = "0.1.26" @@ -2976,7 +2994,7 @@ checksum = "75f43d41e26995c17e71ee126451dd3941010b0514a81a9d11f3b341debc2399" dependencies = [ "bytes", "fnv", - "itoa 1.0.5", + "itoa", ] [[package]] @@ -3029,7 +3047,7 @@ dependencies = [ "http-body", "httparse", "httpdate", - "itoa 1.0.5", + "itoa", "pin-project-lite 0.2.9", "socket2", "tokio", @@ -3277,12 +3295,6 @@ dependencies = [ "either", ] -[[package]] -name = "itoa" -version = "0.4.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" - [[package]] name = "itoa" version = "1.0.5" @@ -5083,7 +5095,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a652d9771a63711fd3c3deb670acfbe5c30a4072e664d7a3bf5a9e1056ac72c3" dependencies = [ "arrayvec 0.7.2", - "itoa 1.0.5", + "itoa", ] [[package]] @@ -7188,7 +7200,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "83cd1b99916654a69008fd66b4f9397fbe08e6e51dfe23d4417acf5d3b8cb87c" dependencies = [ "dtoa", - "itoa 1.0.5", + "itoa", "parking_lot 0.12.1", "prometheus-client-derive-text-encode", ] @@ -9380,16 +9392,6 @@ dependencies = [ "serde_derive", ] -[[package]] -name = "serde_cbor" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bef2ebfde456fb76bbcf9f59315333decc4fda0b2b44b420243c11e0f5ec1f5" -dependencies = [ - "half", - "serde", -] - [[package]] name = "serde_derive" version = "1.0.152" @@ -9407,7 +9409,7 @@ version = "1.0.91" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "877c235533714907a8c2464236f5c4b2a17262ef1bd71f38f35ea592c8da6883" dependencies = [ - "itoa 1.0.5", + "itoa", "ryu", "serde", ] @@ -10945,12 +10947,9 @@ checksum = "95059e91184749cb66be6dc994f67f182b6d897cb3df74a5bf66b5e709295fd8" [[package]] name = "textwrap" -version = "0.11.0" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" -dependencies = [ - "unicode-width", -] +checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d" [[package]] name = "thiserror" @@ -11024,7 +11023,7 @@ version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a561bf4617eebd33bca6434b988f39ed798e527f51a1e797d0ee4f61c0a38376" dependencies = [ - "itoa 1.0.5", + "itoa", "serde", "time-core", "time-macros", @@ -11338,9 +11337,9 @@ dependencies = [ [[package]] name = "trie-bench" -version = "0.33.0" +version = "0.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5b26bd2cdd7641c5beb476b314c0cb1f629832bf21a6235f545e2d47bc9d05a" +checksum = "2fbb0a830db7c42ae97ce4e21b30e2cf9dbcc1b4f7853bd1aedad3d806c281d0" dependencies = [ "criterion", "hash-db", diff --git a/bin/node/cli/Cargo.toml b/bin/node/cli/Cargo.toml index b55b35c05652d..c529c7c9b8dfd 100644 --- a/bin/node/cli/Cargo.toml +++ b/bin/node/cli/Cargo.toml @@ -122,7 +122,7 @@ serde_json = "1.0" regex = "1.6.0" platforms = "2.0" soketto = "0.7.1" -criterion = { version = "0.3.5", features = ["async_tokio"] } +criterion = { version = "0.4.0", features = ["async_tokio"] } tokio = { version = "1.22.0", features = ["macros", "time", "parking_lot"] } tokio-util = { version = "0.7.4", features = ["compat"] } wait-timeout = "0.2" diff --git a/bin/node/executor/Cargo.toml b/bin/node/executor/Cargo.toml index edcc4df9c8176..ffa8d38ee4b34 100644 --- a/bin/node/executor/Cargo.toml +++ b/bin/node/executor/Cargo.toml @@ -26,7 +26,7 @@ sp-tracing = { version = "6.0.0", path = "../../../primitives/tracing" } sp-trie = { version = "7.0.0", path = "../../../primitives/trie" } [dev-dependencies] -criterion = "0.3.0" +criterion = "0.4.0" futures = "0.3.21" wat = "1.0" frame-support = { version = "4.0.0-dev", path = "../../../frame/support" } diff --git a/client/db/Cargo.toml b/client/db/Cargo.toml index a9f5e28c73159..7a62cb1ea0f53 100644 --- a/client/db/Cargo.toml +++ b/client/db/Cargo.toml @@ -36,7 +36,7 @@ sp-state-machine = { version = "0.13.0", path = "../../primitives/state-machine" sp-trie = { version = "7.0.0", path = "../../primitives/trie" } [dev-dependencies] -criterion = "0.3.3" +criterion = "0.4.0" kvdb-rocksdb = "0.17.0" rand = "0.8.5" tempfile = "3.1.0" diff --git a/client/executor/Cargo.toml b/client/executor/Cargo.toml index 8bedcd3edcff3..46b72565afefc 100644 --- a/client/executor/Cargo.toml +++ b/client/executor/Cargo.toml @@ -46,7 +46,7 @@ sc-tracing = { version = "4.0.0-dev", path = "../tracing" } tracing-subscriber = "0.2.19" paste = "1.0" regex = "1.6.0" -criterion = "0.3" +criterion = "0.4.0" env_logger = "0.9" num_cpus = "1.13.1" tempfile = "3.3.0" diff --git a/client/tracing/Cargo.toml b/client/tracing/Cargo.toml index be6237a344f52..9312c04e9f6db 100644 --- a/client/tracing/Cargo.toml +++ b/client/tracing/Cargo.toml @@ -39,7 +39,7 @@ sp-runtime = { version = "7.0.0", path = "../../primitives/runtime" } sp-tracing = { version = "6.0.0", path = "../../primitives/tracing" } [dev-dependencies] -criterion = "0.3" +criterion = "0.4.0" [[bench]] name = "bench" diff --git a/client/transaction-pool/Cargo.toml b/client/transaction-pool/Cargo.toml index bbb5ebae440a0..6338f8127aa1c 100644 --- a/client/transaction-pool/Cargo.toml +++ b/client/transaction-pool/Cargo.toml @@ -37,7 +37,7 @@ sp-transaction-pool = { version = "4.0.0-dev", path = "../../primitives/transact [dev-dependencies] array-bytes = "4.1" assert_matches = "1.3.0" -criterion = "0.3" +criterion = "0.4.0" sc-block-builder = { version = "0.10.0-dev", path = "../block-builder" } sp-consensus = { version = "0.10.0-dev", path = "../../primitives/consensus/common" } substrate-test-runtime = { version = "2.0.0", path = "../../test-utils/runtime" } diff --git a/frame/system/Cargo.toml b/frame/system/Cargo.toml index 7f573a9cbd575..5a6c89aae32ea 100644 --- a/frame/system/Cargo.toml +++ b/frame/system/Cargo.toml @@ -26,7 +26,7 @@ sp-version = { version = "5.0.0", default-features = false, path = "../../primit sp-weights = { version = "4.0.0", default-features = false, path = "../../primitives/weights" } [dev-dependencies] -criterion = "0.3.3" +criterion = "0.4.0" sp-externalities = { version = "0.13.0", path = "../../primitives/externalities" } substrate-test-runtime-client = { version = "2.0.0", path = "../../test-utils/runtime/client" } diff --git a/primitives/api/test/Cargo.toml b/primitives/api/test/Cargo.toml index b3ceb14fe0d66..5b6c144ef3f6b 100644 --- a/primitives/api/test/Cargo.toml +++ b/primitives/api/test/Cargo.toml @@ -25,7 +25,7 @@ trybuild = "1.0.74" rustversion = "1.0.6" [dev-dependencies] -criterion = "0.3.0" +criterion = "0.4.0" futures = "0.3.21" log = "0.4.17" sp-core = { version = "7.0.0", path = "../../core" } diff --git a/primitives/arithmetic/Cargo.toml b/primitives/arithmetic/Cargo.toml index bbb4bbd1776b1..b3fc6abc33ffd 100644 --- a/primitives/arithmetic/Cargo.toml +++ b/primitives/arithmetic/Cargo.toml @@ -26,7 +26,7 @@ static_assertions = "1.1.0" sp-std = { version = "5.0.0", default-features = false, path = "../std" } [dev-dependencies] -criterion = "0.3" +criterion = "0.4.0" primitive-types = "0.12.0" sp-core = { version = "7.0.0", features = ["full_crypto"], path = "../core" } rand = "0.8.5" diff --git a/primitives/core/Cargo.toml b/primitives/core/Cargo.toml index f9a522178f4c8..5fd838de3538d 100644 --- a/primitives/core/Cargo.toml +++ b/primitives/core/Cargo.toml @@ -25,7 +25,7 @@ impl-serde = { version = "0.4.0", optional = true } hash-db = { version = "0.15.2", default-features = false } hash256-std-hasher = { version = "0.15.2", default-features = false } base58 = { version = "0.2.0", optional = true } -rand = { version = "0.8.5", optional = true, features = ["small_rng"] } +rand = { version = "0.8.5", features = ["small_rng"], optional = true } substrate-bip39 = { version = "0.4.4", optional = true } tiny-bip39 = { version = "1.0.0", optional = true } regex = { version = "1.6.0", optional = true } @@ -60,7 +60,7 @@ sp-runtime-interface = { version = "7.0.0", default-features = false, path = ".. [dev-dependencies] sp-serializer = { version = "4.0.0-dev", path = "../serializer" } rand = "0.8.5" -criterion = "0.3.3" +criterion = "0.4.0" serde_json = "1.0" sp-core-hashing-proc-macro = { version = "5.0.0", path = "./hashing/proc-macro" } diff --git a/primitives/core/benches/bench.rs b/primitives/core/benches/bench.rs index 53421278dca26..77e5bb63fef7a 100644 --- a/primitives/core/benches/bench.rs +++ b/primitives/core/benches/bench.rs @@ -12,10 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -#[macro_use] -extern crate criterion; - -use criterion::{black_box, Bencher, BenchmarkId, Criterion}; +use criterion::{black_box, criterion_group, criterion_main, Bencher, BenchmarkId, Criterion}; use sp_core::{ crypto::Pair as _, hashing::{blake2_128, twox_128}, diff --git a/primitives/trie/Cargo.toml b/primitives/trie/Cargo.toml index 78b0b5d1bbda3..1e83a5d6dfec5 100644 --- a/primitives/trie/Cargo.toml +++ b/primitives/trie/Cargo.toml @@ -37,8 +37,8 @@ schnellru = { version = "0.2.1", optional = true } [dev-dependencies] array-bytes = "4.1" -criterion = "0.3.3" -trie-bench = "0.33.0" +criterion = "0.4.0" +trie-bench = "0.34.0" trie-standardmap = "0.15.2" sp-runtime = { version = "7.0.0", path = "../runtime" } From 3ec657673c5d19037dde1fece706246cce984453 Mon Sep 17 00:00:00 2001 From: Shawn Tabrizi Date: Sun, 29 Jan 2023 13:23:15 -0300 Subject: [PATCH 072/162] fix up template (#13205) --- bin/node-template/pallets/template/Cargo.toml | 6 +++--- bin/node-template/pallets/template/src/mock.rs | 5 ++--- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/bin/node-template/pallets/template/Cargo.toml b/bin/node-template/pallets/template/Cargo.toml index 6dec5c8da6e5d..f6607b25c4d62 100644 --- a/bin/node-template/pallets/template/Cargo.toml +++ b/bin/node-template/pallets/template/Cargo.toml @@ -22,9 +22,9 @@ frame-support = { version = "4.0.0-dev", default-features = false, path = "../.. frame-system = { version = "4.0.0-dev", default-features = false, path = "../../../../frame/system" } [dev-dependencies] -sp-core = { version = "7.0.0", default-features = false, path = "../../../../primitives/core" } -sp-io = { version = "7.0.0", default-features = false, path = "../../../../primitives/io" } -sp-runtime = { version = "7.0.0", default-features = false, path = "../../../../primitives/runtime" } +sp-core = { version = "7.0.0", path = "../../../../primitives/core" } +sp-io = { version = "7.0.0", path = "../../../../primitives/io" } +sp-runtime = { version = "7.0.0", path = "../../../../primitives/runtime" } [features] default = ["std"] diff --git a/bin/node-template/pallets/template/src/mock.rs b/bin/node-template/pallets/template/src/mock.rs index 989681fa59a00..91a1bf6ed5fc8 100644 --- a/bin/node-template/pallets/template/src/mock.rs +++ b/bin/node-template/pallets/template/src/mock.rs @@ -1,6 +1,5 @@ use crate as pallet_template; use frame_support::traits::{ConstU16, ConstU64}; -use frame_system as system; use sp_core::H256; use sp_runtime::{ testing::Header, @@ -22,7 +21,7 @@ frame_support::construct_runtime!( } ); -impl system::Config for Test { +impl frame_system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = (); type BlockLength = (); @@ -55,5 +54,5 @@ impl pallet_template::Config for Test { // Build genesis storage according to the mock runtime. pub fn new_test_ext() -> sp_io::TestExternalities { - system::GenesisConfig::default().build_storage::().unwrap().into() + frame_system::GenesisConfig::default().build_storage::().unwrap().into() } From dca583b69c11b0fe21878e607e8b35bca1422d5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Sun, 29 Jan 2023 21:56:10 +0100 Subject: [PATCH 073/162] Remove `uncles` related code (#13216) The code was added without any clear usage. The inherent for example is not benchmarked and not used. --- Cargo.lock | 24 - Cargo.toml | 2 - bin/node/cli/Cargo.toml | 2 - bin/node/cli/src/service.rs | 12 +- bin/node/runtime/src/lib.rs | 6 - client/consensus/uncles/Cargo.toml | 19 - client/consensus/uncles/README.md | 3 - client/consensus/uncles/src/lib.rs | 45 -- frame/authorship/Cargo.toml | 2 - frame/authorship/src/lib.rs | 602 +----------------- frame/babe/src/mock.rs | 20 +- frame/grandpa/src/mock.rs | 20 +- frame/im-online/src/lib.rs | 4 - frame/im-online/src/mock.rs | 2 - frame/im-online/src/tests.rs | 5 +- frame/staking/src/mock.rs | 18 +- frame/staking/src/pallet/impls.rs | 10 - frame/staking/src/tests.rs | 9 +- .../asset-tx-payment/src/mock.rs | 14 +- primitives/authorship/Cargo.toml | 30 - primitives/authorship/README.md | 3 - primitives/authorship/src/lib.rs | 101 --- 22 files changed, 47 insertions(+), 906 deletions(-) delete mode 100644 client/consensus/uncles/Cargo.toml delete mode 100644 client/consensus/uncles/README.md delete mode 100644 client/consensus/uncles/src/lib.rs delete mode 100644 primitives/authorship/Cargo.toml delete mode 100644 primitives/authorship/README.md delete mode 100644 primitives/authorship/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index c075f065fdd90..29ddf38328519 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4772,7 +4772,6 @@ dependencies = [ "sc-consensus-babe", "sc-consensus-epochs", "sc-consensus-slots", - "sc-consensus-uncles", "sc-executor", "sc-finality-grandpa", "sc-keystore", @@ -4792,7 +4791,6 @@ dependencies = [ "soketto", "sp-api", "sp-authority-discovery", - "sp-authorship", "sp-blockchain", "sp-consensus", "sp-consensus-babe", @@ -5379,7 +5377,6 @@ dependencies = [ "impl-trait-for-tuples", "parity-scale-codec", "scale-info", - "sp-authorship", "sp-core", "sp-io", "sp-runtime", @@ -8299,16 +8296,6 @@ dependencies = [ "substrate-test-runtime-client", ] -[[package]] -name = "sc-consensus-uncles" -version = "0.10.0-dev" -dependencies = [ - "sc-client-api", - "sp-authorship", - "sp-runtime", - "thiserror", -] - [[package]] name = "sc-executor" version = "0.10.0-dev" @@ -9714,17 +9701,6 @@ dependencies = [ "sp-std", ] -[[package]] -name = "sp-authorship" -version = "4.0.0-dev" -dependencies = [ - "async-trait", - "parity-scale-codec", - "sp-inherents", - "sp-runtime", - "sp-std", -] - [[package]] name = "sp-beefy" version = "4.0.0-dev" diff --git a/Cargo.toml b/Cargo.toml index bb52305162ef1..b004886e83f9a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -32,7 +32,6 @@ members = [ "client/consensus/manual-seal", "client/consensus/pow", "client/consensus/slots", - "client/consensus/uncles", "client/db", "client/executor", "client/executor/common", @@ -177,7 +176,6 @@ members = [ "primitives/arithmetic", "primitives/arithmetic/fuzzer", "primitives/authority-discovery", - "primitives/authorship", "primitives/beefy", "primitives/block-builder", "primitives/blockchain", diff --git a/bin/node/cli/Cargo.toml b/bin/node/cli/Cargo.toml index c529c7c9b8dfd..9ec06d9d9cab1 100644 --- a/bin/node/cli/Cargo.toml +++ b/bin/node/cli/Cargo.toml @@ -52,7 +52,6 @@ sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" } sp-core = { version = "7.0.0", path = "../../../primitives/core" } sp-runtime = { version = "7.0.0", path = "../../../primitives/runtime" } sp-timestamp = { version = "4.0.0-dev", path = "../../../primitives/timestamp" } -sp-authorship = { version = "4.0.0-dev", path = "../../../primitives/authorship" } sp-inherents = { version = "4.0.0-dev", path = "../../../primitives/inherents" } sp-keyring = { version = "7.0.0", path = "../../../primitives/keyring" } sp-keystore = { version = "0.13.0", path = "../../../primitives/keystore" } @@ -71,7 +70,6 @@ sc-network = { version = "0.10.0-dev", path = "../../../client/network" } sc-network-common = { version = "0.10.0-dev", path = "../../../client/network/common" } sc-consensus-slots = { version = "0.10.0-dev", path = "../../../client/consensus/slots" } sc-consensus-babe = { version = "0.10.0-dev", path = "../../../client/consensus/babe" } -sc-consensus-uncles = { version = "0.10.0-dev", path = "../../../client/consensus/uncles" } grandpa = { version = "0.10.0-dev", package = "sc-finality-grandpa", path = "../../../client/finality-grandpa" } sc-rpc = { version = "4.0.0-dev", path = "../../../client/rpc" } sc-basic-authorship = { version = "0.10.0-dev", path = "../../../client/basic-authorship" } diff --git a/bin/node/cli/src/service.rs b/bin/node/cli/src/service.rs index e329087947c98..b1e9360b4a6c4 100644 --- a/bin/node/cli/src/service.rs +++ b/bin/node/cli/src/service.rs @@ -222,10 +222,7 @@ pub fn new_partial( slot_duration, ); - let uncles = - sp_authorship::InherentDataProvider::<::Header>::check_inherents(); - - Ok((slot, timestamp, uncles)) + Ok((slot, timestamp)) }, &task_manager.spawn_essential_handle(), config.prometheus_registry(), @@ -440,11 +437,6 @@ pub fn new_full_base( create_inherent_data_providers: move |parent, ()| { let client_clone = client_clone.clone(); async move { - let uncles = sc_consensus_uncles::create_uncles_inherent_data_provider( - &*client_clone, - parent, - )?; - let timestamp = sp_timestamp::InherentDataProvider::from_system_time(); let slot = @@ -459,7 +451,7 @@ pub fn new_full_base( &parent, )?; - Ok((slot, timestamp, uncles, storage_proof)) + Ok((slot, timestamp, storage_proof)) } }, force_authoring, diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index bd8a395d15243..30165cdb6f6c7 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -488,14 +488,8 @@ impl pallet_timestamp::Config for Runtime { type WeightInfo = pallet_timestamp::weights::SubstrateWeight; } -parameter_types! { - pub const UncleGenerations: BlockNumber = 5; -} - impl pallet_authorship::Config for Runtime { type FindAuthor = pallet_session::FindAccountFromAuthorIndex; - type UncleGenerations = UncleGenerations; - type FilterUncle = (); type EventHandler = (Staking, ImOnline); } diff --git a/client/consensus/uncles/Cargo.toml b/client/consensus/uncles/Cargo.toml deleted file mode 100644 index 0be48659f9c77..0000000000000 --- a/client/consensus/uncles/Cargo.toml +++ /dev/null @@ -1,19 +0,0 @@ -[package] -name = "sc-consensus-uncles" -version = "0.10.0-dev" -authors = ["Parity Technologies "] -description = "Generic uncle inclusion utilities for consensus" -edition = "2021" -license = "GPL-3.0-or-later WITH Classpath-exception-2.0" -homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" -readme = "README.md" - -[package.metadata.docs.rs] -targets = ["x86_64-unknown-linux-gnu"] - -[dependencies] -thiserror = "1.0.30" -sc-client-api = { version = "4.0.0-dev", path = "../../api" } -sp-authorship = { version = "4.0.0-dev", path = "../../../primitives/authorship" } -sp-runtime = { version = "7.0.0", path = "../../../primitives/runtime" } diff --git a/client/consensus/uncles/README.md b/client/consensus/uncles/README.md deleted file mode 100644 index 1b6fed5b9772a..0000000000000 --- a/client/consensus/uncles/README.md +++ /dev/null @@ -1,3 +0,0 @@ -Uncles functionality for Substrate. - -License: GPL-3.0-or-later WITH Classpath-exception-2.0 \ No newline at end of file diff --git a/client/consensus/uncles/src/lib.rs b/client/consensus/uncles/src/lib.rs deleted file mode 100644 index d03c2f8aa6b49..0000000000000 --- a/client/consensus/uncles/src/lib.rs +++ /dev/null @@ -1,45 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -//! Uncles functionality for Substrate. - -use sc_client_api::ProvideUncles; -use sp_runtime::{generic::BlockId, traits::Block as BlockT}; - -#[derive(Debug, thiserror::Error)] -pub enum Error { - #[error("Could not retrieve the block hash for block id: {0:?}")] - NoHashForBlockId(BlockId), -} - -/// Maximum uncles generations we may provide to the runtime. -const MAX_UNCLE_GENERATIONS: u32 = 8; - -/// Create a new [`sp_authorship::InherentDataProvider`] at the given block. -pub fn create_uncles_inherent_data_provider( - client: &C, - parent: B::Hash, -) -> Result, sc_client_api::blockchain::Error> -where - B: BlockT, - C: ProvideUncles, -{ - let uncles = client.uncles(parent, MAX_UNCLE_GENERATIONS.into())?; - - Ok(sp_authorship::InherentDataProvider::new(uncles)) -} diff --git a/frame/authorship/Cargo.toml b/frame/authorship/Cargo.toml index 84d00a6fbc54e..a205c51f9c62d 100644 --- a/frame/authorship/Cargo.toml +++ b/frame/authorship/Cargo.toml @@ -20,7 +20,6 @@ impl-trait-for-tuples = "0.2.2" scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } -sp-authorship = { version = "4.0.0-dev", default-features = false, path = "../../primitives/authorship" } sp-runtime = { version = "7.0.0", default-features = false, path = "../../primitives/runtime" } sp-std = { version = "5.0.0", default-features = false, path = "../../primitives/std" } @@ -35,7 +34,6 @@ std = [ "frame-support/std", "frame-system/std", "scale-info/std", - "sp-authorship/std", "sp-runtime/std", "sp-std/std", ] diff --git a/frame/authorship/src/lib.rs b/frame/authorship/src/lib.rs index 4065472d92368..b5568a6acf77c 100644 --- a/frame/authorship/src/lib.rs +++ b/frame/authorship/src/lib.rs @@ -17,36 +17,12 @@ //! Authorship tracking for FRAME runtimes. //! -//! This tracks the current author of the block and recent uncles. +//! This tracks the current author of the block. #![cfg_attr(not(feature = "std"), no_std)] -use codec::{Decode, Encode, MaxEncodedLen}; -use frame_support::{ - dispatch, - traits::{Defensive, FindAuthor, Get, VerifySeal}, - BoundedSlice, BoundedVec, -}; -use sp_authorship::{InherentError, UnclesInherentData, INHERENT_IDENTIFIER}; -use sp_runtime::traits::{Header as HeaderT, One, Saturating, UniqueSaturatedInto}; -use sp_std::{collections::btree_set::BTreeSet, prelude::*, result}; - -const MAX_UNCLES: usize = 10; - -struct MaxUncleEntryItems(core::marker::PhantomData); -impl Get for MaxUncleEntryItems { - fn get() -> u32 { - // There can be at most `MAX_UNCLES` of `UncleEntryItem::Uncle` and - // one `UncleEntryItem::InclusionHeight` per one `UncleGenerations`, - // so this gives us `MAX_UNCLES + 1` entries per one generation. - // - // There can be one extra generation worth of uncles (e.g. even - // if `UncleGenerations` is zero the pallet will still hold - // one generation worth of uncles). - let max_generations: u32 = T::UncleGenerations::get().unique_saturated_into(); - (MAX_UNCLES as u32 + 1) * (max_generations + 1) - } -} +use frame_support::traits::FindAuthor; +use sp_std::prelude::*; pub use pallet::*; @@ -56,87 +32,8 @@ pub use pallet::*; pub trait EventHandler { /// Note that the given account ID is the author of the current block. fn note_author(author: Author); - - /// Note that the given account ID authored the given uncle, and how many - /// blocks older than the current block it is (age >= 0, so siblings are allowed) - fn note_uncle(author: Author, age: BlockNumber); -} - -/// Additional filtering on uncles that pass preliminary ancestry checks. -/// -/// This should do work such as checking seals -pub trait FilterUncle { - /// An accumulator of data about uncles included. - /// - /// In practice, this is used to validate uncles against others in the same block. - type Accumulator: Default; - - /// Do additional filtering on a seal-checked uncle block, with the accumulated - /// filter. - fn filter_uncle( - header: &Header, - acc: &mut Self::Accumulator, - ) -> Result, &'static str>; } -impl FilterUncle for () { - type Accumulator = (); - fn filter_uncle(_: &H, _acc: &mut Self::Accumulator) -> Result, &'static str> { - Ok(None) - } -} - -/// A filter on uncles which verifies seals and does no additional checks. -/// This is well-suited to consensus modes such as PoW where the cost of -/// equivocating is high. -pub struct SealVerify(sp_std::marker::PhantomData); - -impl> FilterUncle for SealVerify { - type Accumulator = (); - - fn filter_uncle(header: &Header, _acc: &mut ()) -> Result, &'static str> { - T::verify_seal(header) - } -} - -/// A filter on uncles which verifies seals and ensures that there is only -/// one uncle included per author per height. -/// -/// This does O(n log n) work in the number of uncles included. -pub struct OnePerAuthorPerHeight(sp_std::marker::PhantomData<(T, N)>); - -impl FilterUncle for OnePerAuthorPerHeight -where - Header: HeaderT + PartialEq, - Header::Number: Ord, - Author: Clone + PartialEq + Ord, - T: VerifySeal, -{ - type Accumulator = BTreeSet<(Header::Number, Author)>; - - fn filter_uncle( - header: &Header, - acc: &mut Self::Accumulator, - ) -> Result, &'static str> { - let author = T::verify_seal(header)?; - let number = header.number(); - - if let Some(ref author) = author { - if !acc.insert((*number, author.clone())) { - return Err("more than one uncle per number per author included") - } - } - - Ok(author) - } -} - -#[derive(Encode, Decode, sp_runtime::RuntimeDebug, scale_info::TypeInfo, MaxEncodedLen)] -#[cfg_attr(any(feature = "std", test), derive(PartialEq))] -enum UncleEntryItem { - InclusionHeight(BlockNumber), - Uncle(Hash, Option), -} #[frame_support::pallet] pub mod pallet { use super::*; @@ -147,25 +44,6 @@ pub mod pallet { pub trait Config: frame_system::Config { /// Find the author of a block. type FindAuthor: FindAuthor; - /// The number of blocks back we should accept uncles. - /// This means that we will deal with uncle-parents that are - /// `UncleGenerations + 1` before `now`. - #[pallet::constant] - type UncleGenerations: Get; - /// A filter for uncles within a block. This is for implementing - /// further constraints on what uncles can be included, other than their ancestry. - /// - /// For PoW, as long as the seals are checked, there is no need to use anything - /// but the `VerifySeal` implementation as the filter. This is because the cost of making - /// many equivocating uncles is high. - /// - /// For PoS, there is no such limitation, so a further constraint must be imposed - /// beyond a seal check in order to prevent an arbitrary number of - /// equivocating uncles from being included. - /// - /// The `OnePerAuthorPerHeight` filter is good for many slot-based PoS - /// engines. - type FilterUncle: FilterUncle; /// An event handler for authored blocks. type EventHandler: EventHandler; } @@ -176,16 +54,7 @@ pub mod pallet { #[pallet::hooks] impl Hooks> for Pallet { - fn on_initialize(now: T::BlockNumber) -> Weight { - let uncle_generations = T::UncleGenerations::get(); - // prune uncles that are older than the allowed number of generations. - if uncle_generations <= now { - let minimum_height = now - uncle_generations; - Self::prune_old_uncles(minimum_height) - } - - >::put(false); - + fn on_initialize(_: T::BlockNumber) -> Weight { if let Some(author) = Self::author() { T::EventHandler::note_author(author); } @@ -196,125 +65,12 @@ pub mod pallet { fn on_finalize(_: T::BlockNumber) { // ensure we never go to trie with these values. >::kill(); - >::kill(); } } - #[pallet::storage] - /// Uncles - pub(super) type Uncles = StorageValue< - _, - BoundedVec, MaxUncleEntryItems>, - ValueQuery, - >; - #[pallet::storage] /// Author of current block. pub(super) type Author = StorageValue<_, T::AccountId, OptionQuery>; - - #[pallet::storage] - /// Whether uncles were already set in this block. - pub(super) type DidSetUncles = StorageValue<_, bool, ValueQuery>; - - #[pallet::error] - pub enum Error { - /// The uncle parent not in the chain. - InvalidUncleParent, - /// Uncles already set in the block. - UnclesAlreadySet, - /// Too many uncles. - TooManyUncles, - /// The uncle is genesis. - GenesisUncle, - /// The uncle is too high in chain. - TooHighUncle, - /// The uncle is already included. - UncleAlreadyIncluded, - /// The uncle isn't recent enough to be included. - OldUncle, - } - - #[pallet::call] - impl Pallet { - /// Provide a set of uncles. - #[pallet::call_index(0)] - #[pallet::weight((0, DispatchClass::Mandatory))] - pub fn set_uncles(origin: OriginFor, new_uncles: Vec) -> DispatchResult { - ensure_none(origin)?; - ensure!(new_uncles.len() <= MAX_UNCLES, Error::::TooManyUncles); - - if >::get() { - return Err(Error::::UnclesAlreadySet.into()) - } - >::put(true); - - Self::verify_and_import_uncles(new_uncles) - } - } - - #[pallet::inherent] - impl ProvideInherent for Pallet { - type Call = Call; - type Error = InherentError; - const INHERENT_IDENTIFIER: InherentIdentifier = INHERENT_IDENTIFIER; - - fn create_inherent(data: &InherentData) -> Option { - let uncles = data.uncles().unwrap_or_default(); - let mut new_uncles = Vec::new(); - - if !uncles.is_empty() { - let prev_uncles = >::get(); - let mut existing_hashes: Vec<_> = prev_uncles - .into_iter() - .filter_map(|entry| match entry { - UncleEntryItem::InclusionHeight(_) => None, - UncleEntryItem::Uncle(h, _) => Some(h), - }) - .collect(); - - let mut acc: >::Accumulator = - Default::default(); - - for uncle in uncles { - match Self::verify_uncle(&uncle, &existing_hashes, &mut acc) { - Ok(_) => { - let hash = uncle.hash(); - new_uncles.push(uncle); - existing_hashes.push(hash); - - if new_uncles.len() == MAX_UNCLES { - break - } - }, - Err(_) => { - // skip this uncle - }, - } - } - } - - if new_uncles.is_empty() { - None - } else { - Some(Call::set_uncles { new_uncles }) - } - } - - fn check_inherent( - call: &Self::Call, - _data: &InherentData, - ) -> result::Result<(), Self::Error> { - match call { - Call::set_uncles { ref new_uncles } if new_uncles.len() > MAX_UNCLES => - Err(InherentError::Uncles(Error::::TooManyUncles.as_str().into())), - _ => Ok(()), - } - } - - fn is_inherent(call: &Self::Call) -> bool { - matches!(call, Call::set_uncles { .. }) - } - } } impl Pallet { @@ -323,7 +79,7 @@ impl Pallet { /// This is safe to invoke in `on_initialize` implementations, as well /// as afterwards. pub fn author() -> Option { - // Check the memoized storage value. + // Check the memorized storage value. if let Some(author) = >::get() { return Some(author) } @@ -335,113 +91,22 @@ impl Pallet { a }) } - - fn verify_and_import_uncles(new_uncles: Vec) -> dispatch::DispatchResult { - let now = >::block_number(); - - let mut uncles = >::get(); - uncles - .try_push(UncleEntryItem::InclusionHeight(now)) - .defensive_proof("the list of uncles accepted per generation is bounded, and the number of generations is bounded, so pushing a new element will always succeed") - .map_err(|_| Error::::TooManyUncles)?; - - let mut acc: >::Accumulator = Default::default(); - - for uncle in new_uncles { - let prev_uncles = uncles.iter().filter_map(|entry| match entry { - UncleEntryItem::InclusionHeight(_) => None, - UncleEntryItem::Uncle(h, _) => Some(h), - }); - let maybe_author = Self::verify_uncle(&uncle, prev_uncles, &mut acc)?; - let hash = uncle.hash(); - - if let Some(author) = maybe_author.clone() { - T::EventHandler::note_uncle(author, now - *uncle.number()); - } - uncles.try_push(UncleEntryItem::Uncle(hash, maybe_author)) - .defensive_proof("the list of uncles accepted per generation is bounded, and the number of generations is bounded, so pushing a new element will always succeed") - .map_err(|_| Error::::TooManyUncles)?; - } - - >::put(&uncles); - Ok(()) - } - - fn verify_uncle<'a, I: IntoIterator>( - uncle: &T::Header, - existing_uncles: I, - accumulator: &mut >::Accumulator, - ) -> Result, dispatch::DispatchError> { - let now = >::block_number(); - - let (minimum_height, maximum_height) = { - let uncle_generations = T::UncleGenerations::get(); - let min = now.saturating_sub(uncle_generations); - - (min, now) - }; - - let hash = uncle.hash(); - - if uncle.number() < &One::one() { - return Err(Error::::GenesisUncle.into()) - } - - if uncle.number() > &maximum_height { - return Err(Error::::TooHighUncle.into()) - } - - { - let parent_number = *uncle.number() - One::one(); - let parent_hash = >::block_hash(&parent_number); - if &parent_hash != uncle.parent_hash() { - return Err(Error::::InvalidUncleParent.into()) - } - } - - if uncle.number() < &minimum_height { - return Err(Error::::OldUncle.into()) - } - - let duplicate = existing_uncles.into_iter().any(|h| *h == hash); - let in_chain = >::block_hash(uncle.number()) == hash; - - if duplicate || in_chain { - return Err(Error::::UncleAlreadyIncluded.into()) - } - - // check uncle validity. - T::FilterUncle::filter_uncle(uncle, accumulator).map_err(Into::into) - } - - fn prune_old_uncles(minimum_height: T::BlockNumber) { - let uncles = >::get(); - let prune_entries = uncles.iter().take_while(|item| match item { - UncleEntryItem::Uncle(_, _) => true, - UncleEntryItem::InclusionHeight(height) => height < &minimum_height, - }); - let prune_index = prune_entries.count(); - let pruned_uncles = - >>::try_from(&uncles[prune_index..]) - .expect("after pruning we can't end up with more uncles than we started with"); - - >::put(pruned_uncles); - } } #[cfg(test)] mod tests { use super::*; use crate as pallet_authorship; + use codec::{Decode, Encode}; use frame_support::{ - traits::{ConstU32, ConstU64, OnFinalize, OnInitialize}, + traits::{ConstU32, ConstU64}, ConsensusEngineId, }; use sp_core::H256; use sp_runtime::{ generic::DigestItem, testing::Header, - traits::{BlakeTwo256, IdentityLookup}, + traits::{BlakeTwo256, Header as HeaderT, IdentityLookup}, }; type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; @@ -454,7 +119,7 @@ mod tests { UncheckedExtrinsic = UncheckedExtrinsic, { System: frame_system::{Pallet, Call, Config, Storage, Event}, - Authorship: pallet_authorship::{Pallet, Call, Storage, Inherent}, + Authorship: pallet_authorship::{Pallet, Storage}, } ); @@ -487,8 +152,6 @@ mod tests { impl pallet::Config for Test { type FindAuthor = AuthorGiven; - type UncleGenerations = ConstU64<5>; - type FilterUncle = SealVerify; type EventHandler = (); } @@ -511,34 +174,6 @@ mod tests { } } - pub struct VerifyBlock; - - impl VerifySeal for VerifyBlock { - fn verify_seal(header: &Header) -> Result, &'static str> { - let pre_runtime_digests = header.digest.logs.iter().filter_map(|d| d.as_pre_runtime()); - let seals = header.digest.logs.iter().filter_map(|d| d.as_seal()); - - let author = - AuthorGiven::find_author(pre_runtime_digests).ok_or_else(|| "no author")?; - - for (id, mut seal) in seals { - if id == TEST_ID { - match u64::decode(&mut seal) { - Err(_) => return Err("wrong seal"), - Ok(a) => { - if a != author { - return Err("wrong author in seal") - } - break - }, - } - } - } - - Ok(Some(author)) - } - } - fn seal_header(mut header: Header, author: u64) -> Header { { let digest = header.digest_mut(); @@ -558,196 +193,6 @@ mod tests { t.into() } - #[test] - fn prune_old_uncles_works() { - use UncleEntryItem::*; - new_test_ext().execute_with(|| { - let hash = Default::default(); - let author = Default::default(); - let uncles = vec![ - InclusionHeight(1u64), - Uncle(hash, Some(author)), - Uncle(hash, None), - Uncle(hash, None), - InclusionHeight(2u64), - Uncle(hash, None), - InclusionHeight(3u64), - Uncle(hash, None), - ]; - let uncles = BoundedVec::try_from(uncles).unwrap(); - - ::Uncles::put(uncles); - Authorship::prune_old_uncles(3); - - let uncles = ::Uncles::get(); - assert_eq!(uncles, vec![InclusionHeight(3u64), Uncle(hash, None)]); - }) - } - - #[test] - fn rejects_bad_uncles() { - new_test_ext().execute_with(|| { - let author_a = 69; - - struct CanonChain { - inner: Vec
, - } - - impl CanonChain { - fn best_hash(&self) -> H256 { - self.inner.last().unwrap().hash() - } - - fn canon_hash(&self, index: usize) -> H256 { - self.inner[index].hash() - } - - fn header(&self, index: usize) -> &Header { - &self.inner[index] - } - - fn push(&mut self, header: Header) { - self.inner.push(header) - } - } - - let mut canon_chain = CanonChain { - inner: vec![seal_header( - create_header(0, Default::default(), Default::default()), - 999, - )], - }; - - let initialize_block = |number, hash: H256| { - System::reset_events(); - System::initialize(&number, &hash, &Default::default()) - }; - - for number in 1..8 { - initialize_block(number, canon_chain.best_hash()); - let header = seal_header(System::finalize(), author_a); - canon_chain.push(header); - } - - // initialize so system context is set up correctly. - initialize_block(8, canon_chain.best_hash()); - - // 2 of the same uncle at once - { - let uncle_a = seal_header( - create_header(3, canon_chain.canon_hash(2), [1; 32].into()), - author_a, - ); - assert_eq!( - Authorship::verify_and_import_uncles(vec![uncle_a.clone(), uncle_a.clone()]), - Err(Error::::UncleAlreadyIncluded.into()), - ); - } - - // 2 of the same uncle at different times. - { - let uncle_a = seal_header( - create_header(3, canon_chain.canon_hash(2), [1; 32].into()), - author_a, - ); - - assert!(Authorship::verify_and_import_uncles(vec![uncle_a.clone()]).is_ok()); - - assert_eq!( - Authorship::verify_and_import_uncles(vec![uncle_a.clone()]), - Err(Error::::UncleAlreadyIncluded.into()), - ); - } - - // same uncle as ancestor. - { - let uncle_clone = canon_chain.header(5).clone(); - - assert_eq!( - Authorship::verify_and_import_uncles(vec![uncle_clone]), - Err(Error::::UncleAlreadyIncluded.into()), - ); - } - - // uncle without valid seal. - { - let unsealed = create_header(3, canon_chain.canon_hash(2), [2; 32].into()); - assert_eq!( - Authorship::verify_and_import_uncles(vec![unsealed]), - Err("no author".into()), - ); - } - - // old uncles can't get in. - { - assert_eq!(System::block_number(), 8); - - let gen_2 = seal_header( - create_header(2, canon_chain.canon_hash(1), [3; 32].into()), - author_a, - ); - - assert_eq!( - Authorship::verify_and_import_uncles(vec![gen_2]), - Err(Error::::OldUncle.into()), - ); - } - - // siblings are also allowed - { - let other_8 = seal_header( - create_header(8, canon_chain.canon_hash(7), [1; 32].into()), - author_a, - ); - - assert!(Authorship::verify_and_import_uncles(vec![other_8]).is_ok()); - } - }); - } - - #[test] - fn maximum_bound() { - new_test_ext().execute_with(|| { - let mut max_item_count = 0; - - let mut author_counter = 0; - let mut current_depth = 1; - let mut parent_hash: H256 = [1; 32].into(); - let mut uncles = vec![]; - - // We deliberately run this for more generations than the limit - // so that we can get the `Uncles` to hit its cap. - for _ in 0..<::UncleGenerations as Get>::get() + 3 { - let new_uncles: Vec<_> = (0..MAX_UNCLES) - .map(|_| { - System::reset_events(); - System::initialize(¤t_depth, &parent_hash, &Default::default()); - // Increment the author on every block to make sure the hash's always - // different. - author_counter += 1; - seal_header(System::finalize(), author_counter) - }) - .collect(); - - author_counter += 1; - System::reset_events(); - System::initialize(¤t_depth, &parent_hash, &Default::default()); - Authorship::on_initialize(current_depth); - Authorship::set_uncles(RuntimeOrigin::none(), uncles).unwrap(); - Authorship::on_finalize(current_depth); - max_item_count = - std::cmp::max(max_item_count, ::Uncles::get().len()); - - let new_parent = seal_header(System::finalize(), author_counter); - parent_hash = new_parent.hash(); - uncles = new_uncles; - current_depth += 1; - } - - assert_eq!(max_item_count, MaxUncleEntryItems::::get() as usize); - }); - } - #[test] fn sets_author_lazily() { new_test_ext().execute_with(|| { @@ -762,33 +207,4 @@ mod tests { assert_eq!(Authorship::author(), Some(author)); }); } - - #[test] - fn one_uncle_per_author_per_number() { - type Filter = OnePerAuthorPerHeight; - - let author_a = 42; - let author_b = 43; - - let mut acc: >::Accumulator = Default::default(); - let header_a1 = seal_header(create_header(1, Default::default(), [1; 32].into()), author_a); - let header_b1 = seal_header(create_header(1, Default::default(), [1; 32].into()), author_b); - - let header_a2_1 = - seal_header(create_header(2, Default::default(), [1; 32].into()), author_a); - let header_a2_2 = - seal_header(create_header(2, Default::default(), [2; 32].into()), author_a); - - let mut check_filter = move |uncle| Filter::filter_uncle(uncle, &mut acc); - - // same height, different author is OK. - assert_eq!(check_filter(&header_a1), Ok(Some(author_a))); - assert_eq!(check_filter(&header_b1), Ok(Some(author_b))); - - // same author, different height. - assert_eq!(check_filter(&header_a2_1), Ok(Some(author_a))); - - // same author, same height (author a, height 2) - assert!(check_filter(&header_a2_2).is_err()); - } } diff --git a/frame/babe/src/mock.rs b/frame/babe/src/mock.rs index abae1b7e33157..b09dc29f6d60a 100644 --- a/frame/babe/src/mock.rs +++ b/frame/babe/src/mock.rs @@ -52,15 +52,15 @@ frame_support::construct_runtime!( NodeBlock = Block, UncheckedExtrinsic = UncheckedExtrinsic, { - System: frame_system::{Pallet, Call, Config, Storage, Event}, - Authorship: pallet_authorship::{Pallet, Call, Storage, Inherent}, - Balances: pallet_balances::{Pallet, Call, Storage, Config, Event}, - Historical: pallet_session_historical::{Pallet}, - Offences: pallet_offences::{Pallet, Storage, Event}, - Babe: pallet_babe::{Pallet, Call, Storage, Config, ValidateUnsigned}, - Staking: pallet_staking::{Pallet, Call, Storage, Config, Event}, - Session: pallet_session::{Pallet, Call, Storage, Event, Config}, - Timestamp: pallet_timestamp::{Pallet, Call, Storage, Inherent}, + System: frame_system, + Authorship: pallet_authorship, + Balances: pallet_balances, + Historical: pallet_session_historical, + Offences: pallet_offences, + Babe: pallet_babe, + Staking: pallet_staking, + Session: pallet_session, + Timestamp: pallet_timestamp, } ); @@ -124,8 +124,6 @@ impl pallet_session::historical::Config for Test { impl pallet_authorship::Config for Test { type FindAuthor = pallet_session::FindAccountFromAuthorIndex; - type UncleGenerations = ConstU64<0>; - type FilterUncle = (); type EventHandler = (); } diff --git a/frame/grandpa/src/mock.rs b/frame/grandpa/src/mock.rs index c618705af0651..54f34008abc56 100644 --- a/frame/grandpa/src/mock.rs +++ b/frame/grandpa/src/mock.rs @@ -51,15 +51,15 @@ frame_support::construct_runtime!( NodeBlock = Block, UncheckedExtrinsic = UncheckedExtrinsic, { - System: frame_system::{Pallet, Call, Config, Storage, Event}, - Authorship: pallet_authorship::{Pallet, Call, Storage, Inherent}, - Timestamp: pallet_timestamp::{Pallet, Call, Storage, Inherent}, - Balances: pallet_balances::{Pallet, Call, Storage, Config, Event}, - Staking: pallet_staking::{Pallet, Call, Config, Storage, Event}, - Session: pallet_session::{Pallet, Call, Storage, Event, Config}, - Grandpa: pallet_grandpa::{Pallet, Call, Storage, Config, Event, ValidateUnsigned}, - Offences: pallet_offences::{Pallet, Storage, Event}, - Historical: pallet_session_historical::{Pallet}, + System: frame_system, + Authorship: pallet_authorship, + Timestamp: pallet_timestamp, + Balances: pallet_balances, + Staking: pallet_staking, + Session: pallet_session, + Grandpa: pallet_grandpa, + Offences: pallet_offences, + Historical: pallet_session_historical, } ); @@ -129,8 +129,6 @@ impl pallet_session::historical::Config for Test { impl pallet_authorship::Config for Test { type FindAuthor = (); - type UncleGenerations = ConstU64<0>; - type FilterUncle = (); type EventHandler = (); } diff --git a/frame/im-online/src/lib.rs b/frame/im-online/src/lib.rs index f23e610a4874d..8c1f46978e8bc 100644 --- a/frame/im-online/src/lib.rs +++ b/frame/im-online/src/lib.rs @@ -607,10 +607,6 @@ impl fn note_author(author: ValidatorId) { Self::note_authorship(author); } - - fn note_uncle(author: ValidatorId, _age: T::BlockNumber) { - Self::note_authorship(author); - } } impl Pallet { diff --git a/frame/im-online/src/mock.rs b/frame/im-online/src/mock.rs index bcb13fa1be837..783e68dfede9f 100644 --- a/frame/im-online/src/mock.rs +++ b/frame/im-online/src/mock.rs @@ -169,8 +169,6 @@ impl pallet_session::historical::Config for Runtime { impl pallet_authorship::Config for Runtime { type FindAuthor = (); - type UncleGenerations = ConstU64<5>; - type FilterUncle = (); type EventHandler = ImOnline; } diff --git a/frame/im-online/src/tests.rs b/frame/im-online/src/tests.rs index 366119278d836..2c026f7176b65 100644 --- a/frame/im-online/src/tests.rs +++ b/frame/im-online/src/tests.rs @@ -308,11 +308,10 @@ fn should_mark_online_validator_when_block_is_authored() { // when ImOnline::note_author(1); - ImOnline::note_uncle(2, 0); // then assert!(ImOnline::is_online(0)); - assert!(ImOnline::is_online(1)); + assert!(!ImOnline::is_online(1)); assert!(!ImOnline::is_online(2)); }); } @@ -338,7 +337,7 @@ fn should_not_send_a_report_if_already_online() { assert_eq!(Session::current_index(), 2); assert_eq!(Session::validators(), vec![1, 2, 3]); ImOnline::note_author(2); - ImOnline::note_uncle(3, 0); + ImOnline::note_author(3); // when UintAuthorityId::set_all_keys(vec![1, 2, 3]); diff --git a/frame/staking/src/mock.rs b/frame/staking/src/mock.rs index edf8d29645a55..81b48694fae99 100644 --- a/frame/staking/src/mock.rs +++ b/frame/staking/src/mock.rs @@ -91,14 +91,14 @@ frame_support::construct_runtime!( NodeBlock = Block, UncheckedExtrinsic = UncheckedExtrinsic, { - System: frame_system::{Pallet, Call, Config, Storage, Event}, - Authorship: pallet_authorship::{Pallet, Call, Storage, Inherent}, - Timestamp: pallet_timestamp::{Pallet, Call, Storage, Inherent}, - Balances: pallet_balances::{Pallet, Call, Storage, Config, Event}, - Staking: pallet_staking::{Pallet, Call, Config, Storage, Event}, - Session: pallet_session::{Pallet, Call, Storage, Event, Config}, - Historical: pallet_session::historical::{Pallet, Storage}, - VoterBagsList: pallet_bags_list::::{Pallet, Call, Storage, Event}, + System: frame_system, + Authorship: pallet_authorship, + Timestamp: pallet_timestamp, + Balances: pallet_balances, + Staking: pallet_staking, + Session: pallet_session, + Historical: pallet_session::historical, + VoterBagsList: pallet_bags_list::, } ); @@ -182,8 +182,6 @@ impl pallet_session::historical::Config for Test { } impl pallet_authorship::Config for Test { type FindAuthor = Author11; - type UncleGenerations = ConstU64<0>; - type FilterUncle = (); type EventHandler = Pallet; } diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index acb995ed24320..faf807eee8275 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -1222,8 +1222,6 @@ impl historical::SessionManager pallet_authorship::EventHandler for Pallet where T: Config + pallet_authorship::Config + pallet_session::Config, @@ -1231,14 +1229,6 @@ where fn note_author(author: T::AccountId) { Self::reward_by_ids(vec![(author, 20)]) } - fn note_uncle(uncle_author: T::AccountId, _age: T::BlockNumber) { - // defensive-only: block author must exist. - if let Some(block_author) = >::author() { - Self::reward_by_ids(vec![(block_author, 2), (uncle_author, 1)]) - } else { - crate::log!(warn, "block author not set, this should never happen"); - } - } } /// This is intended to be used with `FilterHistoricalOffences`. diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index 9c017a53c145b..307c3996a82b6 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -2250,9 +2250,7 @@ fn reward_from_authorship_event_handler_works() { assert_eq!(>::author(), Some(11)); Pallet::::note_author(11); - Pallet::::note_uncle(21, 1); - // Rewarding the same two times works. - Pallet::::note_uncle(11, 1); + Pallet::::note_author(11); // Not mandatory but must be coherent with rewards assert_eq_uvec!(Session::validators(), vec![11, 21]); @@ -2261,10 +2259,7 @@ fn reward_from_authorship_event_handler_works() { // 11 is rewarded as a block producer and uncle referencer and uncle producer assert_eq!( ErasRewardPoints::::get(active_era()), - EraRewardPoints { - individual: vec![(11, 20 + 2 * 2 + 1), (21, 1)].into_iter().collect(), - total: 26, - }, + EraRewardPoints { individual: vec![(11, 20 * 2)].into_iter().collect(), total: 40 }, ); }) } diff --git a/frame/transaction-payment/asset-tx-payment/src/mock.rs b/frame/transaction-payment/asset-tx-payment/src/mock.rs index ddb02f5a611ff..60fb2e6c5e03e 100644 --- a/frame/transaction-payment/asset-tx-payment/src/mock.rs +++ b/frame/transaction-payment/asset-tx-payment/src/mock.rs @@ -45,12 +45,12 @@ frame_support::construct_runtime!( NodeBlock = Block, UncheckedExtrinsic = UncheckedExtrinsic, { - System: system::{Pallet, Call, Config, Storage, Event}, - Balances: pallet_balances::{Pallet, Call, Storage, Config, Event}, - TransactionPayment: pallet_transaction_payment::{Pallet, Storage, Event}, - Assets: pallet_assets::{Pallet, Call, Storage, Event}, - Authorship: pallet_authorship::{Pallet, Call, Storage}, - AssetTxPayment: pallet_asset_tx_payment::{Pallet, Event}, + System: system, + Balances: pallet_balances, + TransactionPayment: pallet_transaction_payment, + Assets: pallet_assets, + Authorship: pallet_authorship, + AssetTxPayment: pallet_asset_tx_payment, } ); @@ -187,8 +187,6 @@ impl FindAuthor for HardcodedAuthor { impl pallet_authorship::Config for Runtime { type FindAuthor = HardcodedAuthor; - type UncleGenerations = (); - type FilterUncle = (); type EventHandler = (); } diff --git a/primitives/authorship/Cargo.toml b/primitives/authorship/Cargo.toml deleted file mode 100644 index 31ea3b2d4c8f3..0000000000000 --- a/primitives/authorship/Cargo.toml +++ /dev/null @@ -1,30 +0,0 @@ -[package] -name = "sp-authorship" -version = "4.0.0-dev" -authors = ["Parity Technologies "] -description = "Authorship primitives" -edition = "2021" -license = "Apache-2.0" -homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" -readme = "README.md" - -[package.metadata.docs.rs] -targets = ["x86_64-unknown-linux-gnu"] - -[dependencies] -async-trait = { version = "0.1.57", optional = true } -codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = ["derive"] } -sp-inherents = { version = "4.0.0-dev", default-features = false, path = "../inherents" } -sp-runtime = { version = "7.0.0", default-features = false, path = "../runtime" } -sp-std = { version = "5.0.0", default-features = false, path = "../std" } - -[features] -default = [ "std" ] -std = [ - "async-trait", - "codec/std", - "sp-inherents/std", - "sp-runtime/std", - "sp-std/std", -] diff --git a/primitives/authorship/README.md b/primitives/authorship/README.md deleted file mode 100644 index 1aa1805cfc5e7..0000000000000 --- a/primitives/authorship/README.md +++ /dev/null @@ -1,3 +0,0 @@ -Authorship Primitives - -License: Apache-2.0 \ No newline at end of file diff --git a/primitives/authorship/src/lib.rs b/primitives/authorship/src/lib.rs deleted file mode 100644 index 6ff6607a896cc..0000000000000 --- a/primitives/authorship/src/lib.rs +++ /dev/null @@ -1,101 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 2019-2022 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. - -//! Authorship Primitives - -#![cfg_attr(not(feature = "std"), no_std)] - -use sp_std::{prelude::*, result::Result}; - -#[cfg(feature = "std")] -use codec::Decode; -use codec::Encode; -use sp_inherents::{Error, InherentData, InherentIdentifier, IsFatalError}; -use sp_runtime::{traits::Header as HeaderT, RuntimeString}; - -/// The identifier for the `uncles` inherent. -pub const INHERENT_IDENTIFIER: InherentIdentifier = *b"uncles00"; - -/// Errors that can occur while checking the authorship inherent. -#[derive(Encode, sp_runtime::RuntimeDebug)] -#[cfg_attr(feature = "std", derive(Decode))] -pub enum InherentError { - Uncles(RuntimeString), -} - -impl IsFatalError for InherentError { - fn is_fatal_error(&self) -> bool { - match self { - InherentError::Uncles(_) => true, - } - } -} - -/// Auxiliary trait to extract uncles inherent data. -pub trait UnclesInherentData { - /// Get uncles. - fn uncles(&self) -> Result, Error>; -} - -impl UnclesInherentData for InherentData { - fn uncles(&self) -> Result, Error> { - Ok(self.get_data(&INHERENT_IDENTIFIER)?.unwrap_or_default()) - } -} - -/// Provider for inherent data. -#[cfg(feature = "std")] -pub struct InherentDataProvider { - uncles: Vec, -} - -#[cfg(feature = "std")] -impl InherentDataProvider { - /// Create a new inherent data provider with the given `uncles`. - pub fn new(uncles: Vec) -> Self { - InherentDataProvider { uncles } - } - - /// Create a new instance that is usable for checking inherents. - /// - /// This will always return an empty vec of uncles. - pub fn check_inherents() -> Self { - Self { uncles: Vec::new() } - } -} - -#[cfg(feature = "std")] -#[async_trait::async_trait] -impl sp_inherents::InherentDataProvider for InherentDataProvider { - async fn provide_inherent_data(&self, inherent_data: &mut InherentData) -> Result<(), Error> { - inherent_data.put_data(INHERENT_IDENTIFIER, &self.uncles) - } - - async fn try_handle_error( - &self, - identifier: &InherentIdentifier, - mut error: &[u8], - ) -> Option> { - if *identifier != INHERENT_IDENTIFIER { - return None - } - - let error = InherentError::decode(&mut error).ok()?; - - Some(Err(Error::Application(Box::from(format!("{:?}", error))))) - } -} From b0e04e7a896ef9b0067c83321c81786f0631f147 Mon Sep 17 00:00:00 2001 From: Jeeyong Um Date: Mon, 30 Jan 2023 14:32:09 +0900 Subject: [PATCH 074/162] Implement RIType traits for u8 array with an arbitrary size (#13256) --- primitives/runtime-interface/src/impls.rs | 115 +++++++++------------- 1 file changed, 48 insertions(+), 67 deletions(-) diff --git a/primitives/runtime-interface/src/impls.rs b/primitives/runtime-interface/src/impls.rs index e801931c306cf..e311b01dbefcf 100644 --- a/primitives/runtime-interface/src/impls.rs +++ b/primitives/runtime-interface/src/impls.rs @@ -276,84 +276,65 @@ impl IntoFFIValue for [T] { } } -/// Implement the traits for the `[u8; N]` arrays, where `N` is the input to this macro. -macro_rules! impl_traits_for_arrays { - ( - $( - $n:expr - ),* - $(,)? - ) => { - $( - /// The type is passed as `u32`. - /// - /// The `u32` is the pointer to the array. - impl RIType for [u8; $n] { - type FFIType = u32; - } - - #[cfg(not(feature = "std"))] - impl IntoFFIValue for [u8; $n] { - type Owned = (); +/// The type is passed as `u32`. +/// +/// The `u32` is the pointer to the array. +impl RIType for [u8; N] { + type FFIType = u32; +} - fn into_ffi_value(&self) -> WrappedFFIValue { - (self.as_ptr() as u32).into() - } - } +#[cfg(not(feature = "std"))] +impl IntoFFIValue for [u8; N] { + type Owned = (); - #[cfg(not(feature = "std"))] - impl FromFFIValue for [u8; $n] { - fn from_ffi_value(arg: u32) -> [u8; $n] { - let mut res = [0u8; $n]; - let data = unsafe { Vec::from_raw_parts(arg as *mut u8, $n, $n) }; + fn into_ffi_value(&self) -> WrappedFFIValue { + (self.as_ptr() as u32).into() + } +} - res.copy_from_slice(&data); +#[cfg(not(feature = "std"))] +impl FromFFIValue for [u8; N] { + fn from_ffi_value(arg: u32) -> [u8; N] { + let mut res = [0u8; N]; + let data = unsafe { Vec::from_raw_parts(arg as *mut u8, N, N) }; - res - } - } + res.copy_from_slice(&data); - #[cfg(feature = "std")] - impl FromFFIValue for [u8; $n] { - type SelfInstance = [u8; $n]; + res + } +} - fn from_ffi_value(context: &mut dyn FunctionContext, arg: u32) -> Result<[u8; $n]> { - let mut res = [0u8; $n]; - context.read_memory_into(Pointer::new(arg), &mut res)?; - Ok(res) - } - } +#[cfg(feature = "std")] +impl FromFFIValue for [u8; N] { + type SelfInstance = [u8; N]; - #[cfg(feature = "std")] - impl IntoFFIValue for [u8; $n] { - fn into_ffi_value(self, context: &mut dyn FunctionContext) -> Result { - let addr = context.allocate_memory($n)?; - context.write_memory(addr, &self)?; - Ok(addr.into()) - } - } + fn from_ffi_value(context: &mut dyn FunctionContext, arg: u32) -> Result<[u8; N]> { + let mut res = [0u8; N]; + context.read_memory_into(Pointer::new(arg), &mut res)?; + Ok(res) + } +} - #[cfg(feature = "std")] - impl IntoPreallocatedFFIValue for [u8; $n] { - type SelfInstance = [u8; $n]; - - fn into_preallocated_ffi_value( - self_instance: Self::SelfInstance, - context: &mut dyn FunctionContext, - allocated: u32, - ) -> Result<()> { - context.write_memory(Pointer::new(allocated), &self_instance) - } - } - )* +#[cfg(feature = "std")] +impl IntoFFIValue for [u8; N] { + fn into_ffi_value(self, context: &mut dyn FunctionContext) -> Result { + let addr = context.allocate_memory(N as u32)?; + context.write_memory(addr, &self)?; + Ok(addr.into()) } } -impl_traits_for_arrays! { - 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, - 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, - 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, - 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, +#[cfg(feature = "std")] +impl IntoPreallocatedFFIValue for [u8; N] { + type SelfInstance = [u8; N]; + + fn into_preallocated_ffi_value( + self_instance: Self::SelfInstance, + context: &mut dyn FunctionContext, + allocated: u32, + ) -> Result<()> { + context.write_memory(Pointer::new(allocated), &self_instance) + } } impl PassBy for sp_std::result::Result { From 2d35736b2135c274d606a5d369d9dc1e068a741f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Silva?= <123550+andresilva@users.noreply.github.com> Date: Mon, 30 Jan 2023 15:25:11 +0000 Subject: [PATCH 075/162] grandpa: cleanup stale entries in set id session mapping (#13237) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * grandpa: cleanup stale entries in set id session mapping * Update frame/grandpa/src/migrations.rs Co-authored-by: Bastian Köcher * grandpa: remove unused import * grandpa: migration off-by-one * Update frame/grandpa/src/lib.rs Co-authored-by: Anton * Update frame/grandpa/src/lib.rs Co-authored-by: Anton * grandpa: MaxSetIdSessionEntries as u64 * node-template: fix MaxSetIdSessionEntries type --------- Co-authored-by: Bastian Köcher Co-authored-by: Anton --- bin/node-template/runtime/src/lib.rs | 1 + bin/node/runtime/src/lib.rs | 5 +++ frame/grandpa/src/lib.rs | 30 +++++++++++++++--- frame/grandpa/src/migrations.rs | 46 ++++++++++++++++++++++++++++ frame/grandpa/src/mock.rs | 2 ++ frame/grandpa/src/tests.rs | 27 ++++++++++++++++ 6 files changed, 107 insertions(+), 4 deletions(-) diff --git a/bin/node-template/runtime/src/lib.rs b/bin/node-template/runtime/src/lib.rs index baba5d9b05e59..4840459816632 100644 --- a/bin/node-template/runtime/src/lib.rs +++ b/bin/node-template/runtime/src/lib.rs @@ -230,6 +230,7 @@ impl pallet_grandpa::Config for Runtime { type WeightInfo = (); type MaxAuthorities = ConstU32<32>; + type MaxSetIdSessionEntries = ConstU64<0>; } impl pallet_timestamp::Config for Runtime { diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 30165cdb6f6c7..8e8ecc125dba4 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -1310,6 +1310,10 @@ impl pallet_authority_discovery::Config for Runtime { type MaxAuthorities = MaxAuthorities; } +parameter_types! { + pub const MaxSetIdSessionEntries: u32 = BondingDuration::get() * SessionsPerEra::get(); +} + impl pallet_grandpa::Config for Runtime { type RuntimeEvent = RuntimeEvent; @@ -1331,6 +1335,7 @@ impl pallet_grandpa::Config for Runtime { type WeightInfo = (); type MaxAuthorities = MaxAuthorities; + type MaxSetIdSessionEntries = MaxSetIdSessionEntries; } parameter_types! { diff --git a/frame/grandpa/src/lib.rs b/frame/grandpa/src/lib.rs index aa09b445c6bdd..ea534947ddd37 100644 --- a/frame/grandpa/src/lib.rs +++ b/frame/grandpa/src/lib.rs @@ -121,6 +121,15 @@ pub mod pallet { /// Max Authorities in use #[pallet::constant] type MaxAuthorities: Get; + + /// The maximum number of entries to keep in the set id to session index mapping. + /// + /// Since the `SetIdSession` map is only used for validating equivocations this + /// value should relate to the bonding duration of whatever staking system is + /// being used (if any). If equivocation handling is not enabled then this value + /// can be zero. + #[pallet::constant] + type MaxSetIdSessionEntries: Get; } #[pallet::hooks] @@ -323,6 +332,12 @@ pub mod pallet { /// A mapping from grandpa set ID to the index of the *most recent* session for which its /// members were responsible. /// + /// This is only used for validating equivocation proofs. An equivocation proof must + /// contains a key-ownership proof for a given session, therefore we need a way to tie + /// together sessions and GRANDPA set ids, i.e. we need to validate that a validator + /// was the owner of a given key on a given session, and what the active set ID was + /// during that session. + /// /// TWOX-NOTE: `SetId` is not under user control. #[pallet::storage] #[pallet::getter(fn session_for_set)] @@ -643,10 +658,17 @@ where }; if res.is_ok() { - CurrentSetId::::mutate(|s| { + let current_set_id = CurrentSetId::::mutate(|s| { *s += 1; *s - }) + }); + + let max_set_id_session_entries = T::MaxSetIdSessionEntries::get().max(1); + if current_set_id >= max_set_id_session_entries { + SetIdSession::::remove(current_set_id - max_set_id_session_entries); + } + + current_set_id } else { // either the session module signalled that the validators have changed // or the set was stalled. but since we didn't successfully schedule @@ -659,8 +681,8 @@ where Self::current_set_id() }; - // if we didn't issue a change, we update the mapping to note that the current - // set corresponds to the latest equivalent session (i.e. now). + // update the mapping to note that the current set corresponds to the + // latest equivalent session (i.e. now). let session_index = >::current_index(); SetIdSession::::insert(current_set_id, &session_index); } diff --git a/frame/grandpa/src/migrations.rs b/frame/grandpa/src/migrations.rs index 7795afcd8034f..f4a28fff13974 100644 --- a/frame/grandpa/src/migrations.rs +++ b/frame/grandpa/src/migrations.rs @@ -15,5 +15,51 @@ // See the License for the specific language governing permissions and // limitations under the License. +use frame_support::{ + traits::{Get, OnRuntimeUpgrade}, + weights::Weight, +}; + +use crate::{Config, CurrentSetId, SetIdSession, LOG_TARGET}; + /// Version 4. pub mod v4; + +/// This migration will clean up all stale set id -> session entries from the +/// `SetIdSession` storage map, only the latest `max_set_id_session_entries` +/// will be kept. +/// +/// This migration should be added with a runtime upgrade that introduces the +/// `MaxSetIdSessionEntries` constant to the pallet (although it could also be +/// done later on). +pub struct CleanupSetIdSessionMap(sp_std::marker::PhantomData); +impl OnRuntimeUpgrade for CleanupSetIdSessionMap { + fn on_runtime_upgrade() -> Weight { + // NOTE: since this migration will loop over all stale entries in the + // map we need to set some cutoff value, otherwise the migration might + // take too long to run. for scenarios where there are that many entries + // to cleanup a multiblock migration will be needed instead. + if CurrentSetId::::get() > 25_000 { + log::warn!( + target: LOG_TARGET, + "CleanupSetIdSessionMap migration was aborted since there are too many entries to cleanup." + ); + + return T::DbWeight::get().reads(1) + } + + cleanup_set_id_sesion_map::() + } +} + +fn cleanup_set_id_sesion_map() -> Weight { + let until_set_id = CurrentSetId::::get().saturating_sub(T::MaxSetIdSessionEntries::get()); + + for set_id in 0..=until_set_id { + SetIdSession::::remove(set_id); + } + + T::DbWeight::get() + .reads(1) + .saturating_add(T::DbWeight::get().writes(until_set_id + 1)) +} diff --git a/frame/grandpa/src/mock.rs b/frame/grandpa/src/mock.rs index 54f34008abc56..7d54966a498a6 100644 --- a/frame/grandpa/src/mock.rs +++ b/frame/grandpa/src/mock.rs @@ -219,6 +219,7 @@ impl pallet_offences::Config for Test { parameter_types! { pub const ReportLongevity: u64 = BondingDuration::get() as u64 * SessionsPerEra::get() as u64 * Period::get(); + pub const MaxSetIdSessionEntries: u32 = BondingDuration::get() * SessionsPerEra::get(); } impl Config for Test { @@ -239,6 +240,7 @@ impl Config for Test { type WeightInfo = (); type MaxAuthorities = ConstU32<100>; + type MaxSetIdSessionEntries = MaxSetIdSessionEntries; } pub fn grandpa_log(log: ConsensusLog) -> DigestItem { diff --git a/frame/grandpa/src/tests.rs b/frame/grandpa/src/tests.rs index 626decd12821e..e090dcebb60bf 100644 --- a/frame/grandpa/src/tests.rs +++ b/frame/grandpa/src/tests.rs @@ -781,6 +781,33 @@ fn on_new_session_doesnt_start_new_set_if_schedule_change_failed() { }); } +#[test] +fn cleans_up_old_set_id_session_mappings() { + new_test_ext(vec![(1, 1), (2, 1), (3, 1)]).execute_with(|| { + let max_set_id_session_entries = MaxSetIdSessionEntries::get(); + + start_era(max_set_id_session_entries); + + // we should have a session id mapping for all the set ids from + // `max_set_id_session_entries` eras we have observed + for i in 1..=max_set_id_session_entries { + assert!(Grandpa::session_for_set(i as u64).is_some()); + } + + start_era(max_set_id_session_entries * 2); + + // we should keep tracking the new mappings for new eras + for i in max_set_id_session_entries + 1..=max_set_id_session_entries * 2 { + assert!(Grandpa::session_for_set(i as u64).is_some()); + } + + // but the old ones should have been pruned by now + for i in 1..=max_set_id_session_entries { + assert!(Grandpa::session_for_set(i as u64).is_none()); + } + }); +} + #[test] fn always_schedules_a_change_on_new_session_when_stalled() { new_test_ext(vec![(1, 1), (2, 1), (3, 1)]).execute_with(|| { From 599cd6e45de8d10e498f2b6e3edf17530ab59db7 Mon Sep 17 00:00:00 2001 From: Muharem Ismailov Date: Wed, 1 Feb 2023 03:11:41 +0100 Subject: [PATCH 076/162] Benchmark's successful origin api update (#13146) * try successful origin unimplemented by default * error as a default impl for try_successful_origin * remove successful_origin func of EnsureOrigin trait * default impl -> unimplemented!() * update EnsureOriginWithArg * fix EnsureOriginWithArg * prefix unused arg with underscore * use try_successful_origin instead successful_origin, map err to Weightless * fix tests * remove default impl * unwrap for indirect origin dep * replace unwrap by expect with a message --------- Co-authored-by: parity-processbot <> --- frame/alliance/src/benchmarking.rs | 23 ++- frame/assets/src/benchmarking.rs | 14 +- frame/bounties/src/benchmarking.rs | 6 +- frame/democracy/src/benchmarking.rs | 42 +++-- frame/fast-unstake/src/benchmarking.rs | 5 +- frame/identity/src/benchmarking.rs | 23 ++- frame/lottery/src/benchmarking.rs | 14 +- frame/membership/src/lib.rs | 37 ++-- frame/nfts/src/benchmarking.rs | 11 +- frame/nis/src/benchmarking.rs | 5 +- frame/preimage/src/benchmarking.rs | 116 +++++++++---- frame/ranked-collective/src/benchmarking.rs | 37 ++-- frame/ranked-collective/src/lib.rs | 39 ----- frame/referenda/src/benchmarking.rs | 183 ++++++++++++++------ frame/scheduler/src/benchmarking.rs | 5 +- frame/support/src/traits/dispatch.rs | 38 +--- frame/system/src/tests.rs | 7 +- frame/tips/src/benchmarking.rs | 7 +- frame/treasury/src/benchmarking.rs | 11 +- frame/uniques/src/benchmarking.rs | 8 +- frame/whitelist/src/benchmarking.rs | 14 +- 21 files changed, 402 insertions(+), 243 deletions(-) diff --git a/frame/alliance/src/benchmarking.rs b/frame/alliance/src/benchmarking.rs index f312e032bbb0f..01b81ed66e999 100644 --- a/frame/alliance/src/benchmarking.rs +++ b/frame/alliance/src/benchmarking.rs @@ -25,7 +25,7 @@ use sp_std::{ prelude::*, }; -use frame_benchmarking::v1::{account, benchmarks_instance_pallet}; +use frame_benchmarking::v1::{account, benchmarks_instance_pallet, BenchmarkError}; use frame_support::traits::{EnsureOrigin, Get, UnfilteredDispatchable}; use frame_system::{Pallet as System, RawOrigin as SystemOrigin}; @@ -581,7 +581,8 @@ benchmarks_instance_pallet! { let rule = rule(b"hello world"); let call = Call::::set_rule { rule: rule.clone() }; - let origin = T::AdminOrigin::successful_origin(); + let origin = + T::AdminOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; }: { call.dispatch_bypass_filter(origin)? } verify { assert_eq!(Alliance::::rule(), Some(rule.clone())); @@ -594,7 +595,8 @@ benchmarks_instance_pallet! { let announcement = announcement(b"hello world"); let call = Call::::announce { announcement: announcement.clone() }; - let origin = T::AnnouncementOrigin::successful_origin(); + let origin = + T::AnnouncementOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; }: { call.dispatch_bypass_filter(origin)? } verify { assert!(Alliance::::announcements().contains(&announcement)); @@ -609,7 +611,8 @@ benchmarks_instance_pallet! { Announcements::::put(announcements); let call = Call::::remove_announcement { announcement: announcement.clone() }; - let origin = T::AnnouncementOrigin::successful_origin(); + let origin = + T::AnnouncementOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; }: { call.dispatch_bypass_filter(origin)? } verify { assert!(Alliance::::announcements().is_empty()); @@ -665,7 +668,8 @@ benchmarks_instance_pallet! { let ally1_lookup = T::Lookup::unlookup(ally1.clone()); let call = Call::::elevate_ally { ally: ally1_lookup }; - let origin = T::MembershipManager::successful_origin(); + let origin = + T::MembershipManager::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; }: { call.dispatch_bypass_filter(origin)? } verify { assert!(!Alliance::::is_ally(&ally1)); @@ -725,7 +729,8 @@ benchmarks_instance_pallet! { let fellow2_lookup = T::Lookup::unlookup(fellow2.clone()); let call = Call::::kick_member { who: fellow2_lookup }; - let origin = T::MembershipManager::successful_origin(); + let origin = + T::MembershipManager::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; }: { call.dispatch_bypass_filter(origin)? } verify { assert!(!Alliance::::is_member(&fellow2)); @@ -754,7 +759,8 @@ benchmarks_instance_pallet! { unscrupulous_list.extend(websites.into_iter().map(UnscrupulousItem::Website)); let call = Call::::add_unscrupulous_items { items: unscrupulous_list.clone() }; - let origin = T::AnnouncementOrigin::successful_origin(); + let origin = + T::AnnouncementOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; }: { call.dispatch_bypass_filter(origin)? } verify { assert_last_event::(Event::UnscrupulousItemAdded { items: unscrupulous_list }.into()); @@ -784,7 +790,8 @@ benchmarks_instance_pallet! { unscrupulous_list.extend(websites.into_iter().map(UnscrupulousItem::Website)); let call = Call::::remove_unscrupulous_items { items: unscrupulous_list.clone() }; - let origin = T::AnnouncementOrigin::successful_origin(); + let origin = + T::AnnouncementOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; }: { call.dispatch_bypass_filter(origin)? } verify { assert_last_event::(Event::UnscrupulousItemRemoved { items: unscrupulous_list }.into()); diff --git a/frame/assets/src/benchmarking.rs b/frame/assets/src/benchmarking.rs index 9acf69f1e4ef4..cf0ec353f6350 100644 --- a/frame/assets/src/benchmarking.rs +++ b/frame/assets/src/benchmarking.rs @@ -21,7 +21,7 @@ use super::*; use frame_benchmarking::v1::{ - account, benchmarks_instance_pallet, whitelist_account, whitelisted_caller, + account, benchmarks_instance_pallet, whitelist_account, whitelisted_caller, BenchmarkError, }; use frame_support::{ dispatch::UnfilteredDispatchable, @@ -135,7 +135,8 @@ fn assert_event, I: 'static>(generic_event: >::Runti benchmarks_instance_pallet! { create { let asset_id = default_asset_id::(); - let origin = T::CreateOrigin::successful_origin(&asset_id.into()); + let origin = T::CreateOrigin::try_successful_origin(&asset_id.into()) + .map_err(|_| BenchmarkError::Weightless)?; let caller = T::CreateOrigin::ensure_origin(origin, &asset_id.into()).unwrap(); let caller_lookup = T::Lookup::unlookup(caller.clone()); T::Currency::make_free_balance_be(&caller, DepositBalanceOf::::max_value()); @@ -362,7 +363,8 @@ benchmarks_instance_pallet! { let (asset_id, _, _) = create_default_asset::(true); - let origin = T::ForceOrigin::successful_origin(); + let origin = + T::ForceOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; let call = Call::::force_set_metadata { id: asset_id, name: name.clone(), @@ -382,7 +384,8 @@ benchmarks_instance_pallet! { let origin = SystemOrigin::Signed(caller).into(); Assets::::set_metadata(origin, asset_id, dummy.clone(), dummy, 12)?; - let origin = T::ForceOrigin::successful_origin(); + let origin = + T::ForceOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; let call = Call::::force_clear_metadata { id: asset_id }; }: { call.dispatch_bypass_filter(origin)? } verify { @@ -392,7 +395,8 @@ benchmarks_instance_pallet! { force_asset_status { let (asset_id, caller, caller_lookup) = create_default_asset::(true); - let origin = T::ForceOrigin::successful_origin(); + let origin = + T::ForceOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; let call = Call::::force_asset_status { id: asset_id, owner: caller_lookup.clone(), diff --git a/frame/bounties/src/benchmarking.rs b/frame/bounties/src/benchmarking.rs index a43372978e5ca..881f1c912e38b 100644 --- a/frame/bounties/src/benchmarking.rs +++ b/frame/bounties/src/benchmarking.rs @@ -173,7 +173,8 @@ benchmarks_instance_pallet! { let (caller, curator, fee, value, reason) = setup_bounty::(0, 0); Bounties::::propose_bounty(RawOrigin::Signed(caller).into(), value, reason)?; let bounty_id = BountyCount::::get() - 1; - let approve_origin = T::ApproveOrigin::successful_origin(); + let approve_origin = + T::ApproveOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; }: close_bounty(approve_origin, bounty_id) close_bounty_active { @@ -181,7 +182,8 @@ benchmarks_instance_pallet! { let (curator_lookup, bounty_id) = create_bounty::()?; Treasury::::on_initialize(T::BlockNumber::zero()); let bounty_id = BountyCount::::get() - 1; - let approve_origin = T::ApproveOrigin::successful_origin(); + let approve_origin = + T::ApproveOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; }: close_bounty(approve_origin, bounty_id) verify { assert_last_event::(Event::BountyCanceled { index: bounty_id }.into()) diff --git a/frame/democracy/src/benchmarking.rs b/frame/democracy/src/benchmarking.rs index 66d9e2a007afa..f2d45b719f678 100644 --- a/frame/democracy/src/benchmarking.rs +++ b/frame/democracy/src/benchmarking.rs @@ -19,7 +19,7 @@ use super::*; -use frame_benchmarking::v1::{account, benchmarks, whitelist_account}; +use frame_benchmarking::v1::{account, benchmarks, whitelist_account, BenchmarkError}; use frame_support::{ assert_noop, assert_ok, traits::{Currency, EnsureOrigin, Get, OnInitialize, UnfilteredDispatchable}, @@ -177,7 +177,8 @@ benchmarks! { } emergency_cancel { - let origin = T::CancellationOrigin::successful_origin(); + let origin = + T::CancellationOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; let ref_index = add_referendum::(0).0; assert_ok!(Democracy::::referendum_status(ref_index)); }: _(origin, ref_index) @@ -200,10 +201,13 @@ benchmarks! { let (ref_index, hash) = add_referendum::(0); assert_ok!(Democracy::::referendum_status(ref_index)); // Place our proposal in the external queue, too. - assert_ok!( - Democracy::::external_propose(T::ExternalOrigin::successful_origin(), make_proposal::(0)) - ); - let origin = T::BlacklistOrigin::successful_origin(); + assert_ok!(Democracy::::external_propose( + T::ExternalOrigin::try_successful_origin() + .expect("ExternalOrigin has no successful origin required for the benchmark"), + make_proposal::(0) + )); + let origin = + T::BlacklistOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; }: _(origin, hash, Some(ref_index)) verify { // Referendum has been canceled @@ -215,7 +219,8 @@ benchmarks! { // Worst case scenario, we external propose a previously blacklisted proposal external_propose { - let origin = T::ExternalOrigin::successful_origin(); + let origin = + T::ExternalOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; let proposal = make_proposal::(0); // Add proposal to blacklist with block number 0 @@ -233,7 +238,8 @@ benchmarks! { } external_propose_majority { - let origin = T::ExternalMajorityOrigin::successful_origin(); + let origin = T::ExternalMajorityOrigin::try_successful_origin() + .map_err(|_| BenchmarkError::Weightless)?; let proposal = make_proposal::(0); }: _(origin, proposal) verify { @@ -242,7 +248,8 @@ benchmarks! { } external_propose_default { - let origin = T::ExternalDefaultOrigin::successful_origin(); + let origin = T::ExternalDefaultOrigin::try_successful_origin() + .map_err(|_| BenchmarkError::Weightless)?; let proposal = make_proposal::(0); }: _(origin, proposal) verify { @@ -251,13 +258,15 @@ benchmarks! { } fast_track { - let origin_propose = T::ExternalDefaultOrigin::successful_origin(); + let origin_propose = T::ExternalDefaultOrigin::try_successful_origin() + .expect("ExternalDefaultOrigin has no successful origin required for the benchmark"); let proposal = make_proposal::(0); let proposal_hash = proposal.hash(); Democracy::::external_propose_default(origin_propose, proposal)?; // NOTE: Instant origin may invoke a little bit more logic, but may not always succeed. - let origin_fast_track = T::FastTrackOrigin::successful_origin(); + let origin_fast_track = + T::FastTrackOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; let voting_period = T::FastTrackVotingPeriod::get(); let delay = 0u32; }: _(origin_fast_track, proposal_hash, voting_period, delay.into()) @@ -269,7 +278,8 @@ benchmarks! { let proposal = make_proposal::(0); let proposal_hash = proposal.hash(); - let origin_propose = T::ExternalDefaultOrigin::successful_origin(); + let origin_propose = T::ExternalDefaultOrigin::try_successful_origin() + .expect("ExternalDefaultOrigin has no successful origin required for the benchmark"); Democracy::::external_propose_default(origin_propose, proposal)?; let mut vetoers: BoundedVec = Default::default(); @@ -279,7 +289,7 @@ benchmarks! { vetoers.sort(); Blacklist::::insert(proposal_hash, (T::BlockNumber::zero(), vetoers)); - let origin = T::VetoOrigin::successful_origin(); + let origin = T::VetoOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; ensure!(NextExternal::::get().is_some(), "no external proposal"); }: _(origin, proposal_hash) verify { @@ -293,7 +303,8 @@ benchmarks! { for i in 0 .. T::MaxProposals::get() { add_proposal::(i)?; } - let cancel_origin = T::CancelProposalOrigin::successful_origin(); + let cancel_origin = T::CancelProposalOrigin::try_successful_origin() + .map_err(|_| BenchmarkError::Weightless)?; }: _(cancel_origin, 0) cancel_referendum { @@ -313,7 +324,8 @@ benchmarks! { // Launch external LastTabledWasExternal::::put(false); - let origin = T::ExternalMajorityOrigin::successful_origin(); + let origin = T::ExternalMajorityOrigin::try_successful_origin() + .map_err(|_| BenchmarkError::Weightless)?; let proposal = make_proposal::(r); let call = Call::::external_propose_majority { proposal }; call.dispatch_bypass_filter(origin)?; diff --git a/frame/fast-unstake/src/benchmarking.rs b/frame/fast-unstake/src/benchmarking.rs index 77488b6447c61..e0e4186d78014 100644 --- a/frame/fast-unstake/src/benchmarking.rs +++ b/frame/fast-unstake/src/benchmarking.rs @@ -20,7 +20,7 @@ #![cfg(feature = "runtime-benchmarks")] use crate::{types::*, Pallet as FastUnstake, *}; -use frame_benchmarking::v1::{benchmarks, whitelist_account}; +use frame_benchmarking::v1::{benchmarks, whitelist_account, BenchmarkError}; use frame_support::{ assert_ok, traits::{Currency, EnsureOrigin, Get, Hooks}, @@ -192,7 +192,8 @@ benchmarks! { } control { - let origin = ::ControlOrigin::successful_origin(); + let origin = ::ControlOrigin::try_successful_origin() + .map_err(|_| BenchmarkError::Weightless)?; } : _(origin, T::MaxErasToCheckPerBlock::get()) verify {} diff --git a/frame/identity/src/benchmarking.rs b/frame/identity/src/benchmarking.rs index 356bcb2e80174..2d485af0f698b 100644 --- a/frame/identity/src/benchmarking.rs +++ b/frame/identity/src/benchmarking.rs @@ -22,7 +22,7 @@ use super::*; use crate::Pallet as Identity; -use frame_benchmarking::v1::{account, benchmarks, whitelisted_caller}; +use frame_benchmarking::v1::{account, benchmarks, whitelisted_caller, BenchmarkError}; use frame_support::{ ensure, traits::{EnsureOrigin, Get}, @@ -42,7 +42,8 @@ fn add_registrars(r: u32) -> Result<(), &'static str> { let registrar: T::AccountId = account("registrar", i, SEED); let registrar_lookup = T::Lookup::unlookup(registrar.clone()); let _ = T::Currency::make_free_balance_be(®istrar, BalanceOf::::max_value()); - let registrar_origin = T::RegistrarOrigin::successful_origin(); + let registrar_origin = T::RegistrarOrigin::try_successful_origin() + .expect("RegistrarOrigin has no successful origin required for the benchmark"); Identity::::add_registrar(registrar_origin, registrar_lookup)?; Identity::::set_fee(RawOrigin::Signed(registrar.clone()).into(), i, 10u32.into())?; let fields = @@ -121,7 +122,8 @@ benchmarks! { add_registrar { let r in 1 .. T::MaxRegistrars::get() - 1 => add_registrars::(r)?; ensure!(Registrars::::get().len() as u32 == r, "Registrars not set up correctly."); - let origin = T::RegistrarOrigin::successful_origin(); + let origin = + T::RegistrarOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; let account = T::Lookup::unlookup(account("registrar", r + 1, SEED)); }: _(origin, account) verify { @@ -280,7 +282,8 @@ benchmarks! { let r in 1 .. T::MaxRegistrars::get() - 1 => add_registrars::(r)?; - let registrar_origin = T::RegistrarOrigin::successful_origin(); + let registrar_origin = T::RegistrarOrigin::try_successful_origin() + .expect("RegistrarOrigin has no successful origin required for the benchmark"); Identity::::add_registrar(registrar_origin, caller_lookup)?; let registrars = Registrars::::get(); ensure!(registrars[r as usize].as_ref().unwrap().fee == 0u32.into(), "Fee already set."); @@ -297,7 +300,8 @@ benchmarks! { let r in 1 .. T::MaxRegistrars::get() - 1 => add_registrars::(r)?; - let registrar_origin = T::RegistrarOrigin::successful_origin(); + let registrar_origin = T::RegistrarOrigin::try_successful_origin() + .expect("RegistrarOrigin has no successful origin required for the benchmark"); Identity::::add_registrar(registrar_origin, caller_lookup)?; let registrars = Registrars::::get(); ensure!(registrars[r as usize].as_ref().unwrap().account == caller, "id not set."); @@ -315,7 +319,8 @@ benchmarks! { let r in 1 .. T::MaxRegistrars::get() - 1 => add_registrars::(r)?; - let registrar_origin = T::RegistrarOrigin::successful_origin(); + let registrar_origin = T::RegistrarOrigin::try_successful_origin() + .expect("RegistrarOrigin has no successful origin required for the benchmark"); Identity::::add_registrar(registrar_origin, caller_lookup)?; let fields = IdentityFields( IdentityField::Display | IdentityField::Legal | IdentityField::Web | IdentityField::Riot @@ -347,7 +352,8 @@ benchmarks! { let info_hash = T::Hashing::hash_of(&info); Identity::::set_identity(user_origin.clone(), Box::new(info))?; - let registrar_origin = T::RegistrarOrigin::successful_origin(); + let registrar_origin = T::RegistrarOrigin::try_successful_origin() + .expect("RegistrarOrigin has no successful origin required for the benchmark"); Identity::::add_registrar(registrar_origin, caller_lookup)?; Identity::::request_judgement(user_origin, r, 10u32.into())?; }: _(RawOrigin::Signed(caller), r, user_lookup, Judgement::Reasonable, info_hash) @@ -385,7 +391,8 @@ benchmarks! { )?; } ensure!(IdentityOf::::contains_key(&target), "Identity not set"); - let origin = T::ForceOrigin::successful_origin(); + let origin = + T::ForceOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; }: _(origin, target_lookup) verify { ensure!(!IdentityOf::::contains_key(&target), "Identity not removed"); diff --git a/frame/lottery/src/benchmarking.rs b/frame/lottery/src/benchmarking.rs index 658dd25a98a27..0db7fabb365ef 100644 --- a/frame/lottery/src/benchmarking.rs +++ b/frame/lottery/src/benchmarking.rs @@ -21,7 +21,7 @@ use super::*; -use frame_benchmarking::v1::{account, benchmarks, whitelisted_caller}; +use frame_benchmarking::v1::{account, benchmarks, whitelisted_caller, BenchmarkError}; use frame_support::{ storage::bounded_vec::BoundedVec, traits::{EnsureOrigin, OnInitialize}, @@ -43,7 +43,8 @@ fn setup_lottery(repeat: bool) -> Result<(), &'static str> { ]; // Last call will be the match for worst case scenario. calls.push(frame_system::Call::::remark { remark: vec![] }.into()); - let origin = T::ManagerOrigin::successful_origin(); + let origin = T::ManagerOrigin::try_successful_origin() + .expect("ManagerOrigin has no successful origin required for the benchmark"); Lottery::::set_calls(origin.clone(), calls)?; Lottery::::start_lottery(origin, price, length, delay, repeat)?; Ok(()) @@ -76,7 +77,8 @@ benchmarks! { set_calls { let n in 0 .. T::MaxCalls::get() as u32; let calls = vec![frame_system::Call::::remark { remark: vec![] }.into(); n as usize]; - let origin = T::ManagerOrigin::successful_origin(); + let origin = + T::ManagerOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; assert!(CallIndices::::get().is_empty()); }: _(origin, calls) verify { @@ -89,7 +91,8 @@ benchmarks! { let price = BalanceOf::::max_value(); let end = 10u32.into(); let payout = 5u32.into(); - let origin = T::ManagerOrigin::successful_origin(); + let origin = + T::ManagerOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; }: _(origin, price, end, payout, true) verify { assert!(crate::Lottery::::get().is_some()); @@ -98,7 +101,8 @@ benchmarks! { stop_repeat { setup_lottery::(true)?; assert_eq!(crate::Lottery::::get().unwrap().repeat, true); - let origin = T::ManagerOrigin::successful_origin(); + let origin = + T::ManagerOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; }: _(origin) verify { assert_eq!(crate::Lottery::::get().unwrap().repeat, false); diff --git a/frame/membership/src/lib.rs b/frame/membership/src/lib.rs index 6d973a15fe032..8b39a08ce6699 100644 --- a/frame/membership/src/lib.rs +++ b/frame/membership/src/lib.rs @@ -362,15 +362,17 @@ impl, I: 'static> SortedMembers for Pallet { #[cfg(feature = "runtime-benchmarks")] mod benchmark { use super::{Pallet as Membership, *}; - use frame_benchmarking::v1::{account, benchmarks_instance_pallet, whitelist}; + use frame_benchmarking::v1::{account, benchmarks_instance_pallet, whitelist, BenchmarkError}; use frame_support::{assert_ok, traits::EnsureOrigin}; use frame_system::RawOrigin; const SEED: u32 = 0; fn set_members, I: 'static>(members: Vec, prime: Option) { - let reset_origin = T::ResetOrigin::successful_origin(); - let prime_origin = T::PrimeOrigin::successful_origin(); + let reset_origin = T::ResetOrigin::try_successful_origin() + .expect("ResetOrigin has no successful origin required for the benchmark"); + let prime_origin = T::PrimeOrigin::try_successful_origin() + .expect("PrimeOrigin has no successful origin required for the benchmark"); assert_ok!(>::reset_members(reset_origin, members.clone())); if let Some(prime) = prime.map(|i| members[i].clone()) { @@ -390,9 +392,11 @@ mod benchmark { let new_member = account::("add", m, SEED); let new_member_lookup = T::Lookup::unlookup(new_member.clone()); }: { - assert_ok!(>::add_member(T::AddOrigin::successful_origin(), new_member_lookup)); - } - verify { + assert_ok!(>::add_member( + T::AddOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?, + new_member_lookup, + )); + } verify { assert!(>::get().contains(&new_member)); #[cfg(test)] crate::tests::clean(); } @@ -408,7 +412,10 @@ mod benchmark { let to_remove = members.first().cloned().unwrap(); let to_remove_lookup = T::Lookup::unlookup(to_remove.clone()); }: { - assert_ok!(>::remove_member(T::RemoveOrigin::successful_origin(), to_remove_lookup)); + assert_ok!(>::remove_member( + T::RemoveOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?, + to_remove_lookup, + )); } verify { assert!(!>::get().contains(&to_remove)); // prime is rejigged @@ -428,7 +435,7 @@ mod benchmark { let remove_lookup = T::Lookup::unlookup(remove.clone()); }: { assert_ok!(>::swap_member( - T::SwapOrigin::successful_origin(), + T::SwapOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?, remove_lookup, add_lookup, )); @@ -448,7 +455,10 @@ mod benchmark { set_members::(members.clone(), Some(members.len() - 1)); let mut new_members = (m..2*m).map(|i| account("member", i, SEED)).collect::>(); }: { - assert_ok!(>::reset_members(T::ResetOrigin::successful_origin(), new_members.clone())); + assert_ok!(>::reset_members( + T::ResetOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?, + new_members.clone(), + )); } verify { new_members.sort(); assert_eq!(>::get(), new_members); @@ -485,7 +495,10 @@ mod benchmark { let prime_lookup = T::Lookup::unlookup(prime.clone()); set_members::(members, None); }: { - assert_ok!(>::set_prime(T::PrimeOrigin::successful_origin(), prime_lookup)); + assert_ok!(>::set_prime( + T::PrimeOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?, + prime_lookup, + )); } verify { assert!(>::get().is_some()); assert!(::get_prime().is_some()); @@ -498,7 +511,9 @@ mod benchmark { let prime = members.last().cloned().unwrap(); set_members::(members, None); }: { - assert_ok!(>::clear_prime(T::PrimeOrigin::successful_origin())); + assert_ok!(>::clear_prime( + T::PrimeOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?, + )); } verify { assert!(>::get().is_none()); assert!(::get_prime().is_none()); diff --git a/frame/nfts/src/benchmarking.rs b/frame/nfts/src/benchmarking.rs index 17ff28b822814..a4007f6b2c133 100644 --- a/frame/nfts/src/benchmarking.rs +++ b/frame/nfts/src/benchmarking.rs @@ -22,7 +22,7 @@ use super::*; use enumflags2::{BitFlag, BitFlags}; use frame_benchmarking::v1::{ - account, benchmarks_instance_pallet, whitelist_account, whitelisted_caller, + account, benchmarks_instance_pallet, whitelist_account, whitelisted_caller, BenchmarkError, }; use frame_support::{ assert_ok, @@ -151,7 +151,8 @@ fn default_item_config() -> ItemConfig { benchmarks_instance_pallet! { create { let collection = T::Helper::collection(0); - let origin = T::CreateOrigin::successful_origin(&collection); + let origin = T::CreateOrigin::try_successful_origin(&collection) + .map_err(|_| BenchmarkError::Weightless)?; let caller = T::CreateOrigin::ensure_origin(origin.clone(), &collection).unwrap(); whitelist_account!(caller); let admin = T::Lookup::unlookup(caller.clone()); @@ -311,7 +312,8 @@ benchmarks_instance_pallet! { force_collection_owner { let (collection, _, _) = create_collection::(); - let origin = T::ForceOrigin::successful_origin(); + let origin = + T::ForceOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; let target: T::AccountId = account("target", 0, SEED); let target_lookup = T::Lookup::unlookup(target.clone()); T::Currency::make_free_balance_be(&target, T::Currency::minimum_balance()); @@ -326,7 +328,8 @@ benchmarks_instance_pallet! { force_collection_config { let (collection, caller, _) = create_collection::(); - let origin = T::ForceOrigin::successful_origin(); + let origin = + T::ForceOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; let call = Call::::force_collection_config { collection, config: make_collection_config::(CollectionSetting::DepositRequired.into()), diff --git a/frame/nis/src/benchmarking.rs b/frame/nis/src/benchmarking.rs index b01d414c4b251..10d3a238a3f5e 100644 --- a/frame/nis/src/benchmarking.rs +++ b/frame/nis/src/benchmarking.rs @@ -20,7 +20,7 @@ #![cfg(feature = "runtime-benchmarks")] use super::*; -use frame_benchmarking::v1::{account, benchmarks, whitelisted_caller}; +use frame_benchmarking::v1::{account, benchmarks, whitelisted_caller, BenchmarkError}; use frame_support::traits::{nonfungible::Inspect, Currency, EnsureOrigin, Get}; use frame_system::RawOrigin; use sp_arithmetic::Perquintill; @@ -100,7 +100,8 @@ benchmarks! { } fund_deficit { - let origin = T::FundOrigin::successful_origin(); + let origin = + T::FundOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; let caller: T::AccountId = whitelisted_caller(); let bid = T::MinBid::get().max(One::one()); T::Currency::make_free_balance_be(&caller, bid); diff --git a/frame/preimage/src/benchmarking.rs b/frame/preimage/src/benchmarking.rs index f9526b67d4bc8..56361b88c2583 100644 --- a/frame/preimage/src/benchmarking.rs +++ b/frame/preimage/src/benchmarking.rs @@ -18,7 +18,7 @@ //! Preimage pallet benchmarking. use super::*; -use frame_benchmarking::v1::{account, benchmarks, whitelist_account}; +use frame_benchmarking::v1::{account, benchmarks, whitelist_account, BenchmarkError}; use frame_support::assert_ok; use frame_system::RawOrigin; use sp_runtime::traits::Bounded; @@ -62,7 +62,11 @@ benchmarks! { let caller = funded_account::("caller", 0); whitelist_account!(caller); let (preimage, hash) = sized_preimage_and_hash::(s); - assert_ok!(Preimage::::request_preimage(T::ManagerOrigin::successful_origin(), hash)); + assert_ok!(Preimage::::request_preimage( + T::ManagerOrigin::try_successful_origin() + .expect("ManagerOrigin has no successful origin required for the benchmark"), + hash, + )); }: note_preimage(RawOrigin::Signed(caller), preimage) verify { assert!(Preimage::::have_preimage(&hash)); @@ -71,9 +75,15 @@ benchmarks! { note_no_deposit_preimage { let s in 0 .. MAX_SIZE; let (preimage, hash) = sized_preimage_and_hash::(s); - assert_ok!(Preimage::::request_preimage(T::ManagerOrigin::successful_origin(), hash)); - }: note_preimage(T::ManagerOrigin::successful_origin(), preimage) - verify { + assert_ok!(Preimage::::request_preimage( + T::ManagerOrigin::try_successful_origin() + .expect("ManagerOrigin has no successful origin required for the benchmark"), + hash, + )); + }: note_preimage( + T::ManagerOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?, + preimage + ) verify { assert!(Preimage::::have_preimage(&hash)); } @@ -90,9 +100,15 @@ benchmarks! { // Cheap unnote - will not unreserve since there's no deposit held. unnote_no_deposit_preimage { let (preimage, hash) = preimage_and_hash::(); - assert_ok!(Preimage::::note_preimage(T::ManagerOrigin::successful_origin(), preimage)); - }: unnote_preimage(T::ManagerOrigin::successful_origin(), hash) - verify { + assert_ok!(Preimage::::note_preimage( + T::ManagerOrigin::try_successful_origin() + .expect("ManagerOrigin has no successful origin required for the benchmark"), + preimage, + )); + }: unnote_preimage( + T::ManagerOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?, + hash + ) verify { assert!(!Preimage::::have_preimage(&hash)); } @@ -102,8 +118,10 @@ benchmarks! { let noter = funded_account::("noter", 0); whitelist_account!(noter); assert_ok!(Preimage::::note_preimage(RawOrigin::Signed(noter.clone()).into(), preimage)); - }: _(T::ManagerOrigin::successful_origin(), hash) - verify { + }: _( + T::ManagerOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?, + hash + ) verify { let deposit = T::BaseDeposit::get() + T::ByteDeposit::get() * MAX_SIZE.into(); let s = RequestStatus::Requested { deposit: Some((noter, deposit)), count: 1, len: Some(MAX_SIZE) }; assert_eq!(StatusFor::::get(&hash), Some(s)); @@ -111,26 +129,40 @@ benchmarks! { // Cheap request - would unreserve the deposit but none was held. request_no_deposit_preimage { let (preimage, hash) = preimage_and_hash::(); - assert_ok!(Preimage::::note_preimage(T::ManagerOrigin::successful_origin(), preimage)); - }: request_preimage(T::ManagerOrigin::successful_origin(), hash) - verify { + assert_ok!(Preimage::::note_preimage( + T::ManagerOrigin::try_successful_origin() + .expect("ManagerOrigin has no successful origin required for the benchmark"), + preimage, + )); + }: request_preimage( + T::ManagerOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?, + hash + ) verify { let s = RequestStatus::Requested { deposit: None, count: 2, len: Some(MAX_SIZE) }; assert_eq!(StatusFor::::get(&hash), Some(s)); } // Cheap request - the preimage is not yet noted, so deposit to unreserve. request_unnoted_preimage { let (_, hash) = preimage_and_hash::(); - }: request_preimage(T::ManagerOrigin::successful_origin(), hash) - verify { + }: request_preimage( + T::ManagerOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?, + hash + ) verify { let s = RequestStatus::Requested { deposit: None, count: 1, len: None }; assert_eq!(StatusFor::::get(&hash), Some(s)); } // Cheap request - the preimage is already requested, so just a counter bump. request_requested_preimage { let (_, hash) = preimage_and_hash::(); - assert_ok!(Preimage::::request_preimage(T::ManagerOrigin::successful_origin(), hash)); - }: request_preimage(T::ManagerOrigin::successful_origin(), hash) - verify { + assert_ok!(Preimage::::request_preimage( + T::ManagerOrigin::try_successful_origin() + .expect("ManagerOrigin has no successful origin required for the benchmark"), + hash, + )); + }: request_preimage( + T::ManagerOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?, + hash + ) verify { let s = RequestStatus::Requested { deposit: None, count: 2, len: None }; assert_eq!(StatusFor::::get(&hash), Some(s)); } @@ -138,27 +170,53 @@ benchmarks! { // Expensive unrequest - last reference and it's noted, so will destroy the preimage. unrequest_preimage { let (preimage, hash) = preimage_and_hash::(); - assert_ok!(Preimage::::request_preimage(T::ManagerOrigin::successful_origin(), hash)); - assert_ok!(Preimage::::note_preimage(T::ManagerOrigin::successful_origin(), preimage)); - }: _(T::ManagerOrigin::successful_origin(), hash) - verify { + assert_ok!(Preimage::::request_preimage( + T::ManagerOrigin::try_successful_origin() + .expect("ManagerOrigin has no successful origin required for the benchmark"), + hash, + )); + assert_ok!(Preimage::::note_preimage( + T::ManagerOrigin::try_successful_origin() + .expect("ManagerOrigin has no successful origin required for the benchmark"), + preimage, + )); + }: _( + T::ManagerOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?, + hash + ) verify { assert_eq!(StatusFor::::get(&hash), None); } // Cheap unrequest - last reference, but it's not noted. unrequest_unnoted_preimage { let (_, hash) = preimage_and_hash::(); - assert_ok!(Preimage::::request_preimage(T::ManagerOrigin::successful_origin(), hash)); - }: unrequest_preimage(T::ManagerOrigin::successful_origin(), hash) - verify { + assert_ok!(Preimage::::request_preimage( + T::ManagerOrigin::try_successful_origin() + .expect("ManagerOrigin has no successful origin required for the benchmark"), + hash, + )); + }: unrequest_preimage( + T::ManagerOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?, + hash + ) verify { assert_eq!(StatusFor::::get(&hash), None); } // Cheap unrequest - not the last reference. unrequest_multi_referenced_preimage { let (_, hash) = preimage_and_hash::(); - assert_ok!(Preimage::::request_preimage(T::ManagerOrigin::successful_origin(), hash)); - assert_ok!(Preimage::::request_preimage(T::ManagerOrigin::successful_origin(), hash)); - }: unrequest_preimage(T::ManagerOrigin::successful_origin(), hash) - verify { + assert_ok!(Preimage::::request_preimage( + T::ManagerOrigin::try_successful_origin() + .expect("ManagerOrigin has no successful origin required for the benchmark"), + hash, + )); + assert_ok!(Preimage::::request_preimage( + T::ManagerOrigin::try_successful_origin() + .expect("ManagerOrigin has no successful origin required for the benchmark"), + hash, + )); + }: unrequest_preimage( + T::ManagerOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?, + hash + ) verify { let s = RequestStatus::Requested { deposit: None, count: 1, len: None }; assert_eq!(StatusFor::::get(&hash), Some(s)); } diff --git a/frame/ranked-collective/src/benchmarking.rs b/frame/ranked-collective/src/benchmarking.rs index 48df7f1f1e6ab..ad81325becb5e 100644 --- a/frame/ranked-collective/src/benchmarking.rs +++ b/frame/ranked-collective/src/benchmarking.rs @@ -21,7 +21,9 @@ use super::*; #[allow(unused_imports)] use crate::Pallet as RankedCollective; -use frame_benchmarking::v1::{account, benchmarks_instance_pallet, whitelisted_caller}; +use frame_benchmarking::v1::{ + account, benchmarks_instance_pallet, whitelisted_caller, BenchmarkError, +}; use frame_support::{assert_ok, dispatch::UnfilteredDispatchable}; use frame_system::RawOrigin as SystemOrigin; @@ -35,13 +37,15 @@ fn make_member, I: 'static>(rank: Rank) -> T::AccountId { let who = account::("member", MemberCount::::get(0), SEED); let who_lookup = T::Lookup::unlookup(who.clone()); assert_ok!(Pallet::::add_member( - T::PromoteOrigin::successful_origin(), - who_lookup.clone() + T::PromoteOrigin::try_successful_origin() + .expect("PromoteOrigin has no successful origin required for the benchmark"), + who_lookup.clone(), )); for _ in 0..rank { assert_ok!(Pallet::::promote_member( - T::PromoteOrigin::successful_origin(), - who_lookup.clone() + T::PromoteOrigin::try_successful_origin() + .expect("PromoteOrigin has no successful origin required for the benchmark"), + who_lookup.clone(), )); } who @@ -51,7 +55,8 @@ benchmarks_instance_pallet! { add_member { let who = account::("member", 0, SEED); let who_lookup = T::Lookup::unlookup(who.clone()); - let origin = T::PromoteOrigin::successful_origin(); + let origin = + T::PromoteOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; let call = Call::::add_member { who: who_lookup }; }: { call.dispatch_bypass_filter(origin)? } verify { @@ -67,7 +72,8 @@ benchmarks_instance_pallet! { let who_lookup = T::Lookup::unlookup(who.clone()); let last = make_member::(rank); let last_index = (0..=rank).map(|r| IdToIndex::::get(r, &last).unwrap()).collect::>(); - let origin = T::DemoteOrigin::successful_origin(); + let origin = + T::DemoteOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; let call = Call::::remove_member { who: who_lookup, min_rank: rank }; }: { call.dispatch_bypass_filter(origin)? } verify { @@ -83,7 +89,8 @@ benchmarks_instance_pallet! { let rank = r as u16; let who = make_member::(rank); let who_lookup = T::Lookup::unlookup(who.clone()); - let origin = T::PromoteOrigin::successful_origin(); + let origin = + T::PromoteOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; let call = Call::::promote_member { who: who_lookup }; }: { call.dispatch_bypass_filter(origin)? } verify { @@ -99,7 +106,8 @@ benchmarks_instance_pallet! { let who_lookup = T::Lookup::unlookup(who.clone()); let last = make_member::(rank); let last_index = IdToIndex::::get(rank, &last).unwrap(); - let origin = T::DemoteOrigin::successful_origin(); + let origin = + T::DemoteOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; let call = Call::::demote_member { who: who_lookup }; }: { call.dispatch_bypass_filter(origin)? } verify { @@ -115,14 +123,19 @@ benchmarks_instance_pallet! { vote { let caller: T::AccountId = whitelisted_caller(); let caller_lookup = T::Lookup::unlookup(caller.clone()); - assert_ok!(Pallet::::add_member(T::PromoteOrigin::successful_origin(), caller_lookup.clone())); + assert_ok!(Pallet::::add_member( + T::PromoteOrigin::try_successful_origin() + .expect("PromoteOrigin has no successful origin required for the benchmark"), + caller_lookup.clone(), + )); // Create a poll let class = T::Polls::classes().into_iter().next().unwrap(); let rank = T::MinRankOfClass::convert(class.clone()); for _ in 0..rank { assert_ok!(Pallet::::promote_member( - T::PromoteOrigin::successful_origin(), - caller_lookup.clone() + T::PromoteOrigin::try_successful_origin() + .expect("PromoteOrigin has no successful origin required for the benchmark"), + caller_lookup.clone(), )); } diff --git a/frame/ranked-collective/src/lib.rs b/frame/ranked-collective/src/lib.rs index b057a57508023..84be1243c8afc 100644 --- a/frame/ranked-collective/src/lib.rs +++ b/frame/ranked-collective/src/lib.rs @@ -259,19 +259,6 @@ impl, I: 'static, const MIN_RANK: u16> EnsureOrigin::get(MIN_RANK, 0).ok_or(())?; Ok(frame_system::RawOrigin::Signed(who).into()) } - - #[cfg(feature = "runtime-benchmarks")] - fn successful_origin() -> T::RuntimeOrigin { - match Self::try_successful_origin() { - Ok(o) => o, - Err(()) => { - let who: T::AccountId = frame_benchmarking::whitelisted_caller(); - crate::Pallet::::do_add_member_to_rank(who.clone(), MIN_RANK) - .expect("failed to add ranked member"); - frame_system::RawOrigin::Signed(who).into() - }, - } - } } /// Guard to ensure that the given origin is a member of the collective. The account ID of the @@ -295,19 +282,6 @@ impl, I: 'static, const MIN_RANK: u16> EnsureOrigin::get(MIN_RANK, 0).ok_or(())?; Ok(frame_system::RawOrigin::Signed(who).into()) } - - #[cfg(feature = "runtime-benchmarks")] - fn successful_origin() -> T::RuntimeOrigin { - match Self::try_successful_origin() { - Ok(o) => o, - Err(()) => { - let who: T::AccountId = frame_benchmarking::whitelisted_caller(); - crate::Pallet::::do_add_member_to_rank(who.clone(), MIN_RANK) - .expect("failed to add ranked member"); - frame_system::RawOrigin::Signed(who).into() - }, - } - } } /// Guard to ensure that the given origin is a member of the collective. The pair of both the @@ -331,19 +305,6 @@ impl, I: 'static, const MIN_RANK: u16> EnsureOrigin::get(MIN_RANK, 0).ok_or(())?; Ok(frame_system::RawOrigin::Signed(who).into()) } - - #[cfg(feature = "runtime-benchmarks")] - fn successful_origin() -> T::RuntimeOrigin { - match Self::try_successful_origin() { - Ok(o) => o, - Err(()) => { - let who: T::AccountId = frame_benchmarking::whitelisted_caller(); - crate::Pallet::::do_add_member_to_rank(who.clone(), MIN_RANK) - .expect("failed to add ranked member"); - frame_system::RawOrigin::Signed(who).into() - }, - } - } } #[frame_support::pallet] diff --git a/frame/referenda/src/benchmarking.rs b/frame/referenda/src/benchmarking.rs index db5299e0d5bb2..62b37857f2567 100644 --- a/frame/referenda/src/benchmarking.rs +++ b/frame/referenda/src/benchmarking.rs @@ -20,7 +20,9 @@ use super::*; use crate::Pallet as Referenda; use assert_matches::assert_matches; -use frame_benchmarking::v1::{account, benchmarks_instance_pallet, whitelist_account}; +use frame_benchmarking::v1::{ + account, benchmarks_instance_pallet, whitelist_account, BenchmarkError, +}; use frame_support::{ assert_ok, dispatch::UnfilteredDispatchable, @@ -48,8 +50,7 @@ fn dummy_call, I: 'static>() -> Bounded<>::RuntimeCa T::Preimages::bound(call).unwrap() } -fn create_referendum, I: 'static>() -> (T::RuntimeOrigin, ReferendumIndex) { - let origin: T::RuntimeOrigin = T::SubmitOrigin::successful_origin(); +fn create_referendum, I: 'static>(origin: T::RuntimeOrigin) -> ReferendumIndex { if let Ok(caller) = frame_system::ensure_signed(origin.clone()) { T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value()); whitelist_account!(caller); @@ -61,7 +62,7 @@ fn create_referendum, I: 'static>() -> (T::RuntimeOrigin, Referendu let call = crate::Call::::submit { proposal_origin, proposal, enactment_moment }; assert_ok!(call.dispatch_bypass_filter(origin.clone())); let index = ReferendumCount::::get() - 1; - (origin, index) + index } fn place_deposit, I: 'static>(index: ReferendumIndex) { @@ -75,6 +76,7 @@ fn nudge, I: 'static>(index: ReferendumIndex) { } fn fill_queue, I: 'static>( + origin: T::RuntimeOrigin, index: ReferendumIndex, spaces: u32, pass_after: u32, @@ -82,7 +84,7 @@ fn fill_queue, I: 'static>( // First, create enough other referendums to fill the track. let mut others = vec![]; for _ in 0..info::(index).max_deciding { - let (_origin, index) = create_referendum::(); + let index = create_referendum::(origin.clone()); place_deposit::(index); others.push(index); } @@ -90,7 +92,7 @@ fn fill_queue, I: 'static>( // We will also need enough referenda which are queued and passing, we want `MaxQueued - 1` // in order to force the maximum amount of work to insert ours into the queue. for _ in spaces..T::MaxQueued::get() { - let (_origin, index) = create_referendum::(); + let index = create_referendum::(origin.clone()); place_deposit::(index); make_passing_after::(index, Perbill::from_percent(pass_after)); others.push(index); @@ -194,7 +196,8 @@ fn is_not_confirming, I: 'static>(index: ReferendumIndex) -> bool { benchmarks_instance_pallet! { submit { - let origin: T::RuntimeOrigin = T::SubmitOrigin::successful_origin(); + let origin = + T::SubmitOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; if let Ok(caller) = frame_system::ensure_signed(origin.clone()) { T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value()); whitelist_account!(caller); @@ -210,15 +213,19 @@ benchmarks_instance_pallet! { } place_decision_deposit_preparing { - let (origin, index) = create_referendum::(); + let origin = + T::SubmitOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; + let index = create_referendum::(origin.clone()); }: place_decision_deposit(origin, index) verify { assert!(Referenda::::ensure_ongoing(index).unwrap().decision_deposit.is_some()); } place_decision_deposit_queued { - let (origin, index) = create_referendum::(); - fill_queue::(index, 1, 90); + let origin = + T::SubmitOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; + let index = create_referendum::(origin.clone()); + fill_queue::(origin.clone(), index, 1, 90); }: place_decision_deposit(origin, index) verify { let track = Referenda::::ensure_ongoing(index).unwrap().track; @@ -227,8 +234,10 @@ benchmarks_instance_pallet! { } place_decision_deposit_not_queued { - let (origin, index) = create_referendum::(); - fill_queue::(index, 0, 90); + let origin = + T::SubmitOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; + let index = create_referendum::(origin.clone()); + fill_queue::(origin.clone(), index, 0, 90); let track = Referenda::::ensure_ongoing(index).unwrap().track; assert_eq!(TrackQueue::::get(&track).len() as u32, T::MaxQueued::get()); assert!(TrackQueue::::get(&track).into_iter().all(|(i, _)| i != index)); @@ -239,7 +248,9 @@ benchmarks_instance_pallet! { } place_decision_deposit_passing { - let (origin, index) = create_referendum::(); + let origin = + T::SubmitOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; + let index = create_referendum::(origin.clone()); skip_prepare_period::(index); make_passing::(index); }: place_decision_deposit(origin, index) @@ -248,7 +259,9 @@ benchmarks_instance_pallet! { } place_decision_deposit_failing { - let (origin, index) = create_referendum::(); + let origin = + T::SubmitOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; + let index = create_referendum::(origin.clone()); skip_prepare_period::(index); }: place_decision_deposit(origin, index) verify { @@ -256,19 +269,31 @@ benchmarks_instance_pallet! { } refund_decision_deposit { - let (origin, index) = create_referendum::(); + let origin = + T::SubmitOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; + let index = create_referendum::(origin.clone()); place_deposit::(index); - assert_ok!(Referenda::::cancel(T::CancelOrigin::successful_origin(), index)); + assert_ok!(Referenda::::cancel( + T::CancelOrigin::try_successful_origin() + .expect("CancelOrigin has no successful origin required for the benchmark"), + index, + )); }: _(origin, index) verify { assert_matches!(ReferendumInfoFor::::get(index), Some(ReferendumInfo::Cancelled(_, _, None))); } refund_submission_deposit { - let (origin, index) = create_referendum::(); + let origin = + T::SubmitOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; + let index = create_referendum::(origin.clone()); let caller = frame_system::ensure_signed(origin.clone()).unwrap(); let balance = T::Currency::free_balance(&caller); - assert_ok!(Referenda::::cancel(T::CancelOrigin::successful_origin(), index)); + assert_ok!(Referenda::::cancel( + T::CancelOrigin::try_successful_origin() + .expect("CancelOrigin has no successful origin required for the benchmark"), + index, + )); assert_matches!(ReferendumInfoFor::::get(index), Some(ReferendumInfo::Cancelled(_, Some(_), _))); }: _(origin, index) verify { @@ -279,28 +304,42 @@ benchmarks_instance_pallet! { } cancel { - let (_origin, index) = create_referendum::(); + let origin = T::SubmitOrigin::try_successful_origin() + .expect("SubmitOrigin has no successful origin required for the benchmark"); + let index = create_referendum::(origin); place_deposit::(index); - }: _(T::CancelOrigin::successful_origin(), index) - verify { + }: _( + T::CancelOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?, + index + ) verify { assert_matches!(ReferendumInfoFor::::get(index), Some(ReferendumInfo::Cancelled(..))); } kill { - let (_origin, index) = create_referendum::(); + let origin = T::SubmitOrigin::try_successful_origin() + .expect("SubmitOrigin has no successful origin required for the benchmark"); + let index = create_referendum::(origin); place_deposit::(index); - }: _(T::KillOrigin::successful_origin(), index) - verify { + }: _( + T::KillOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?, + index + ) verify { assert_matches!(ReferendumInfoFor::::get(index), Some(ReferendumInfo::Killed(..))); } one_fewer_deciding_queue_empty { - let (_origin, index) = create_referendum::(); + let origin = T::SubmitOrigin::try_successful_origin() + .expect("SubmitOrigin has no successful origin required for the benchmark"); + let index = create_referendum::(origin); place_deposit::(index); skip_prepare_period::(index); nudge::(index); let track = Referenda::::ensure_ongoing(index).unwrap().track; - assert_ok!(Referenda::::cancel(T::CancelOrigin::successful_origin(), index)); + assert_ok!(Referenda::::cancel( + T::CancelOrigin::try_successful_origin() + .expect("CancelOrigin has no successful origin required for the benchmark"), + index, + )); assert_eq!(DecidingCount::::get(&track), 1); }: one_fewer_deciding(RawOrigin::Root, track) verify { @@ -308,11 +347,17 @@ benchmarks_instance_pallet! { } one_fewer_deciding_failing { - let (_origin, index) = create_referendum::(); + let origin = T::SubmitOrigin::try_successful_origin() + .expect("SubmitOrigin has no successful origin required for the benchmark"); + let index = create_referendum::(origin.clone()); // No spaces free in the queue. - let queued = fill_queue::(index, 0, 90); + let queued = fill_queue::(origin, index, 0, 90); let track = Referenda::::ensure_ongoing(index).unwrap().track; - assert_ok!(Referenda::::cancel(T::CancelOrigin::successful_origin(), queued[0])); + assert_ok!(Referenda::::cancel( + T::CancelOrigin::try_successful_origin() + .expect("CancelOrigin has no successful origin required for the benchmark"), + queued[0], + )); assert_eq!(TrackQueue::::get(&track).len() as u32, T::MaxQueued::get()); let deciding_count = DecidingCount::::get(&track); }: one_fewer_deciding(RawOrigin::Root, track) @@ -327,11 +372,17 @@ benchmarks_instance_pallet! { } one_fewer_deciding_passing { - let (_origin, index) = create_referendum::(); + let origin = T::SubmitOrigin::try_successful_origin() + .expect("SubmitOrigin has no successful origin required for the benchmark"); + let index = create_referendum::(origin.clone()); // No spaces free in the queue. - let queued = fill_queue::(index, 0, 0); + let queued = fill_queue::(origin, index, 0, 0); let track = Referenda::::ensure_ongoing(index).unwrap().track; - assert_ok!(Referenda::::cancel(T::CancelOrigin::successful_origin(), queued[0])); + assert_ok!(Referenda::::cancel( + T::CancelOrigin::try_successful_origin() + .expect("CancelOrigin has no successful origin required for the benchmark"), + queued[0], + )); assert_eq!(TrackQueue::::get(&track).len() as u32, T::MaxQueued::get()); let deciding_count = DecidingCount::::get(&track); }: one_fewer_deciding(RawOrigin::Root, track) @@ -346,10 +397,12 @@ benchmarks_instance_pallet! { } nudge_referendum_requeued_insertion { + let origin = T::SubmitOrigin::try_successful_origin() + .expect("SubmitOrigin has no successful origin required for the benchmark"); // First create our referendum and place the deposit. It will be failing. - let (_origin, index) = create_referendum::(); + let index = create_referendum::(origin.clone()); place_deposit::(index); - fill_queue::(index, 0, 90); + fill_queue::(origin, index, 0, 90); // Now nudge ours, with the track now full and the queue full of referenda with votes, // ours will not be in the queue. @@ -367,10 +420,12 @@ benchmarks_instance_pallet! { } nudge_referendum_requeued_slide { + let origin = T::SubmitOrigin::try_successful_origin() + .expect("SubmitOrigin has no successful origin required for the benchmark"); // First create our referendum and place the deposit. It will be failing. - let (_origin, index) = create_referendum::(); + let index = create_referendum::(origin.clone()); place_deposit::(index); - fill_queue::(index, 1, 90); + fill_queue::(origin, index, 1, 90); // Now nudge ours, with the track now full, ours will be queued, but with no votes, it // will have the worst position. @@ -393,10 +448,12 @@ benchmarks_instance_pallet! { // free and this failing. It would result in `QUEUE_SIZE - 1` items being shifted for the // insertion at the beginning. + let origin = T::SubmitOrigin::try_successful_origin() + .expect("SubmitOrigin has no successful origin required for the benchmark"); // First create our referendum and place the deposit. It will be failing. - let (_origin, index) = create_referendum::(); + let index = create_referendum::(origin.clone()); place_deposit::(index); - fill_queue::(index, 1, 0); + fill_queue::(origin, index, 1, 0); let track = Referenda::::ensure_ongoing(index).unwrap().track; assert_eq!(TrackQueue::::get(&track).len() as u32, T::MaxQueued::get() - 1); @@ -410,10 +467,12 @@ benchmarks_instance_pallet! { } nudge_referendum_not_queued { + let origin = T::SubmitOrigin::try_successful_origin() + .expect("SubmitOrigin has no successful origin required for the benchmark"); // First create our referendum and place the deposit. It will be failing. - let (_origin, index) = create_referendum::(); + let index = create_referendum::(origin.clone()); place_deposit::(index); - fill_queue::(index, 0, 0); + fill_queue::(origin, index, 0, 0); let track = Referenda::::ensure_ongoing(index).unwrap().track; assert_eq!(TrackQueue::::get(&track).len() as u32, T::MaxQueued::get()); @@ -427,7 +486,9 @@ benchmarks_instance_pallet! { } nudge_referendum_no_deposit { - let (_origin, index) = create_referendum::(); + let origin = T::SubmitOrigin::try_successful_origin() + .expect("SubmitOrigin has no successful origin required for the benchmark"); + let index = create_referendum::(origin); skip_prepare_period::(index); }: nudge_referendum(RawOrigin::Root, index) verify { @@ -436,7 +497,9 @@ benchmarks_instance_pallet! { } nudge_referendum_preparing { - let (_origin, index) = create_referendum::(); + let origin = T::SubmitOrigin::try_successful_origin() + .expect("SubmitOrigin has no successful origin required for the benchmark"); + let index = create_referendum::(origin); place_deposit::(index); }: nudge_referendum(RawOrigin::Root, index) verify { @@ -445,7 +508,9 @@ benchmarks_instance_pallet! { } nudge_referendum_timed_out { - let (_origin, index) = create_referendum::(); + let origin = T::SubmitOrigin::try_successful_origin() + .expect("SubmitOrigin has no successful origin required for the benchmark"); + let index = create_referendum::(origin); skip_timeout_period::(index); }: nudge_referendum(RawOrigin::Root, index) verify { @@ -454,7 +519,9 @@ benchmarks_instance_pallet! { } nudge_referendum_begin_deciding_failing { - let (_origin, index) = create_referendum::(); + let origin = T::SubmitOrigin::try_successful_origin() + .expect("SubmitOrigin has no successful origin required for the benchmark"); + let index = create_referendum::(origin); place_deposit::(index); skip_prepare_period::(index); }: nudge_referendum(RawOrigin::Root, index) @@ -463,7 +530,9 @@ benchmarks_instance_pallet! { } nudge_referendum_begin_deciding_passing { - let (_origin, index) = create_referendum::(); + let origin = T::SubmitOrigin::try_successful_origin() + .expect("SubmitOrigin has no successful origin required for the benchmark"); + let index = create_referendum::(origin); place_deposit::(index); make_passing::(index); skip_prepare_period::(index); @@ -473,7 +542,9 @@ benchmarks_instance_pallet! { } nudge_referendum_begin_confirming { - let (_origin, index) = create_referendum::(); + let origin = T::SubmitOrigin::try_successful_origin() + .expect("SubmitOrigin has no successful origin required for the benchmark"); + let index = create_referendum::(origin); place_deposit::(index); skip_prepare_period::(index); nudge::(index); @@ -485,7 +556,9 @@ benchmarks_instance_pallet! { } nudge_referendum_end_confirming { - let (_origin, index) = create_referendum::(); + let origin = T::SubmitOrigin::try_successful_origin() + .expect("SubmitOrigin has no successful origin required for the benchmark"); + let index = create_referendum::(origin); place_deposit::(index); skip_prepare_period::(index); make_passing::(index); @@ -498,7 +571,9 @@ benchmarks_instance_pallet! { } nudge_referendum_continue_not_confirming { - let (_origin, index) = create_referendum::(); + let origin = T::SubmitOrigin::try_successful_origin() + .expect("SubmitOrigin has no successful origin required for the benchmark"); + let index = create_referendum::(origin); place_deposit::(index); skip_prepare_period::(index); nudge::(index); @@ -512,7 +587,9 @@ benchmarks_instance_pallet! { } nudge_referendum_continue_confirming { - let (_origin, index) = create_referendum::(); + let origin = T::SubmitOrigin::try_successful_origin() + .expect("SubmitOrigin has no successful origin required for the benchmark"); + let index = create_referendum::(origin); place_deposit::(index); make_passing::(index); skip_prepare_period::(index); @@ -525,7 +602,9 @@ benchmarks_instance_pallet! { } nudge_referendum_approved { - let (_origin, index) = create_referendum::(); + let origin = T::SubmitOrigin::try_successful_origin() + .expect("SubmitOrigin has no successful origin required for the benchmark"); + let index = create_referendum::(origin); place_deposit::(index); skip_prepare_period::(index); make_passing::(index); @@ -538,7 +617,9 @@ benchmarks_instance_pallet! { } nudge_referendum_rejected { - let (_origin, index) = create_referendum::(); + let origin = T::SubmitOrigin::try_successful_origin() + .expect("SubmitOrigin has no successful origin required for the benchmark"); + let index = create_referendum::(origin); place_deposit::(index); skip_prepare_period::(index); make_failing::(index); diff --git a/frame/scheduler/src/benchmarking.rs b/frame/scheduler/src/benchmarking.rs index 9ec82f5c8447e..94a833bd98e0a 100644 --- a/frame/scheduler/src/benchmarking.rs +++ b/frame/scheduler/src/benchmarking.rs @@ -18,7 +18,7 @@ //! Scheduler pallet benchmarking. use super::*; -use frame_benchmarking::v1::{account, benchmarks}; +use frame_benchmarking::v1::{account, benchmarks, BenchmarkError}; use frame_support::{ ensure, traits::{schedule::Priority, BoundedInline}, @@ -244,7 +244,8 @@ benchmarks! { fill_schedule::(when, s)?; assert_eq!(Agenda::::get(when).len(), s as usize); - let schedule_origin = T::ScheduleOrigin::successful_origin(); + let schedule_origin = + T::ScheduleOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; }: _>(schedule_origin, when, 0) verify { ensure!( diff --git a/frame/support/src/traits/dispatch.rs b/frame/support/src/traits/dispatch.rs index 36ddf5b507c0c..50c6c22791944 100644 --- a/frame/support/src/traits/dispatch.rs +++ b/frame/support/src/traits/dispatch.rs @@ -40,25 +40,12 @@ pub trait EnsureOrigin { /// Perform the origin check. fn try_origin(o: OuterOrigin) -> Result; - /// Returns an outer origin capable of passing `try_origin` check. - /// - /// NOTE: This should generally *NOT* be reimplemented. Instead implement - /// `try_successful_origin`. + /// Attempt to get an outer origin capable of passing `try_origin` check. May return `Err` if it + /// is impossible. /// /// ** Should be used for benchmarking only!!! ** #[cfg(feature = "runtime-benchmarks")] - fn successful_origin() -> OuterOrigin { - Self::try_successful_origin().expect("No origin exists which can satisfy the guard") - } - - /// Attept to get an outer origin capable of passing `try_origin` check. May return `Err` if it - /// is impossible. Default implementation just uses `successful_origin()`. - /// - /// ** Should be used for benchmarking only!!! ** - #[cfg(feature = "runtime-benchmarks")] - fn try_successful_origin() -> Result { - Ok(Self::successful_origin()) - } + fn try_successful_origin() -> Result; } /// [`EnsureOrigin`] implementation that always fails. @@ -171,25 +158,12 @@ pub trait EnsureOriginWithArg { /// Perform the origin check, returning the origin value if unsuccessful. This allows chaining. fn try_origin(o: OuterOrigin, a: &Argument) -> Result; - /// Returns an outer origin capable of passing `try_origin` check. - /// - /// NOTE: This should generally *NOT* be reimplemented. Instead implement - /// `try_successful_origin`. - /// - /// ** Should be used for benchmarking only!!! ** - #[cfg(feature = "runtime-benchmarks")] - fn successful_origin(a: &Argument) -> OuterOrigin { - Self::try_successful_origin(a).expect("No origin exists which can satisfy the guard") - } - - /// Attept to get an outer origin capable of passing `try_origin` check. May return `Err` if it - /// is impossible. Default implementation just uses `successful_origin()`. + /// Attempt to get an outer origin capable of passing `try_origin` check. May return `Err` if it + /// is impossible. /// /// ** Should be used for benchmarking only!!! ** #[cfg(feature = "runtime-benchmarks")] - fn try_successful_origin(a: &Argument) -> Result { - Ok(Self::successful_origin(a)) - } + fn try_successful_origin(a: &Argument) -> Result; } pub struct AsEnsureOriginWithArg(sp_std::marker::PhantomData); diff --git a/frame/system/src/tests.rs b/frame/system/src/tests.rs index 8223f66744151..f441e785599eb 100644 --- a/frame/system/src/tests.rs +++ b/frame/system/src/tests.rs @@ -679,10 +679,13 @@ fn ensure_signed_stuff_works() { #[cfg(feature = "runtime-benchmarks")] { - let successful_origin: RuntimeOrigin = EnsureSigned::successful_origin(); + let successful_origin: RuntimeOrigin = EnsureSigned::try_successful_origin() + .expect("EnsureSigned has no successful origin required for the test"); assert_ok!(EnsureSigned::try_origin(successful_origin)); - let successful_origin: RuntimeOrigin = EnsureSignedBy::::successful_origin(); + let successful_origin: RuntimeOrigin = + EnsureSignedBy::::try_successful_origin() + .expect("EnsureSignedBy has no successful origin required for the test"); assert_ok!(EnsureSignedBy::::try_origin(successful_origin)); } } diff --git a/frame/tips/src/benchmarking.rs b/frame/tips/src/benchmarking.rs index 8ffc53b45e4ca..5b1a102b8eb30 100644 --- a/frame/tips/src/benchmarking.rs +++ b/frame/tips/src/benchmarking.rs @@ -19,7 +19,9 @@ #![cfg(feature = "runtime-benchmarks")] -use frame_benchmarking::v1::{account, benchmarks_instance_pallet, whitelisted_caller}; +use frame_benchmarking::v1::{ + account, benchmarks_instance_pallet, whitelisted_caller, BenchmarkError, +}; use frame_support::ensure; use frame_system::RawOrigin; use sp_runtime::traits::Saturating; @@ -196,7 +198,8 @@ benchmarks_instance_pallet! { let reason_hash = T::Hashing::hash(&reason[..]); let hash = T::Hashing::hash_of(&(&reason_hash, &beneficiary)); ensure!(Tips::::contains_key(hash), "tip does not exist"); - let reject_origin = T::RejectOrigin::successful_origin(); + let reject_origin = + T::RejectOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; }: _(reject_origin, hash) impl_benchmark_test_suite!(TipsMod, crate::tests::new_test_ext(), crate::tests::Test); diff --git a/frame/treasury/src/benchmarking.rs b/frame/treasury/src/benchmarking.rs index eb44744506bf4..0947618a2b02f 100644 --- a/frame/treasury/src/benchmarking.rs +++ b/frame/treasury/src/benchmarking.rs @@ -21,7 +21,7 @@ use super::{Pallet as Treasury, *}; -use frame_benchmarking::v1::{account, benchmarks_instance_pallet}; +use frame_benchmarking::v1::{account, benchmarks_instance_pallet, BenchmarkError}; use frame_support::{ dispatch::UnfilteredDispatchable, ensure, @@ -99,7 +99,8 @@ benchmarks_instance_pallet! { beneficiary_lookup )?; let proposal_id = Treasury::::proposal_count() - 1; - let reject_origin = T::RejectOrigin::successful_origin(); + let reject_origin = + T::RejectOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; }: _(reject_origin, proposal_id) approve_proposal { @@ -112,7 +113,8 @@ benchmarks_instance_pallet! { beneficiary_lookup )?; let proposal_id = Treasury::::proposal_count() - 1; - let approve_origin = T::ApproveOrigin::successful_origin(); + let approve_origin = + T::ApproveOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; }: _(approve_origin, proposal_id) remove_approval { @@ -124,7 +126,8 @@ benchmarks_instance_pallet! { )?; let proposal_id = Treasury::::proposal_count() - 1; Treasury::::approve_proposal(RawOrigin::Root.into(), proposal_id)?; - let reject_origin = T::RejectOrigin::successful_origin(); + let reject_origin = + T::RejectOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; }: _(reject_origin, proposal_id) on_initialize_proposals { diff --git a/frame/uniques/src/benchmarking.rs b/frame/uniques/src/benchmarking.rs index 5ecb093a5d010..2656582f0e073 100644 --- a/frame/uniques/src/benchmarking.rs +++ b/frame/uniques/src/benchmarking.rs @@ -21,7 +21,7 @@ use super::*; use frame_benchmarking::v1::{ - account, benchmarks_instance_pallet, whitelist_account, whitelisted_caller, + account, benchmarks_instance_pallet, whitelist_account, whitelisted_caller, BenchmarkError, }; use frame_support::{ dispatch::UnfilteredDispatchable, @@ -137,7 +137,8 @@ fn assert_last_event, I: 'static>(generic_event: >:: benchmarks_instance_pallet! { create { let collection = T::Helper::collection(0); - let origin = T::CreateOrigin::successful_origin(&collection); + let origin = T::CreateOrigin::try_successful_origin(&collection) + .map_err(|_| BenchmarkError::Weightless)?; let caller = T::CreateOrigin::ensure_origin(origin.clone(), &collection).unwrap(); whitelist_account!(caller); let admin = T::Lookup::unlookup(caller.clone()); @@ -290,7 +291,8 @@ benchmarks_instance_pallet! { force_item_status { let (collection, caller, caller_lookup) = create_collection::(); - let origin = T::ForceOrigin::successful_origin(); + let origin = + T::ForceOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; let call = Call::::force_item_status { collection, owner: caller_lookup.clone(), diff --git a/frame/whitelist/src/benchmarking.rs b/frame/whitelist/src/benchmarking.rs index e64842b34df59..582f4a7997c67 100644 --- a/frame/whitelist/src/benchmarking.rs +++ b/frame/whitelist/src/benchmarking.rs @@ -20,7 +20,7 @@ #![cfg(feature = "runtime-benchmarks")] use super::*; -use frame_benchmarking::v1::benchmarks; +use frame_benchmarking::v1::{benchmarks, BenchmarkError}; use frame_support::{ensure, traits::EnsureOrigin}; #[cfg(test)] @@ -28,7 +28,8 @@ use crate::Pallet as Whitelist; benchmarks! { whitelist_call { - let origin = T::WhitelistOrigin::successful_origin(); + let origin = + T::WhitelistOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; let call_hash = Default::default(); }: _(origin, call_hash) verify { @@ -43,7 +44,8 @@ benchmarks! { } remove_whitelisted_call { - let origin = T::WhitelistOrigin::successful_origin(); + let origin = + T::WhitelistOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; let call_hash = Default::default(); Pallet::::whitelist_call(origin.clone(), call_hash) .expect("whitelisting call must be successful"); @@ -70,7 +72,8 @@ benchmarks! { // NOTE: we remove `10` because we need some bytes to encode the variants and vec length let n in 1 .. T::Preimages::MAX_LENGTH as u32 - 10; - let origin = T::DispatchWhitelistedOrigin::successful_origin(); + let origin = T::DispatchWhitelistedOrigin::try_successful_origin() + .map_err(|_| BenchmarkError::Weightless)?; let remark = sp_std::vec![1u8; n as usize]; let call: ::RuntimeCall = frame_system::Call::remark { remark }.into(); let call_weight = call.get_dispatch_info().weight; @@ -98,7 +101,8 @@ benchmarks! { dispatch_whitelisted_call_with_preimage { let n in 1 .. 10_000; - let origin = T::DispatchWhitelistedOrigin::successful_origin(); + let origin = T::DispatchWhitelistedOrigin::try_successful_origin() + .map_err(|_| BenchmarkError::Weightless)?; let remark = sp_std::vec![1u8; n as usize]; let call: ::RuntimeCall = frame_system::Call::remark { remark }.into(); From 4ff092b9c0ef27834a616e8771ee5fe21f3ab73d Mon Sep 17 00:00:00 2001 From: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Date: Wed, 1 Feb 2023 10:38:41 -0300 Subject: [PATCH 077/162] hooks default impl missing where clause (#13264) * hooks default impl missing where clause * add tests * Update frame/support/test/tests/pallet_ui/pass/where_clause_missing_hooks.rs --------- Co-authored-by: parity-processbot <> --- .../procedural/src/pallet/expand/hooks.rs | 2 +- .../tests/pallet_ui/duplicate_store_attr.rs | 3 +-- .../pass/where_clause_missing_hooks.rs | 19 +++++++++++++++++++ 3 files changed, 21 insertions(+), 3 deletions(-) create mode 100644 frame/support/test/tests/pallet_ui/pass/where_clause_missing_hooks.rs diff --git a/frame/support/procedural/src/pallet/expand/hooks.rs b/frame/support/procedural/src/pallet/expand/hooks.rs index c41a65b57b57a..987d0691b1ecc 100644 --- a/frame/support/procedural/src/pallet/expand/hooks.rs +++ b/frame/support/procedural/src/pallet/expand/hooks.rs @@ -76,7 +76,7 @@ pub fn expand_hooks(def: &mut Def) -> proc_macro2::TokenStream { quote::quote! { impl<#type_impl_gen> #frame_support::traits::Hooks<::BlockNumber> - for Pallet<#type_use_gen> {} + for #pallet_ident<#type_use_gen> #where_clause {} } } else { proc_macro2::TokenStream::new() diff --git a/frame/support/test/tests/pallet_ui/duplicate_store_attr.rs b/frame/support/test/tests/pallet_ui/duplicate_store_attr.rs index d675ddefe985b..ab318034aca05 100644 --- a/frame/support/test/tests/pallet_ui/duplicate_store_attr.rs +++ b/frame/support/test/tests/pallet_ui/duplicate_store_attr.rs @@ -22,5 +22,4 @@ mod pallet { type Foo = StorageValue<_, u8>; } -fn main() { -} +fn main() {} diff --git a/frame/support/test/tests/pallet_ui/pass/where_clause_missing_hooks.rs b/frame/support/test/tests/pallet_ui/pass/where_clause_missing_hooks.rs new file mode 100644 index 0000000000000..bf5f22306207a --- /dev/null +++ b/frame/support/test/tests/pallet_ui/pass/where_clause_missing_hooks.rs @@ -0,0 +1,19 @@ +#[frame_support::pallet] +mod pallet { + #[pallet::config] + pub trait Config: frame_system::Config where ::Index: From {} + + #[pallet::pallet] + pub struct Pallet(core::marker::PhantomData); + + #[pallet::call] + impl Pallet where ::Index: From {} + + impl Pallet where ::Index: From { + fn foo(x: u128) { + let _index = ::Index::from(x); + } + } +} + +fn main() {} From 0d47b6293cfe653434f9e7756f83a605ad4a4403 Mon Sep 17 00:00:00 2001 From: Matteo Muraca <56828990+muraca@users.noreply.github.com> Date: Wed, 1 Feb 2023 18:11:34 +0100 Subject: [PATCH 078/162] implemented `contains_prefix` for StorageDoubleMap and StorageNMap (#13232) * implemented `contains_prefix` for StorageDoubleMap and StorageNMap Signed-off-by: muraca * match prefix to next_key Signed-off-by: muraca * warning unexpected behaviour with empty keys Signed-off-by: muraca * clarifications for unhashed::contains_prefixed_key Signed-off-by: muraca * added tests for StorageNMap Signed-off-by: muraca --------- Signed-off-by: muraca --- .../src/storage/generator/double_map.rs | 7 +++ frame/support/src/storage/generator/nmap.rs | 7 +++ frame/support/src/storage/mod.rs | 47 ++++++++++++++++++- frame/support/src/storage/unhashed.rs | 10 ++++ 4 files changed, 70 insertions(+), 1 deletion(-) diff --git a/frame/support/src/storage/generator/double_map.rs b/frame/support/src/storage/generator/double_map.rs index c95dcee9d7e5c..b60bb79566d51 100644 --- a/frame/support/src/storage/generator/double_map.rs +++ b/frame/support/src/storage/generator/double_map.rs @@ -233,6 +233,13 @@ where .into() } + fn contains_prefix(k1: KArg1) -> bool + where + KArg1: EncodeLike, + { + unhashed::contains_prefixed_key(Self::storage_double_map_final_key1(k1).as_ref()) + } + fn iter_prefix_values(k1: KArg1) -> storage::PrefixIterator where KArg1: ?Sized + EncodeLike, diff --git a/frame/support/src/storage/generator/nmap.rs b/frame/support/src/storage/generator/nmap.rs index 79f3d72044e28..8cf1459431171 100755 --- a/frame/support/src/storage/generator/nmap.rs +++ b/frame/support/src/storage/generator/nmap.rs @@ -208,6 +208,13 @@ where ) } + fn contains_prefix(partial_key: KP) -> bool + where + K: HasKeyPrefix, + { + unhashed::contains_prefixed_key(&Self::storage_n_map_partial_key(partial_key)) + } + fn iter_prefix_values(partial_key: KP) -> PrefixIterator where K: HasKeyPrefix, diff --git a/frame/support/src/storage/mod.rs b/frame/support/src/storage/mod.rs index 28f2dee992281..dd91d8cc2a335 100644 --- a/frame/support/src/storage/mod.rs +++ b/frame/support/src/storage/mod.rs @@ -563,6 +563,12 @@ pub trait StorageDoubleMap { where KArg1: ?Sized + EncodeLike; + /// Does any value under the first key `k1` (explicitly) exist in storage? + /// Might have unexpected behaviour with empty keys, e.g. `[]`. + fn contains_prefix(k1: KArg1) -> bool + where + KArg1: EncodeLike; + /// Iterate over values that share the first key. fn iter_prefix_values(k1: KArg1) -> PrefixIterator where @@ -739,6 +745,12 @@ pub trait StorageNMap { where K: HasKeyPrefix; + /// Does any value under a `partial_key` prefix (explicitly) exist in storage? + /// Might have unexpected behaviour with empty keys, e.g. `[]`. + fn contains_prefix(partial_key: KP) -> bool + where + K: HasKeyPrefix; + /// Iterate over values that share the partial prefix key. fn iter_prefix_values(partial_key: KP) -> PrefixIterator where @@ -1485,7 +1497,7 @@ pub fn storage_prefix(pallet_name: &[u8], storage_name: &[u8]) -> [u8; 32] { #[cfg(test)] mod test { use super::*; - use crate::{assert_ok, hash::Identity, Twox128}; + use crate::{assert_ok, hash::Identity, pallet_prelude::NMapKey, Twox128}; use bounded_vec::BoundedVec; use frame_support::traits::ConstU32; use generator::StorageValue as _; @@ -1780,6 +1792,39 @@ mod test { #[crate::storage_alias] type FooDoubleMap = StorageDoubleMap>>; + #[crate::storage_alias] + type FooTripleMap = StorageNMap< + Prefix, + (NMapKey, NMapKey, NMapKey), + u64, + >; + + #[test] + fn contains_prefix_works() { + TestExternalities::default().execute_with(|| { + // Test double maps + assert!(FooDoubleMap::iter_prefix_values(1).next().is_none()); + assert_eq!(FooDoubleMap::contains_prefix(1), false); + + assert_ok!(FooDoubleMap::try_append(1, 1, 4)); + assert_ok!(FooDoubleMap::try_append(2, 1, 4)); + assert!(FooDoubleMap::iter_prefix_values(1).next().is_some()); + assert!(FooDoubleMap::contains_prefix(1)); + FooDoubleMap::remove(1, 1); + assert_eq!(FooDoubleMap::contains_prefix(1), false); + + // Test N Maps + assert!(FooTripleMap::iter_prefix_values((1,)).next().is_none()); + assert_eq!(FooTripleMap::contains_prefix((1,)), false); + + FooTripleMap::insert((1, 1, 1), 4); + FooTripleMap::insert((2, 1, 1), 4); + assert!(FooTripleMap::iter_prefix_values((1,)).next().is_some()); + assert!(FooTripleMap::contains_prefix((1,))); + FooTripleMap::remove((1, 1, 1)); + assert_eq!(FooTripleMap::contains_prefix((1,)), false); + }); + } #[test] fn try_append_works() { diff --git a/frame/support/src/storage/unhashed.rs b/frame/support/src/storage/unhashed.rs index 850e93e7d7fe4..8388c5f885c51 100644 --- a/frame/support/src/storage/unhashed.rs +++ b/frame/support/src/storage/unhashed.rs @@ -154,6 +154,16 @@ pub fn clear_prefix( MultiRemovalResults { maybe_cursor, backend: i, unique: i, loops: i } } +/// Returns `true` if the storage contains any key, which starts with a certain prefix, +/// and is longer than said prefix. +/// This means that a key which equals the prefix will not be counted. +pub fn contains_prefixed_key(prefix: &[u8]) -> bool { + match sp_io::storage::next_key(prefix) { + Some(key) => key.starts_with(prefix), + None => false, + } +} + /// Get a Vec of bytes from storage. pub fn get_raw(key: &[u8]) -> Option> { sp_io::storage::get(key).map(|value| value.to_vec()) From f88a55ead416b37d71f933dea2bd29d1fbf1d088 Mon Sep 17 00:00:00 2001 From: Sergej Sakac <73715684+Szegoo@users.noreply.github.com> Date: Wed, 1 Feb 2023 18:17:05 +0100 Subject: [PATCH 079/162] Calling proxy doesn't remove announcement (#13267) * Calling proxy doesn't remove announcement * Update frame/proxy/src/tests.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * fmt --------- Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> --- frame/proxy/src/lib.rs | 2 -- frame/proxy/src/tests.rs | 17 +++++++++++++++++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/frame/proxy/src/lib.rs b/frame/proxy/src/lib.rs index d98534d16a21b..dfe8c86ca5097 100644 --- a/frame/proxy/src/lib.rs +++ b/frame/proxy/src/lib.rs @@ -183,8 +183,6 @@ pub mod pallet { /// Dispatch the given `call` from an account that the sender is authorised for through /// `add_proxy`. /// - /// Removes any corresponding announcement(s). - /// /// The dispatch origin for this call must be _Signed_. /// /// Parameters: diff --git a/frame/proxy/src/tests.rs b/frame/proxy/src/tests.rs index 3eb3ab3705332..0e7db3512f15b 100644 --- a/frame/proxy/src/tests.rs +++ b/frame/proxy/src/tests.rs @@ -288,6 +288,23 @@ fn announcer_must_be_proxy() { }); } +#[test] +fn calling_proxy_doesnt_remove_announcement() { + new_test_ext().execute_with(|| { + assert_ok!(Proxy::add_proxy(RuntimeOrigin::signed(1), 2, ProxyType::Any, 0)); + + let call = Box::new(call_transfer(6, 1)); + let call_hash = BlakeTwo256::hash_of(&call); + + assert_ok!(Proxy::announce(RuntimeOrigin::signed(2), 1, call_hash)); + assert_ok!(Proxy::proxy(RuntimeOrigin::signed(2), 1, None, call)); + + // The announcement is not removed by calling proxy. + let announcements = Announcements::::get(2); + assert_eq!(announcements.0, vec![Announcement { real: 1, call_hash, height: 1 }]); + }); +} + #[test] fn delayed_requires_pre_announcement() { new_test_ext().execute_with(|| { From da40ff14e082aff9f606227ec18db4906379ed01 Mon Sep 17 00:00:00 2001 From: Sergej Sakac <73715684+Szegoo@users.noreply.github.com> Date: Thu, 2 Feb 2023 07:47:49 +0100 Subject: [PATCH 080/162] Fee and tip represented as asset ID inside `AssetTxFeePaid` (#13083) * fee & tip in the asset ID Balance type * docs * rewrite * update runtime config * docs --- .../asset-tx-payment/src/lib.rs | 26 ++++++++++--------- .../asset-tx-payment/src/payment.rs | 17 ++++++++---- 2 files changed, 26 insertions(+), 17 deletions(-) diff --git a/frame/transaction-payment/asset-tx-payment/src/lib.rs b/frame/transaction-payment/asset-tx-payment/src/lib.rs index 230b307317f8b..645ebb1e123be 100644 --- a/frame/transaction-payment/asset-tx-payment/src/lib.rs +++ b/frame/transaction-payment/asset-tx-payment/src/lib.rs @@ -134,8 +134,8 @@ pub mod pallet { /// has been paid by `who` in an asset `asset_id`. AssetTxFeePaid { who: T::AccountId, - actual_fee: BalanceOf, - tip: BalanceOf, + actual_fee: AssetBalanceOf, + tip: AssetBalanceOf, asset_id: Option>, }, } @@ -284,18 +284,20 @@ where let actual_fee = pallet_transaction_payment::Pallet::::compute_actual_fee( len as u32, info, post_info, tip, ); - T::OnChargeAssetTransaction::correct_and_deposit_fee( - &who, - info, - post_info, - actual_fee.into(), - tip.into(), - already_withdrawn.into(), - )?; + + let (converted_fee, converted_tip) = + T::OnChargeAssetTransaction::correct_and_deposit_fee( + &who, + info, + post_info, + actual_fee.into(), + tip.into(), + already_withdrawn.into(), + )?; Pallet::::deposit_event(Event::::AssetTxFeePaid { who, - actual_fee, - tip, + actual_fee: converted_fee, + tip: converted_tip, asset_id, }); }, diff --git a/frame/transaction-payment/asset-tx-payment/src/payment.rs b/frame/transaction-payment/asset-tx-payment/src/payment.rs index 85d1bec4b275c..ae8253b6e7d3e 100644 --- a/frame/transaction-payment/asset-tx-payment/src/payment.rs +++ b/frame/transaction-payment/asset-tx-payment/src/payment.rs @@ -58,6 +58,8 @@ pub trait OnChargeAssetTransaction { /// the corrected amount. /// /// Note: The `fee` already includes the `tip`. + /// + /// Returns the fee and tip in the asset used for payment as (fee, tip). fn correct_and_deposit_fee( who: &T::AccountId, dispatch_info: &DispatchInfoOf, @@ -65,7 +67,7 @@ pub trait OnChargeAssetTransaction { corrected_fee: Self::Balance, tip: Self::Balance, already_withdrawn: Self::LiquidityInfo, - ) -> Result<(), TransactionValidityError>; + ) -> Result<(AssetBalanceOf, AssetBalanceOf), TransactionValidityError>; } /// Allows specifying what to do with the withdrawn asset fees. @@ -132,19 +134,24 @@ where /// Since the predicted fee might have been too high, parts of the fee may be refunded. /// /// Note: The `corrected_fee` already includes the `tip`. + /// + /// Returns the fee and tip in the asset used for payment as (fee, tip). fn correct_and_deposit_fee( who: &T::AccountId, _dispatch_info: &DispatchInfoOf, _post_info: &PostDispatchInfoOf, corrected_fee: Self::Balance, - _tip: Self::Balance, + tip: Self::Balance, paid: Self::LiquidityInfo, - ) -> Result<(), TransactionValidityError> { + ) -> Result<(AssetBalanceOf, AssetBalanceOf), TransactionValidityError> { let min_converted_fee = if corrected_fee.is_zero() { Zero::zero() } else { One::one() }; - // Convert the corrected fee into the asset used for payment. + // Convert the corrected fee and tip into the asset used for payment. let converted_fee = CON::to_asset_balance(corrected_fee, paid.asset()) .map_err(|_| -> TransactionValidityError { InvalidTransaction::Payment.into() })? .max(min_converted_fee); + let converted_tip = CON::to_asset_balance(tip, paid.asset()) + .map_err(|_| -> TransactionValidityError { InvalidTransaction::Payment.into() })?; + // Calculate how much refund we should return. let (final_fee, refund) = paid.split(converted_fee); // Refund to the account that paid the fees. If this fails, the account might have dropped @@ -152,6 +159,6 @@ where let _ = >::resolve(who, refund); // Handle the final fee, e.g. by transferring to the block author or burning. HC::handle_credit(final_fee); - Ok(()) + Ok((converted_fee, converted_tip)) } } From c9310e122625ff473eceaa3917b39ed2bc0ec4c1 Mon Sep 17 00:00:00 2001 From: Davirain Date: Thu, 2 Feb 2023 18:07:48 +0800 Subject: [PATCH 081/162] Move beefy-merkle-tree to utils/binary-merkle-tree and make it generic (#13076) * move BeefyMmrApi to pallet-beefy-mmr * fix test_utils use pallet-beefy-mmr BeefyMmrApi * Move beefy-merkle-tree to utils and Rename to Merkle-tree * fix fmt and test * Update merkle-tree to binary-merkle-tree and Remove Keccak256 mod from merkle-tree * change merkle-tree name to binary-merkle-tree * mirr fix --- Cargo.lock | 11 +-- Cargo.toml | 2 +- frame/beefy-mmr/Cargo.toml | 6 +- frame/beefy-mmr/src/lib.rs | 16 +++- frame/beefy-mmr/src/mock.rs | 2 +- test-utils/runtime/Cargo.toml | 4 +- test-utils/runtime/src/lib.rs | 2 +- .../binary-merkle-tree}/Cargo.toml | 14 ++- .../binary-merkle-tree}/src/lib.rs | 89 ++++++++----------- 9 files changed, 75 insertions(+), 71 deletions(-) rename {frame/beefy-mmr/primitives => utils/binary-merkle-tree}/Cargo.toml (58%) rename {frame/beefy-mmr/primitives => utils/binary-merkle-tree}/src/lib.rs (93%) diff --git a/Cargo.lock b/Cargo.lock index 29ddf38328519..a0e9e0e636cdb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -543,14 +543,14 @@ dependencies = [ ] [[package]] -name = "beefy-merkle-tree" +name = "binary-merkle-tree" version = "4.0.0-dev" dependencies = [ "array-bytes", "env_logger", + "hash-db", "log", - "sp-api", - "sp-beefy", + "sp-core", "sp-runtime", ] @@ -5499,7 +5499,7 @@ name = "pallet-beefy-mmr" version = "4.0.0-dev" dependencies = [ "array-bytes", - "beefy-merkle-tree", + "binary-merkle-tree", "frame-support", "frame-system", "log", @@ -5509,6 +5509,7 @@ dependencies = [ "parity-scale-codec", "scale-info", "serde", + "sp-api", "sp-beefy", "sp-core", "sp-io", @@ -10699,7 +10700,6 @@ dependencies = [ name = "substrate-test-runtime" version = "2.0.0" dependencies = [ - "beefy-merkle-tree", "cfg-if", "frame-support", "frame-system", @@ -10708,6 +10708,7 @@ dependencies = [ "log", "memory-db", "pallet-babe", + "pallet-beefy-mmr", "pallet-timestamp", "parity-scale-codec", "sc-block-builder", diff --git a/Cargo.toml b/Cargo.toml index b004886e83f9a..f87172b5ebabd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -85,7 +85,6 @@ members = [ "frame/balances", "frame/beefy", "frame/beefy-mmr", - "frame/beefy-mmr/primitives", "frame/benchmarking", "frame/benchmarking/pov", "frame/bounties", @@ -246,6 +245,7 @@ members = [ "utils/frame/rpc/client", "utils/prometheus", "utils/wasm-builder", + "utils/binary-merkle-tree", ] # The list of dependencies below (which can be both direct and indirect dependencies) are crates diff --git a/frame/beefy-mmr/Cargo.toml b/frame/beefy-mmr/Cargo.toml index 54da26c394f0c..1d24e821c5012 100644 --- a/frame/beefy-mmr/Cargo.toml +++ b/frame/beefy-mmr/Cargo.toml @@ -14,7 +14,7 @@ codec = { package = "parity-scale-codec", version = "3.2.2", default-features = log = { version = "0.4.17", default-features = false } scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } serde = { version = "1.0.136", optional = true } -beefy-merkle-tree = { version = "4.0.0-dev", default-features = false, path = "./primitives" } +binary-merkle-tree = { version = "4.0.0-dev", default-features = false, path = "../../utils/binary-merkle-tree" } beefy-primitives = { version = "4.0.0-dev", default-features = false, path = "../../primitives/beefy", package = "sp-beefy" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } @@ -25,6 +25,7 @@ sp-core = { version = "7.0.0", default-features = false, path = "../../primitive sp-io = { version = "7.0.0", default-features = false, path = "../../primitives/io" } sp-runtime = { version = "7.0.0", default-features = false, path = "../../primitives/runtime" } sp-std = { version = "5.0.0", default-features = false, path = "../../primitives/std" } +sp-api = { version = "4.0.0-dev", default-features = false, path = "../../primitives/api" } [dev-dependencies] array-bytes = "4.1" @@ -34,7 +35,7 @@ sp-staking = { version = "4.0.0-dev", path = "../../primitives/staking" } default = ["std"] std = [ "array-bytes", - "beefy-merkle-tree/std", + "binary-merkle-tree/std", "beefy-primitives/std", "codec/std", "frame-support/std", @@ -49,5 +50,6 @@ std = [ "sp-io/std", "sp-runtime/std", "sp-std/std", + "sp-api/std", ] try-runtime = ["frame-support/try-runtime"] diff --git a/frame/beefy-mmr/src/lib.rs b/frame/beefy-mmr/src/lib.rs index 0b7fc22cd279b..e5506ecd01d6e 100644 --- a/frame/beefy-mmr/src/lib.rs +++ b/frame/beefy-mmr/src/lib.rs @@ -200,10 +200,24 @@ impl Pallet { .map(T::BeefyAuthorityToMerkleLeaf::convert) .collect::>(); let len = beefy_addresses.len() as u32; - let root = beefy_merkle_tree::merkle_root::<::Hashing, _>( + let root = binary_merkle_tree::merkle_root::<::Hashing, _>( beefy_addresses, ) .into(); BeefyAuthoritySet { id, len, root } } } + +sp_api::decl_runtime_apis! { + /// API useful for BEEFY light clients. + pub trait BeefyMmrApi + where + BeefyAuthoritySet: sp_api::Decode, + { + /// Return the currently active BEEFY authority set proof. + fn authority_set_proof() -> BeefyAuthoritySet; + + /// Return the next/queued BEEFY authority set proof. + fn next_authority_set_proof() -> BeefyNextAuthoritySet; + } +} diff --git a/frame/beefy-mmr/src/mock.rs b/frame/beefy-mmr/src/mock.rs index 0a64ad3fc9976..2de71cd5b320a 100644 --- a/frame/beefy-mmr/src/mock.rs +++ b/frame/beefy-mmr/src/mock.rs @@ -147,7 +147,7 @@ impl BeefyDataProvider> for DummyDataProvider { fn extra_data() -> Vec { let mut col = vec![(15, vec![1, 2, 3]), (5, vec![4, 5, 6])]; col.sort(); - beefy_merkle_tree::merkle_root::<::Hashing, _>( + binary_merkle_tree::merkle_root::<::Hashing, _>( col.into_iter().map(|pair| pair.encode()), ) .as_ref() diff --git a/test-utils/runtime/Cargo.toml b/test-utils/runtime/Cargo.toml index 2c943c47f32b0..0852003a6808f 100644 --- a/test-utils/runtime/Cargo.toml +++ b/test-utils/runtime/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] beefy-primitives = { version = "4.0.0-dev", default-features = false, path = "../../primitives/beefy", package = "sp-beefy" } -beefy-merkle-tree = { version = "4.0.0-dev", default-features = false, path = "../../frame/beefy-mmr/primitives" } +pallet-beefy-mmr = { version = "4.0.0-dev", default-features = false, path = "../../frame/beefy-mmr" } sp-application-crypto = { version = "7.0.0", default-features = false, path = "../../primitives/application-crypto" } sp-consensus-aura = { version = "0.10.0-dev", default-features = false, path = "../../primitives/consensus/aura" } sp-consensus-babe = { version = "0.10.0-dev", default-features = false, path = "../../primitives/consensus/babe" } @@ -67,7 +67,7 @@ default = [ ] std = [ "beefy-primitives/std", - "beefy-merkle-tree/std", + "pallet-beefy-mmr/std", "sp-application-crypto/std", "sp-consensus-aura/std", "sp-consensus-babe/std", diff --git a/test-utils/runtime/src/lib.rs b/test-utils/runtime/src/lib.rs index 8b64528e243bd..5fc7c5e8558ea 100644 --- a/test-utils/runtime/src/lib.rs +++ b/test-utils/runtime/src/lib.rs @@ -978,7 +978,7 @@ cfg_if! { } } - impl beefy_merkle_tree::BeefyMmrApi for Runtime { + impl pallet_beefy_mmr::BeefyMmrApi for Runtime { fn authority_set_proof() -> beefy_primitives::mmr::BeefyAuthoritySet { Default::default() } diff --git a/frame/beefy-mmr/primitives/Cargo.toml b/utils/binary-merkle-tree/Cargo.toml similarity index 58% rename from frame/beefy-mmr/primitives/Cargo.toml rename to utils/binary-merkle-tree/Cargo.toml index c087bc2f37cd3..a59d27fb09bb9 100644 --- a/frame/beefy-mmr/primitives/Cargo.toml +++ b/utils/binary-merkle-tree/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "beefy-merkle-tree" +name = "binary-merkle-tree" version = "4.0.0-dev" authors = ["Parity Technologies "] edition = "2021" @@ -11,20 +11,18 @@ homepage = "https://substrate.io" [dependencies] array-bytes = { version = "4.1", optional = true } log = { version = "0.4", default-features = false, optional = true } - -beefy-primitives = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/beefy", package = "sp-beefy" } -sp-api = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/api" } -sp-runtime = { version = "7.0.0", default-features = false, path = "../../../primitives/runtime" } +hash-db = { version = "0.15.2", default-features = false } [dev-dependencies] array-bytes = "4.1" env_logger = "0.9" +sp-core = { version = "7.0.0", path = "../../primitives/core" } +sp-runtime = { version = "7.0.0", path = "../../primitives/runtime" } [features] debug = ["array-bytes", "log"] default = ["debug", "std"] std = [ - "beefy-primitives/std", - "sp-api/std", - "sp-runtime/std" + "log/std", + "hash-db/std" ] diff --git a/frame/beefy-mmr/primitives/src/lib.rs b/utils/binary-merkle-tree/src/lib.rs similarity index 93% rename from frame/beefy-mmr/primitives/src/lib.rs rename to utils/binary-merkle-tree/src/lib.rs index e6f8acefb039a..42f4e8a5bbf26 100644 --- a/frame/beefy-mmr/primitives/src/lib.rs +++ b/utils/binary-merkle-tree/src/lib.rs @@ -31,40 +31,42 @@ //! efficient by removing the need to track which side each intermediate hash is concatenated on. //! //! If the number of leaves is not even, last leaf (hash of) is promoted to the upper layer. +#[cfg(not(feature = "std"))] +extern crate alloc; +#[cfg(not(feature = "std"))] +use alloc::vec; +#[cfg(not(feature = "std"))] +use alloc::vec::Vec; -pub use sp_runtime::traits::Keccak256; -use sp_runtime::{app_crypto::sp_core, sp_std, traits::Hash as HashT}; -use sp_std::{vec, vec::Vec}; - -use beefy_primitives::mmr::{BeefyAuthoritySet, BeefyNextAuthoritySet}; +use hash_db::Hasher; /// Construct a root hash of a Binary Merkle Tree created from given leaves. /// /// See crate-level docs for details about Merkle Tree construction. /// /// In case an empty list of leaves is passed the function returns a 0-filled hash. -pub fn merkle_root(leaves: I) -> H::Output +pub fn merkle_root(leaves: I) -> H::Out where - H: HashT, - H::Output: Default + AsRef<[u8]> + PartialOrd, + H: Hasher, + H::Out: Default + AsRef<[u8]> + PartialOrd, I: IntoIterator, I::Item: AsRef<[u8]>, { - let iter = leaves.into_iter().map(|l| ::hash(l.as_ref())); + let iter = leaves.into_iter().map(|l| ::hash(l.as_ref())); merkelize::(iter, &mut ()).into() } -fn merkelize(leaves: I, visitor: &mut V) -> H::Output +fn merkelize(leaves: I, visitor: &mut V) -> H::Out where - H: HashT, - H::Output: Default + AsRef<[u8]> + PartialOrd, - V: Visitor, - I: Iterator, + H: Hasher, + H::Out: Default + AsRef<[u8]> + PartialOrd, + V: Visitor, + I: Iterator, { let upper = Vec::with_capacity((leaves.size_hint().1.unwrap_or(0).saturating_add(1)) / 2); let mut next = match merkelize_row::(leaves, upper, visitor) { Ok(root) => return root, - Err(next) if next.is_empty() => return H::Output::default(), + Err(next) if next.is_empty() => return H::Out::default(), Err(next) => next, }; @@ -139,17 +141,17 @@ impl Visitor for () { /// # Panic /// /// The function will panic if given `leaf_index` is greater than the number of leaves. -pub fn merkle_proof(leaves: I, leaf_index: usize) -> MerkleProof +pub fn merkle_proof(leaves: I, leaf_index: usize) -> MerkleProof where - H: HashT, - H::Output: Default + Copy + AsRef<[u8]> + PartialOrd, + H: Hasher, + H::Out: Default + Copy + AsRef<[u8]> + PartialOrd, I: IntoIterator, I::IntoIter: ExactSizeIterator, T: AsRef<[u8]>, { let mut leaf = None; let iter = leaves.into_iter().enumerate().map(|(idx, l)| { - let hash = ::hash(l.as_ref()); + let hash = ::hash(l.as_ref()); if idx == leaf_index { leaf = Some(l); } @@ -234,28 +236,28 @@ impl<'a, H, T: AsRef<[u8]>> From<&'a T> for Leaf<'a, H> { /// /// The proof must not contain the root hash. pub fn verify_proof<'a, H, P, L>( - root: &'a H::Output, + root: &'a H::Out, proof: P, number_of_leaves: usize, leaf_index: usize, leaf: L, ) -> bool where - H: HashT, - H::Output: PartialEq + AsRef<[u8]> + PartialOrd, - P: IntoIterator, - L: Into>, + H: Hasher, + H::Out: PartialEq + AsRef<[u8]> + PartialOrd, + P: IntoIterator, + L: Into>, { if leaf_index >= number_of_leaves { return false } let leaf_hash = match leaf.into() { - Leaf::Value(content) => ::hash(content), + Leaf::Value(content) => ::hash(content), Leaf::Hash(hash) => hash, }; - let hash_len = ::LENGTH; + let hash_len = ::LENGTH; let mut combined = vec![0_u8; hash_len * 2]; let computed = proof.into_iter().fold(leaf_hash, |a, b| { if a < b { @@ -265,7 +267,7 @@ where combined[..hash_len].copy_from_slice(&b.as_ref()); combined[hash_len..].copy_from_slice(&a.as_ref()); } - let hash = ::hash(&combined); + let hash = ::hash(&combined); #[cfg(feature = "debug")] log::debug!( "[verify_proof]: (a, b) {:?}, {:?} => {:?} ({:?}) hash", @@ -287,20 +289,20 @@ where /// empty iterator) an `Err` with the inner nodes of upper layer is returned. fn merkelize_row( mut iter: I, - mut next: Vec, + mut next: Vec, visitor: &mut V, -) -> Result> +) -> Result> where - H: HashT, - H::Output: AsRef<[u8]> + PartialOrd, - V: Visitor, - I: Iterator, + H: Hasher, + H::Out: AsRef<[u8]> + PartialOrd, + V: Visitor, + I: Iterator, { #[cfg(feature = "debug")] log::debug!("[merkelize_row]"); next.clear(); - let hash_len = ::LENGTH; + let hash_len = ::LENGTH; let mut index = 0; let mut combined = vec![0_u8; hash_len * 2]; loop { @@ -326,7 +328,7 @@ where combined[hash_len..].copy_from_slice(a.as_ref()); } - next.push(::hash(&combined)); + next.push(::hash(&combined)); }, // Odd number of items. Promote the item to the upper layer. (Some(a), None) if !next.is_empty() => { @@ -347,24 +349,11 @@ where } } -sp_api::decl_runtime_apis! { - /// API useful for BEEFY light clients. - pub trait BeefyMmrApi - where - BeefyAuthoritySet: sp_api::Decode, - { - /// Return the currently active BEEFY authority set proof. - fn authority_set_proof() -> BeefyAuthoritySet; - - /// Return the next/queued BEEFY authority set proof. - fn next_authority_set_proof() -> BeefyNextAuthoritySet; - } -} - #[cfg(test)] mod tests { use super::*; - use crate::sp_core::H256; + use sp_core::H256; + use sp_runtime::traits::Keccak256; #[test] fn should_generate_empty_root() { From 4d02469dfe1c11466b45a9779dd36014ee549b27 Mon Sep 17 00:00:00 2001 From: Alexandru Vasile <60601340+lexnv@users.noreply.github.com> Date: Thu, 2 Feb 2023 19:14:40 +0200 Subject: [PATCH 082/162] Metadata V15: Derive `TypeInfo` for describing runtime types (#13272) * scale_info: Derive TypeInfo for types present in runtime API Signed-off-by: Alexandru Vasile * cargo: Update Cargo.lock Signed-off-by: Alexandru Vasile --------- Signed-off-by: Alexandru Vasile --- Cargo.lock | 3 +++ client/consensus/babe/Cargo.toml | 1 + client/consensus/babe/src/lib.rs | 2 +- frame/benchmarking/src/utils.rs | 13 +++++++------ frame/contracts/primitives/Cargo.toml | 2 ++ frame/contracts/primitives/src/lib.rs | 17 +++++++++-------- frame/support/src/traits/storage.rs | 4 +++- frame/support/src/traits/try_runtime.rs | 4 ++-- frame/transaction-payment/src/types.rs | 8 +++++--- primitives/consensus/babe/src/lib.rs | 6 +++--- primitives/core/src/lib.rs | 2 +- primitives/finality-grandpa/src/lib.rs | 2 +- primitives/inherents/Cargo.toml | 2 ++ primitives/inherents/src/lib.rs | 4 ++-- primitives/merkle-mountain-range/src/lib.rs | 4 ++-- primitives/runtime/src/generic/block.rs | 2 +- primitives/runtime/src/transaction_validity.rs | 4 ++-- test-utils/runtime/src/lib.rs | 2 +- 18 files changed, 48 insertions(+), 34 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a0e9e0e636cdb..dda127fdded77 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5615,6 +5615,7 @@ version = "7.0.0" dependencies = [ "bitflags", "parity-scale-codec", + "scale-info", "sp-runtime", "sp-std", "sp-weights", @@ -8151,6 +8152,7 @@ dependencies = [ "sc-network", "sc-network-test", "sc-telemetry", + "scale-info", "schnorrkel", "sp-api", "sp-application-crypto", @@ -9959,6 +9961,7 @@ dependencies = [ "futures", "impl-trait-for-tuples", "parity-scale-codec", + "scale-info", "sp-core", "sp-runtime", "sp-std", diff --git a/client/consensus/babe/Cargo.toml b/client/consensus/babe/Cargo.toml index f0ff0080fd610..8088bef9d7e1b 100644 --- a/client/consensus/babe/Cargo.toml +++ b/client/consensus/babe/Cargo.toml @@ -15,6 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] async-trait = "0.1.57" +scale-info = { version = "2.1.1", features = ["derive"] } codec = { package = "parity-scale-codec", version = "3.2.2", features = ["derive"] } futures = "0.3.21" log = "0.4.17" diff --git a/client/consensus/babe/src/lib.rs b/client/consensus/babe/src/lib.rs index 0eac4aca07479..99b29986ec8fc 100644 --- a/client/consensus/babe/src/lib.rs +++ b/client/consensus/babe/src/lib.rs @@ -152,7 +152,7 @@ mod tests; const LOG_TARGET: &str = "babe"; /// BABE epoch information -#[derive(Decode, Encode, PartialEq, Eq, Clone, Debug)] +#[derive(Decode, Encode, PartialEq, Eq, Clone, Debug, scale_info::TypeInfo)] pub struct Epoch { /// The epoch index. pub epoch_index: u64, diff --git a/frame/benchmarking/src/utils.rs b/frame/benchmarking/src/utils.rs index 6ad9ac7bb0bd6..74e44fbf91103 100644 --- a/frame/benchmarking/src/utils.rs +++ b/frame/benchmarking/src/utils.rs @@ -22,6 +22,7 @@ use frame_support::{ pallet_prelude::*, traits::StorageInfo, }; +use scale_info::TypeInfo; #[cfg(feature = "std")] use serde::{Deserialize, Serialize}; use sp_io::hashing::blake2_256; @@ -31,7 +32,7 @@ use sp_storage::TrackedStorageKey; /// An alphabet of possible parameters to use for benchmarking. #[cfg_attr(feature = "std", derive(Serialize, Deserialize))] -#[derive(Encode, Decode, Clone, Copy, PartialEq, Debug)] +#[derive(Encode, Decode, Clone, Copy, PartialEq, Debug, TypeInfo)] #[allow(missing_docs)] #[allow(non_camel_case_types)] pub enum BenchmarkParameter { @@ -72,7 +73,7 @@ impl std::fmt::Display for BenchmarkParameter { /// The results of a single of benchmark. #[cfg_attr(feature = "std", derive(Serialize, Deserialize))] -#[derive(Encode, Decode, Clone, PartialEq, Debug)] +#[derive(Encode, Decode, Clone, PartialEq, Debug, TypeInfo)] pub struct BenchmarkBatch { /// The pallet containing this benchmark. #[cfg_attr(feature = "std", serde(with = "serde_as_str"))] @@ -111,7 +112,7 @@ pub struct BenchmarkBatchSplitResults { /// Contains duration of the function call in nanoseconds along with the benchmark parameters /// used for that benchmark result. #[cfg_attr(feature = "std", derive(Serialize, Deserialize))] -#[derive(Encode, Decode, Default, Clone, PartialEq, Debug)] +#[derive(Encode, Decode, Default, Clone, PartialEq, Debug, TypeInfo)] pub struct BenchmarkResult { pub components: Vec<(BenchmarkParameter, u32)>, pub extrinsic_time: u128, @@ -199,7 +200,7 @@ impl From for BenchmarkError { } /// Configuration used to setup and run runtime benchmarks. -#[derive(Encode, Decode, Default, Clone, PartialEq, Debug)] +#[derive(Encode, Decode, Default, Clone, PartialEq, Debug, TypeInfo)] pub struct BenchmarkConfig { /// The encoded name of the pallet to benchmark. pub pallet: Vec, @@ -216,14 +217,14 @@ pub struct BenchmarkConfig { /// A list of benchmarks available for a particular pallet and instance. /// /// All `Vec` must be valid utf8 strings. -#[derive(Encode, Decode, Default, Clone, PartialEq, Debug)] +#[derive(Encode, Decode, Default, Clone, PartialEq, Debug, TypeInfo)] pub struct BenchmarkList { pub pallet: Vec, pub instance: Vec, pub benchmarks: Vec, } -#[derive(Encode, Decode, Default, Clone, PartialEq, Debug)] +#[derive(Encode, Decode, Default, Clone, PartialEq, Debug, TypeInfo)] pub struct BenchmarkMetadata { pub name: Vec, pub components: Vec<(BenchmarkParameter, u32, u32)>, diff --git a/frame/contracts/primitives/Cargo.toml b/frame/contracts/primitives/Cargo.toml index aafcd912af657..2460edc5a7b2f 100644 --- a/frame/contracts/primitives/Cargo.toml +++ b/frame/contracts/primitives/Cargo.toml @@ -14,6 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] bitflags = "1.0" +scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = ["derive"] } # Substrate Dependencies (This crate should not rely on frame) @@ -27,4 +28,5 @@ std = [ "codec/std", "sp-runtime/std", "sp-std/std", + "scale-info/std", ] diff --git a/frame/contracts/primitives/src/lib.rs b/frame/contracts/primitives/src/lib.rs index 4faea9eb3ee75..1811ae09c0572 100644 --- a/frame/contracts/primitives/src/lib.rs +++ b/frame/contracts/primitives/src/lib.rs @@ -21,6 +21,7 @@ use bitflags::bitflags; use codec::{Decode, Encode}; +use scale_info::TypeInfo; use sp_runtime::{ traits::{Saturating, Zero}, DispatchError, RuntimeDebug, @@ -31,7 +32,7 @@ use sp_weights::Weight; /// Result type of a `bare_call` or `bare_instantiate` call. /// /// It contains the execution result together with some auxiliary information. -#[derive(Eq, PartialEq, Encode, Decode, RuntimeDebug)] +#[derive(Eq, PartialEq, Encode, Decode, RuntimeDebug, TypeInfo)] pub struct ContractResult { /// How much weight was consumed during execution. pub gas_consumed: Weight, @@ -86,7 +87,7 @@ pub type CodeUploadResult = pub type GetStorageResult = Result>, ContractAccessError>; /// The possible errors that can happen querying the storage of a contract. -#[derive(Eq, PartialEq, Encode, Decode, RuntimeDebug)] +#[derive(Eq, PartialEq, Encode, Decode, RuntimeDebug, TypeInfo)] pub enum ContractAccessError { /// The given address doesn't point to a contract. DoesntExist, @@ -96,7 +97,7 @@ pub enum ContractAccessError { bitflags! { /// Flags used by a contract to customize exit behaviour. - #[derive(Encode, Decode)] + #[derive(Encode, Decode, TypeInfo)] pub struct ReturnFlags: u32 { /// If this bit is set all changes made by the contract execution are rolled back. const REVERT = 0x0000_0001; @@ -104,7 +105,7 @@ bitflags! { } /// Output of a contract call or instantiation which ran to completion. -#[derive(PartialEq, Eq, Encode, Decode, RuntimeDebug)] +#[derive(PartialEq, Eq, Encode, Decode, RuntimeDebug, TypeInfo)] pub struct ExecReturnValue { /// Flags passed along by `seal_return`. Empty when `seal_return` was never called. pub flags: ReturnFlags, @@ -120,7 +121,7 @@ impl ExecReturnValue { } /// The result of a successful contract instantiation. -#[derive(PartialEq, Eq, Encode, Decode, RuntimeDebug)] +#[derive(PartialEq, Eq, Encode, Decode, RuntimeDebug, TypeInfo)] pub struct InstantiateReturnValue { /// The output of the called constructor. pub result: ExecReturnValue, @@ -129,7 +130,7 @@ pub struct InstantiateReturnValue { } /// The result of succesfully uploading a contract. -#[derive(PartialEq, Eq, Encode, Decode, RuntimeDebug)] +#[derive(PartialEq, Eq, Encode, Decode, RuntimeDebug, TypeInfo)] pub struct CodeUploadReturnValue { /// The key under which the new code is stored. pub code_hash: CodeHash, @@ -138,7 +139,7 @@ pub struct CodeUploadReturnValue { } /// Reference to an existing code hash or a new wasm module. -#[derive(Eq, PartialEq, Encode, Decode, RuntimeDebug)] +#[derive(Eq, PartialEq, Encode, Decode, RuntimeDebug, TypeInfo)] pub enum Code { /// A wasm module as raw bytes. Upload(Vec), @@ -153,7 +154,7 @@ impl>, Hash> From for Code { } /// The amount of balance that was either charged or refunded in order to pay for storage. -#[derive(Eq, PartialEq, Ord, PartialOrd, Encode, Decode, RuntimeDebug, Clone)] +#[derive(Eq, PartialEq, Ord, PartialOrd, Encode, Decode, RuntimeDebug, Clone, TypeInfo)] pub enum StorageDeposit { /// The transaction reduced storage consumption. /// diff --git a/frame/support/src/traits/storage.rs b/frame/support/src/traits/storage.rs index 24653d1899836..8285ab988d5b1 100644 --- a/frame/support/src/traits/storage.rs +++ b/frame/support/src/traits/storage.rs @@ -53,7 +53,9 @@ pub trait StorageInstance { } /// Metadata about storage from the runtime. -#[derive(codec::Encode, codec::Decode, crate::RuntimeDebug, Eq, PartialEq, Clone)] +#[derive( + codec::Encode, codec::Decode, crate::RuntimeDebug, Eq, PartialEq, Clone, scale_info::TypeInfo, +)] pub struct StorageInfo { /// Encoded string of pallet name. pub pallet_name: Vec, diff --git a/frame/support/src/traits/try_runtime.rs b/frame/support/src/traits/try_runtime.rs index 273af09a145e5..cb4902201f1e8 100644 --- a/frame/support/src/traits/try_runtime.rs +++ b/frame/support/src/traits/try_runtime.rs @@ -22,7 +22,7 @@ use sp_arithmetic::traits::AtLeast32BitUnsigned; use sp_std::prelude::*; /// Which state tests to execute. -#[derive(codec::Encode, codec::Decode, Clone)] +#[derive(codec::Encode, codec::Decode, Clone, scale_info::TypeInfo)] pub enum Select { /// None of them. None, @@ -82,7 +82,7 @@ impl sp_std::str::FromStr for Select { } /// Select which checks should be run when trying a runtime upgrade upgrade. -#[derive(codec::Encode, codec::Decode, Clone, Debug, Copy)] +#[derive(codec::Encode, codec::Decode, Clone, Debug, Copy, scale_info::TypeInfo)] pub enum UpgradeCheckSelect { /// Run no checks. None, diff --git a/frame/transaction-payment/src/types.rs b/frame/transaction-payment/src/types.rs index d1a480b64e116..d9677861f434e 100644 --- a/frame/transaction-payment/src/types.rs +++ b/frame/transaction-payment/src/types.rs @@ -21,13 +21,15 @@ use codec::{Decode, Encode}; #[cfg(feature = "std")] use serde::{Deserialize, Serialize}; +use scale_info::TypeInfo; + use sp_runtime::traits::{AtLeast32BitUnsigned, Zero}; use sp_std::prelude::*; use frame_support::dispatch::DispatchClass; /// The base fee and adjusted weight and length fees constitute the _inclusion fee_. -#[derive(Encode, Decode, Clone, Eq, PartialEq)] +#[derive(Encode, Decode, Clone, Eq, PartialEq, TypeInfo)] #[cfg_attr(feature = "std", derive(Debug, Serialize, Deserialize))] #[cfg_attr(feature = "std", serde(rename_all = "camelCase"))] pub struct InclusionFee { @@ -63,7 +65,7 @@ impl InclusionFee { /// - (Optional) `inclusion_fee`: Only the `Pays::Yes` transaction can have the inclusion fee. /// - `tip`: If included in the transaction, the tip will be added on top. Only signed /// transactions can have a tip. -#[derive(Encode, Decode, Clone, Eq, PartialEq)] +#[derive(Encode, Decode, Clone, Eq, PartialEq, TypeInfo)] #[cfg_attr(feature = "std", derive(Debug, Serialize, Deserialize))] #[cfg_attr(feature = "std", serde(rename_all = "camelCase"))] pub struct FeeDetails { @@ -91,7 +93,7 @@ impl FeeDetails { /// Information related to a dispatchable's class, weight, and fee that can be queried from the /// runtime. -#[derive(Eq, PartialEq, Encode, Decode, Default)] +#[derive(Eq, PartialEq, Encode, Decode, Default, TypeInfo)] #[cfg_attr(feature = "std", derive(Debug, Serialize, Deserialize))] #[cfg_attr(feature = "std", serde(rename_all = "camelCase"))] #[cfg_attr( diff --git a/primitives/consensus/babe/src/lib.rs b/primitives/consensus/babe/src/lib.rs index cb44afcb8d4e4..10d027bd9162d 100644 --- a/primitives/consensus/babe/src/lib.rs +++ b/primitives/consensus/babe/src/lib.rs @@ -184,7 +184,7 @@ impl From for BabeConfiguration { } /// Configuration data used by the BABE consensus engine. -#[derive(Clone, PartialEq, Eq, Encode, Decode, RuntimeDebug)] +#[derive(Clone, PartialEq, Eq, Encode, Decode, RuntimeDebug, TypeInfo)] pub struct BabeConfiguration { /// The slot duration in milliseconds for BABE. Currently, only /// the value provided by this type at genesis will be used. @@ -327,7 +327,7 @@ where /// the runtime API boundary this type is unknown and as such we keep this /// opaque representation, implementors of the runtime API will have to make /// sure that all usages of `OpaqueKeyOwnershipProof` refer to the same type. -#[derive(Decode, Encode, PartialEq)] +#[derive(Decode, Encode, PartialEq, TypeInfo)] pub struct OpaqueKeyOwnershipProof(Vec); impl OpaqueKeyOwnershipProof { /// Create a new `OpaqueKeyOwnershipProof` using the given encoded @@ -344,7 +344,7 @@ impl OpaqueKeyOwnershipProof { } /// BABE epoch information -#[derive(Decode, Encode, PartialEq, Eq, Clone, Debug)] +#[derive(Decode, Encode, PartialEq, Eq, Clone, Debug, TypeInfo)] pub struct Epoch { /// The epoch index. pub epoch_index: u64, diff --git a/primitives/core/src/lib.rs b/primitives/core/src/lib.rs index 30d0cc199b74d..80e14b84d3ff4 100644 --- a/primitives/core/src/lib.rs +++ b/primitives/core/src/lib.rs @@ -165,7 +165,7 @@ impl sp_std::str::FromStr for Bytes { } /// Stores the encoded `RuntimeMetadata` for the native side as opaque type. -#[derive(Encode, Decode, PartialEq)] +#[derive(Encode, Decode, PartialEq, TypeInfo)] pub struct OpaqueMetadata(Vec); impl OpaqueMetadata { diff --git a/primitives/finality-grandpa/src/lib.rs b/primitives/finality-grandpa/src/lib.rs index 7b3b55f49cee0..f5307ab06bde7 100644 --- a/primitives/finality-grandpa/src/lib.rs +++ b/primitives/finality-grandpa/src/lib.rs @@ -529,7 +529,7 @@ impl<'a> Decode for VersionedAuthorityList<'a> { /// the runtime API boundary this type is unknown and as such we keep this /// opaque representation, implementors of the runtime API will have to make /// sure that all usages of `OpaqueKeyOwnershipProof` refer to the same type. -#[derive(Decode, Encode, PartialEq)] +#[derive(Decode, Encode, PartialEq, TypeInfo)] pub struct OpaqueKeyOwnershipProof(Vec); impl OpaqueKeyOwnershipProof { diff --git a/primitives/inherents/Cargo.toml b/primitives/inherents/Cargo.toml index c901a6e68a181..fd073db69a6af 100644 --- a/primitives/inherents/Cargo.toml +++ b/primitives/inherents/Cargo.toml @@ -16,6 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] async-trait = { version = "0.1.57", optional = true } codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = ["derive"] } +scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } impl-trait-for-tuples = "0.2.2" thiserror = { version = "1.0.30", optional = true } sp-core = { version = "7.0.0", default-features = false, path = "../core" } @@ -30,6 +31,7 @@ default = [ "std" ] std = [ "async-trait", "codec/std", + "scale-info/std", "sp-core/std", "sp-runtime/std", "sp-std/std", diff --git a/primitives/inherents/src/lib.rs b/primitives/inherents/src/lib.rs index 59db5ef3e8802..f05c9a9ad552b 100644 --- a/primitives/inherents/src/lib.rs +++ b/primitives/inherents/src/lib.rs @@ -204,7 +204,7 @@ pub enum Error { pub type InherentIdentifier = [u8; 8]; /// Inherent data to include in a block. -#[derive(Clone, Default, Encode, Decode)] +#[derive(Clone, Default, Encode, Decode, scale_info::TypeInfo)] pub struct InherentData { /// All inherent data encoded with parity-scale-codec and an identifier. data: BTreeMap>, @@ -276,7 +276,7 @@ impl InherentData { /// /// When a fatal error occurs, all other errors are removed and the implementation needs to /// abort checking inherents. -#[derive(Encode, Decode, Clone)] +#[derive(Encode, Decode, Clone, scale_info::TypeInfo)] pub struct CheckInherentsResult { /// Did the check succeed? okay: bool, diff --git a/primitives/merkle-mountain-range/src/lib.rs b/primitives/merkle-mountain-range/src/lib.rs index 606906185077c..df0a7f75a73fb 100644 --- a/primitives/merkle-mountain-range/src/lib.rs +++ b/primitives/merkle-mountain-range/src/lib.rs @@ -142,7 +142,7 @@ impl FullLeaf for OpaqueLeaf { /// /// It is different from [`OpaqueLeaf`], because it does implement `Codec` /// and the encoding has to match raw `Vec` encoding. -#[derive(codec::Encode, codec::Decode, RuntimeDebug, PartialEq, Eq)] +#[derive(codec::Encode, codec::Decode, RuntimeDebug, PartialEq, Eq, TypeInfo)] pub struct EncodableOpaqueLeaf(pub Vec); impl EncodableOpaqueLeaf { @@ -361,7 +361,7 @@ pub struct Proof { /// Merkle Mountain Range operation error. #[cfg_attr(feature = "std", derive(thiserror::Error))] -#[derive(RuntimeDebug, codec::Encode, codec::Decode, PartialEq, Eq)] +#[derive(RuntimeDebug, codec::Encode, codec::Decode, PartialEq, Eq, TypeInfo)] pub enum Error { /// Error during translation of a block number into a leaf index. #[cfg_attr(feature = "std", error("Error performing numeric op"))] diff --git a/primitives/runtime/src/generic/block.rs b/primitives/runtime/src/generic/block.rs index 3b01633635c24..b03fab2904db5 100644 --- a/primitives/runtime/src/generic/block.rs +++ b/primitives/runtime/src/generic/block.rs @@ -78,7 +78,7 @@ impl fmt::Display for BlockId { } /// Abstraction over a substrate block. -#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug)] +#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, scale_info::TypeInfo)] #[cfg_attr(feature = "std", derive(Serialize, Deserialize))] #[cfg_attr(feature = "std", serde(rename_all = "camelCase"))] #[cfg_attr(feature = "std", serde(deny_unknown_fields))] diff --git a/primitives/runtime/src/transaction_validity.rs b/primitives/runtime/src/transaction_validity.rs index 3b89644c28647..f47459f3eed16 100644 --- a/primitives/runtime/src/transaction_validity.rs +++ b/primitives/runtime/src/transaction_validity.rs @@ -226,7 +226,7 @@ impl From for TransactionValidity { /// Depending on the source we might apply different validation schemes. /// For instance we can disallow specific kinds of transactions if they were not produced /// by our local node (for instance off-chain workers). -#[derive(Copy, Clone, PartialEq, Eq, Encode, Decode, RuntimeDebug)] +#[derive(Copy, Clone, PartialEq, Eq, Encode, Decode, RuntimeDebug, TypeInfo)] pub enum TransactionSource { /// Transaction is already included in block. /// @@ -251,7 +251,7 @@ pub enum TransactionSource { } /// Information concerning a valid transaction. -#[derive(Clone, PartialEq, Eq, Encode, Decode, RuntimeDebug)] +#[derive(Clone, PartialEq, Eq, Encode, Decode, RuntimeDebug, TypeInfo)] pub struct ValidTransaction { /// Priority of the transaction. /// diff --git a/test-utils/runtime/src/lib.rs b/test-utils/runtime/src/lib.rs index 5fc7c5e8558ea..1c2d6ec8a0c81 100644 --- a/test-utils/runtime/src/lib.rs +++ b/test-utils/runtime/src/lib.rs @@ -297,7 +297,7 @@ pub fn run_tests(mut input: &[u8]) -> Vec { } /// A type that can not be decoded. -#[derive(PartialEq)] +#[derive(PartialEq, TypeInfo)] pub struct DecodeFails { _phantom: PhantomData, } From 369365ec3ad827ee2a89f1fa6f242fc8dbb13a10 Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Thu, 2 Feb 2023 18:47:50 +0100 Subject: [PATCH 083/162] benchmarks: EnsureRankedMember must add ranked members (#13297) Signed-off-by: Oliver Tale-Yazdi --- frame/ranked-collective/src/lib.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/frame/ranked-collective/src/lib.rs b/frame/ranked-collective/src/lib.rs index 84be1243c8afc..a65d184d6bf06 100644 --- a/frame/ranked-collective/src/lib.rs +++ b/frame/ranked-collective/src/lib.rs @@ -256,8 +256,7 @@ impl, I: 'static, const MIN_RANK: u16> EnsureOrigin Result { - let who = IndexToId::::get(MIN_RANK, 0).ok_or(())?; - Ok(frame_system::RawOrigin::Signed(who).into()) + EnsureRankedMember::::try_successful_origin() } } @@ -279,8 +278,7 @@ impl, I: 'static, const MIN_RANK: u16> EnsureOrigin Result { - let who = IndexToId::::get(MIN_RANK, 0).ok_or(())?; - Ok(frame_system::RawOrigin::Signed(who).into()) + EnsureRankedMember::::try_successful_origin() } } @@ -302,7 +300,9 @@ impl, I: 'static, const MIN_RANK: u16> EnsureOrigin Result { - let who = IndexToId::::get(MIN_RANK, 0).ok_or(())?; + let who = frame_benchmarking::account::("successful_origin", 0, 0); + crate::Pallet::::do_add_member_to_rank(who.clone(), MIN_RANK) + .expect("Could not add members for benchmarks"); Ok(frame_system::RawOrigin::Signed(who).into()) } } From c6c490d66915e631dcf60dc7d63052c9b46c4713 Mon Sep 17 00:00:00 2001 From: Marcin S Date: Thu, 2 Feb 2023 19:41:40 +0100 Subject: [PATCH 084/162] Minor: Update output validity tests (#13190) * Minor: Update output validity tests Quick follow-up to https://github.com/paritytech/substrate/pull/13183. Mainly, I wanted to double check that the `test_return_max_memory_offset` test doesn't pass just because the output length is 0. I also: - Organized these tests into a module. - Added a comment explaining why we don't use the `wasm_export_functions` macro. * Update test based on review comment --- client/executor/runtime-test/src/lib.rs | 67 ++++++++++++-------- client/executor/src/integration_tests/mod.rs | 2 +- 2 files changed, 42 insertions(+), 27 deletions(-) diff --git a/client/executor/runtime-test/src/lib.rs b/client/executor/runtime-test/src/lib.rs index 0aa30e4bc9675..23584006a72c0 100644 --- a/client/executor/runtime-test/src/lib.rs +++ b/client/executor/runtime-test/src/lib.rs @@ -29,8 +29,6 @@ use sp_runtime::{ print, traits::{BlakeTwo256, Hash}, }; -#[cfg(not(feature = "std"))] -use sp_runtime_interface::pack_ptr_and_len; extern "C" { #[allow(dead_code)] @@ -344,31 +342,48 @@ sp_core::wasm_export_functions! { } } -// Returns a huge len. It should result in an error, and not an allocation. -#[no_mangle] -#[cfg(not(feature = "std"))] -pub extern "C" fn test_return_huge_len(_params: *const u8, _len: usize) -> u64 { - pack_ptr_and_len(0, u32::MAX) -} +// Tests that check output validity. We explicitly return the ptr and len, so we avoid using the +// `wasm_export_functions` macro. +mod output_validity { + #[cfg(not(feature = "std"))] + use super::WASM_PAGE_SIZE; -// Returns an offset right at the edge of the wasm memory boundary. With length 0, it should -// succeed. -#[no_mangle] -#[cfg(not(feature = "std"))] -pub extern "C" fn test_return_max_memory_offset(_params: *const u8, _len: usize) -> u64 { - pack_ptr_and_len((core::arch::wasm32::memory_size(0) * WASM_PAGE_SIZE) as u32, 0) -} + #[cfg(not(feature = "std"))] + use sp_runtime_interface::pack_ptr_and_len; -// Returns an offset right at the edge of the wasm memory boundary. With length 1, it should fail. -#[no_mangle] -#[cfg(not(feature = "std"))] -pub extern "C" fn test_return_max_memory_offset_plus_one(_params: *const u8, _len: usize) -> u64 { - pack_ptr_and_len((core::arch::wasm32::memory_size(0) * WASM_PAGE_SIZE) as u32, 1) -} + // Returns a huge len. It should result in an error, and not an allocation. + #[no_mangle] + #[cfg(not(feature = "std"))] + pub extern "C" fn test_return_huge_len(_params: *const u8, _len: usize) -> u64 { + pack_ptr_and_len(0, u32::MAX) + } -// Returns an output that overflows the u32 range. It should result in an error. -#[no_mangle] -#[cfg(not(feature = "std"))] -pub extern "C" fn test_return_overflow(_params: *const u8, _len: usize) -> u64 { - pack_ptr_and_len(u32::MAX, 1) + // Returns an offset right before the edge of the wasm memory boundary. It should succeed. + #[no_mangle] + #[cfg(not(feature = "std"))] + pub extern "C" fn test_return_max_memory_offset(_params: *const u8, _len: usize) -> u64 { + let output_ptr = (core::arch::wasm32::memory_size(0) * WASM_PAGE_SIZE) as u32 - 1; + let ptr = output_ptr as *mut u8; + unsafe { + ptr.write(u8::MAX); + } + pack_ptr_and_len(output_ptr, 1) + } + + // Returns an offset right after the edge of the wasm memory boundary. It should fail. + #[no_mangle] + #[cfg(not(feature = "std"))] + pub extern "C" fn test_return_max_memory_offset_plus_one( + _params: *const u8, + _len: usize, + ) -> u64 { + pack_ptr_and_len((core::arch::wasm32::memory_size(0) * WASM_PAGE_SIZE) as u32, 1) + } + + // Returns an output that overflows the u32 range. It should result in an error. + #[no_mangle] + #[cfg(not(feature = "std"))] + pub extern "C" fn test_return_overflow(_params: *const u8, _len: usize) -> u64 { + pack_ptr_and_len(u32::MAX, 1) + } } diff --git a/client/executor/src/integration_tests/mod.rs b/client/executor/src/integration_tests/mod.rs index 22e651abe98e2..bb2930803841b 100644 --- a/client/executor/src/integration_tests/mod.rs +++ b/client/executor/src/integration_tests/mod.rs @@ -811,7 +811,7 @@ fn return_max_memory_offset(wasm_method: WasmExecutionMethod) { assert_eq!( call_in_wasm("test_return_max_memory_offset", &[], wasm_method, &mut ext).unwrap(), - ().encode() + (u8::MAX).encode() ); } From 6453a4a2924c369845bceb5b9358b4c09300c610 Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Fri, 3 Feb 2023 12:16:16 +0200 Subject: [PATCH 085/162] BEEFY: define on-chain beefy-genesis and use it to coordinate voter initialization (#13215) * beefy: add support to configure BEEFY genesis * client/beefy: more flexible test runtime api * client/beefy: add tests for custom BEEFY genesis * client/beefy: ignore old state that didn't account for pallet genesis * client/beefy: fix clippy * frame/beefy: default BEEFY-genesis is block One::one() * frame/beefy: add extra doc comments --------- Co-authored-by: parity-processbot <> --- client/beefy/src/aux_schema.rs | 5 +- client/beefy/src/lib.rs | 34 ++-- client/beefy/src/tests.rs | 273 +++++++++++++++++++++------------ client/beefy/src/worker.rs | 6 +- frame/beefy/src/lib.rs | 21 ++- primitives/beefy/src/lib.rs | 5 +- test-utils/runtime/src/lib.rs | 4 + 7 files changed, 234 insertions(+), 114 deletions(-) diff --git a/client/beefy/src/aux_schema.rs b/client/beefy/src/aux_schema.rs index fafa9948c5444..217ea4769d8b9 100644 --- a/client/beefy/src/aux_schema.rs +++ b/client/beefy/src/aux_schema.rs @@ -28,7 +28,7 @@ use sp_runtime::traits::Block as BlockT; const VERSION_KEY: &[u8] = b"beefy_auxschema_version"; const WORKER_STATE: &[u8] = b"beefy_voter_state"; -const CURRENT_VERSION: u32 = 1; +const CURRENT_VERSION: u32 = 2; pub(crate) fn write_current_version(backend: &B) -> ClientResult<()> { info!(target: LOG_TARGET, "🥩 write aux schema version {:?}", CURRENT_VERSION); @@ -63,7 +63,8 @@ where match version { None => (), - Some(1) => return load_decode::<_, PersistedState>(backend, WORKER_STATE), + Some(1) => (), // version 1 is totally obsolete and should be simply ignored + Some(2) => return load_decode::<_, PersistedState>(backend, WORKER_STATE), other => return Err(ClientError::Backend(format!("Unsupported BEEFY DB version: {:?}", other))), } diff --git a/client/beefy/src/lib.rs b/client/beefy/src/lib.rs index 185f3b1ad502e..d7de7295a4a11 100644 --- a/client/beefy/src/lib.rs +++ b/client/beefy/src/lib.rs @@ -53,7 +53,7 @@ use sp_keystore::SyncCryptoStorePtr; use sp_mmr_primitives::MmrApi; use sp_runtime::{ generic::BlockId, - traits::{Block, One, Zero}, + traits::{Block, Zero}, }; use std::{collections::VecDeque, marker::PhantomData, sync::Arc}; @@ -346,6 +346,12 @@ where R: ProvideRuntimeApi, R::Api: BeefyApi, { + let beefy_genesis = runtime + .runtime_api() + .beefy_genesis(&BlockId::hash(best_grandpa.hash())) + .ok() + .flatten() + .ok_or_else(|| ClientError::Backend("BEEFY pallet expected to be active.".into()))?; // Walk back the imported blocks and initialize voter either, at the last block with // a BEEFY justification, or at pallet genesis block; voter will resume from there. let blockchain = backend.blockchain(); @@ -378,20 +384,19 @@ where break state } - if *header.number() == One::one() { - // We've reached chain genesis, initialize voter here. - let genesis_num = *header.number(); + if *header.number() == beefy_genesis { + // We've reached BEEFY genesis, initialize voter here. let genesis_set = expect_validator_set(runtime, BlockId::hash(header.hash())) .and_then(genesis_set_sanity_check)?; info!( target: LOG_TARGET, "🥩 Loading BEEFY voter state from genesis on what appears to be first startup. \ Starting voting rounds at block {:?}, genesis validator set {:?}.", - genesis_num, + beefy_genesis, genesis_set, ); - sessions.push_front(Rounds::new(genesis_num, genesis_set)); + sessions.push_front(Rounds::new(beefy_genesis, genesis_set)); break PersistedState::checked_new(best_grandpa, Zero::zero(), sessions, min_block_delta) .ok_or_else(|| ClientError::Backend("Invalid BEEFY chain".into()))? } @@ -448,13 +453,16 @@ where None => break }; let at = BlockId::hash(notif.header.hash()); - if let Some(active) = runtime.runtime_api().validator_set(&at).ok().flatten() { - // Beefy pallet available, return best grandpa at the time. - info!( - target: LOG_TARGET, "🥩 BEEFY pallet available: block {:?} validator set {:?}", - notif.header.number(), active - ); - return Ok(notif.header) + if let Some(start) = runtime.runtime_api().beefy_genesis(&at).ok().flatten() { + if *notif.header.number() >= start { + // Beefy pallet available, return header for best grandpa at the time. + info!( + target: LOG_TARGET, + "🥩 BEEFY pallet available: block {:?} beefy genesis {:?}", + notif.header.number(), start + ); + return Ok(notif.header) + } } }, _ = gossip_engine => { diff --git a/client/beefy/src/tests.rs b/client/beefy/src/tests.rs index 2642035ba5dd5..008137d9a9965 100644 --- a/client/beefy/src/tests.rs +++ b/client/beefy/src/tests.rs @@ -77,8 +77,8 @@ const BAD_MMR_ROOT: MmrRootHash = MmrRootHash::repeat_byte(0x42); type BeefyBlockImport = crate::BeefyBlockImport< Block, substrate_test_runtime_client::Backend, - two_validators::TestApi, - BlockImportAdapter>, + TestApi, + BlockImportAdapter>, >; pub(crate) type BeefyValidatorSet = ValidatorSet; @@ -198,12 +198,12 @@ impl TestNetFactory for BeefyTestNet { Option>, Self::PeerData, ) { + let keys = &[BeefyKeyring::Alice, BeefyKeyring::Bob]; + let validator_set = ValidatorSet::new(make_beefy_ids(keys), 0).unwrap(); + let api = Arc::new(TestApi::with_validator_set(&validator_set)); let inner = BlockImportAdapter::new(client.clone()); - let (block_import, voter_links, rpc_links) = beefy_block_import_and_links( - inner, - client.as_backend(), - Arc::new(two_validators::TestApi {}), - ); + let (block_import, voter_links, rpc_links) = + beefy_block_import_and_links(inner, client.as_backend(), api); let peer_data = PeerData { beefy_rpc_links: Mutex::new(Some(rpc_links)), beefy_voter_links: Mutex::new(Some(voter_links)), @@ -230,79 +230,79 @@ impl TestNetFactory for BeefyTestNet { } } -macro_rules! create_test_api { - ( $api_name:ident, mmr_root: $mmr_root:expr, $($inits:expr),+ ) => { - pub(crate) mod $api_name { - use super::*; - - #[derive(Clone, Default)] - pub(crate) struct TestApi {} +#[derive(Clone)] +pub(crate) struct TestApi { + pub beefy_genesis: u64, + pub validator_set: BeefyValidatorSet, + pub mmr_root_hash: MmrRootHash, +} - // compiler gets confused and warns us about unused inner - #[allow(dead_code)] - pub(crate) struct RuntimeApi { - inner: TestApi, - } +impl TestApi { + pub fn new( + beefy_genesis: u64, + validator_set: &BeefyValidatorSet, + mmr_root_hash: MmrRootHash, + ) -> Self { + TestApi { beefy_genesis, validator_set: validator_set.clone(), mmr_root_hash } + } - impl ProvideRuntimeApi for TestApi { - type Api = RuntimeApi; - fn runtime_api<'a>(&'a self) -> ApiRef<'a, Self::Api> { - RuntimeApi { inner: self.clone() }.into() - } - } - sp_api::mock_impl_runtime_apis! { - impl BeefyApi for RuntimeApi { - fn validator_set() -> Option { - BeefyValidatorSet::new(make_beefy_ids(&[$($inits),+]), 0) - } - } - - impl MmrApi> for RuntimeApi { - fn mmr_root() -> Result { - Ok($mmr_root) - } - - fn generate_proof( - _block_numbers: Vec, - _best_known_block_number: Option - ) -> Result<(Vec, Proof), MmrError> { - unimplemented!() - } - - fn verify_proof(_leaves: Vec, _proof: Proof) -> Result<(), MmrError> { - unimplemented!() - } - - fn verify_proof_stateless( - _root: MmrRootHash, - _leaves: Vec, - _proof: Proof - ) -> Result<(), MmrError> { - unimplemented!() - } - } - } + pub fn with_validator_set(validator_set: &BeefyValidatorSet) -> Self { + TestApi { + beefy_genesis: 1, + validator_set: validator_set.clone(), + mmr_root_hash: GOOD_MMR_ROOT, } - }; + } +} + +// compiler gets confused and warns us about unused inner +#[allow(dead_code)] +pub(crate) struct RuntimeApi { + inner: TestApi, +} + +impl ProvideRuntimeApi for TestApi { + type Api = RuntimeApi; + fn runtime_api(&self) -> ApiRef { + RuntimeApi { inner: self.clone() }.into() + } } +sp_api::mock_impl_runtime_apis! { + impl BeefyApi for RuntimeApi { + fn beefy_genesis() -> Option> { + Some(self.inner.beefy_genesis) + } + + fn validator_set() -> Option { + Some(self.inner.validator_set.clone()) + } + } + + impl MmrApi> for RuntimeApi { + fn mmr_root() -> Result { + Ok(self.inner.mmr_root_hash) + } + + fn generate_proof( + _block_numbers: Vec, + _best_known_block_number: Option + ) -> Result<(Vec, Proof), MmrError> { + unimplemented!() + } + + fn verify_proof(_leaves: Vec, _proof: Proof) -> Result<(), MmrError> { + unimplemented!() + } -create_test_api!(two_validators, mmr_root: GOOD_MMR_ROOT, BeefyKeyring::Alice, BeefyKeyring::Bob); -create_test_api!( - four_validators, - mmr_root: GOOD_MMR_ROOT, - BeefyKeyring::Alice, - BeefyKeyring::Bob, - BeefyKeyring::Charlie, - BeefyKeyring::Dave -); -create_test_api!( - bad_four_validators, - mmr_root: BAD_MMR_ROOT, - BeefyKeyring::Alice, - BeefyKeyring::Bob, - BeefyKeyring::Charlie, - BeefyKeyring::Dave -); + fn verify_proof_stateless( + _root: MmrRootHash, + _leaves: Vec, + _proof: Proof + ) -> Result<(), MmrError> { + unimplemented!() + } + } +} fn add_mmr_digest(header: &mut Header, mmr_hash: MmrRootHash) { header.digest_mut().push(DigestItem::Consensus( @@ -332,9 +332,9 @@ pub(crate) fn create_beefy_keystore(authority: BeefyKeyring) -> SyncCryptoStoreP fn voter_init_setup( net: &mut BeefyTestNet, finality: &mut futures::stream::Fuse>, + api: &TestApi, ) -> sp_blockchain::Result> { let backend = net.peer(0).client().as_backend(); - let api = Arc::new(crate::tests::two_validators::TestApi {}); let known_peers = Arc::new(Mutex::new(KnownPeers::new())); let gossip_validator = Arc::new(crate::communication::gossip::GossipValidator::new(known_peers)); @@ -345,9 +345,9 @@ fn voter_init_setup( None, ); let best_grandpa = - futures::executor::block_on(wait_for_runtime_pallet(&*api, &mut gossip_engine, finality)) + futures::executor::block_on(wait_for_runtime_pallet(api, &mut gossip_engine, finality)) .unwrap(); - load_or_init_voter_state(&*backend, &*api, best_grandpa, 1) + load_or_init_voter_state(&*backend, api, best_grandpa, 1) } // Spawns beefy voters. Returns a future to spawn on the runtime. @@ -357,7 +357,7 @@ fn initialize_beefy( min_block_delta: u32, ) -> impl Future where - API: ProvideRuntimeApi + Default + Sync + Send, + API: ProvideRuntimeApi + Sync + Send, API::Api: BeefyApi + MmrApi>, { let tasks = FuturesUnordered::new(); @@ -544,7 +544,7 @@ async fn beefy_finalizing_blocks() { let mut net = BeefyTestNet::new(2); - let api = Arc::new(two_validators::TestApi {}); + let api = Arc::new(TestApi::with_validator_set(&validator_set)); let beefy_peers = peers.iter().enumerate().map(|(id, key)| (id, key, api.clone())).collect(); tokio::spawn(initialize_beefy(&mut net, beefy_peers, min_block_delta)); @@ -582,7 +582,7 @@ async fn lagging_validators() { let min_block_delta = 1; let mut net = BeefyTestNet::new(2); - let api = Arc::new(two_validators::TestApi {}); + let api = Arc::new(TestApi::with_validator_set(&validator_set)); let beefy_peers = peers.iter().enumerate().map(|(id, key)| (id, key, api.clone())).collect(); tokio::spawn(initialize_beefy(&mut net, beefy_peers, min_block_delta)); @@ -660,7 +660,7 @@ async fn correct_beefy_payload() { let mut net = BeefyTestNet::new(4); // Alice, Bob, Charlie will vote on good payloads - let good_api = Arc::new(four_validators::TestApi {}); + let good_api = Arc::new(TestApi::new(1, &validator_set, GOOD_MMR_ROOT)); let good_peers = [BeefyKeyring::Alice, BeefyKeyring::Bob, BeefyKeyring::Charlie] .iter() .enumerate() @@ -669,7 +669,7 @@ async fn correct_beefy_payload() { tokio::spawn(initialize_beefy(&mut net, good_peers, min_block_delta)); // Dave will vote on bad mmr roots - let bad_api = Arc::new(bad_four_validators::TestApi {}); + let bad_api = Arc::new(TestApi::new(1, &validator_set, BAD_MMR_ROOT)); let bad_peers = vec![(3, &BeefyKeyring::Dave, bad_api)]; tokio::spawn(initialize_beefy(&mut net, bad_peers, min_block_delta)); @@ -714,6 +714,8 @@ async fn beefy_importing_blocks() { sp_tracing::try_init_simple(); let mut net = BeefyTestNet::new(2); + let keys = &[BeefyKeyring::Alice, BeefyKeyring::Bob]; + let good_set = ValidatorSet::new(make_beefy_ids(keys), 0).unwrap(); let client = net.peer(0).client().clone(); let (mut block_import, _, peer_data) = net.make_block_import(client.clone()); @@ -769,9 +771,7 @@ async fn beefy_importing_blocks() { // Import with valid justification. let parent_id = BlockId::Number(1); let block_num = 2; - let keys = &[BeefyKeyring::Alice, BeefyKeyring::Bob]; - let validator_set = ValidatorSet::new(make_beefy_ids(keys), 0).unwrap(); - let proof = crate::justification::tests::new_finality_proof(block_num, &validator_set, keys); + let proof = crate::justification::tests::new_finality_proof(block_num, &good_set, keys); let versioned_proof: VersionedFinalityProof, Signature> = proof.into(); let encoded = versioned_proof.encode(); let justif = Some(Justifications::from((BEEFY_ENGINE_ID, encoded))); @@ -814,8 +814,8 @@ async fn beefy_importing_blocks() { let parent_id = BlockId::Number(2); let block_num = 3; let keys = &[BeefyKeyring::Alice]; - let validator_set = ValidatorSet::new(make_beefy_ids(keys), 1).unwrap(); - let proof = crate::justification::tests::new_finality_proof(block_num, &validator_set, keys); + let bad_set = ValidatorSet::new(make_beefy_ids(keys), 1).unwrap(); + let proof = crate::justification::tests::new_finality_proof(block_num, &bad_set, keys); let versioned_proof: VersionedFinalityProof, Signature> = proof.into(); let encoded = versioned_proof.encode(); let justif = Some(Justifications::from((BEEFY_ENGINE_ID, encoded))); @@ -865,7 +865,7 @@ async fn voter_initialization() { let min_block_delta = 10; let mut net = BeefyTestNet::new(2); - let api = Arc::new(two_validators::TestApi {}); + let api = Arc::new(TestApi::with_validator_set(&validator_set)); let beefy_peers = peers.iter().enumerate().map(|(id, key)| (id, key, api.clone())).collect(); tokio::spawn(initialize_beefy(&mut net, beefy_peers, min_block_delta)); @@ -898,7 +898,7 @@ async fn on_demand_beefy_justification_sync() { let mut net = BeefyTestNet::new(4); // Alice, Bob, Charlie start first and make progress through voting. - let api = Arc::new(four_validators::TestApi {}); + let api = Arc::new(TestApi::with_validator_set(&validator_set)); let fast_peers = [BeefyKeyring::Alice, BeefyKeyring::Bob, BeefyKeyring::Charlie]; let voting_peers = fast_peers.iter().enumerate().map(|(id, key)| (id, key, api.clone())).collect(); @@ -977,8 +977,9 @@ async fn should_initialize_voter_at_genesis() { // finalize 13 without justifications net.peer(0).client().as_client().finalize_block(hashes[13], None).unwrap(); - // load persistent state - nothing in DB, should init at session boundary - let persisted_state = voter_init_setup(&mut net, &mut finality).unwrap(); + let api = TestApi::with_validator_set(&validator_set); + // load persistent state - nothing in DB, should init at genesis + let persisted_state = voter_init_setup(&mut net, &mut finality, &api).unwrap(); // Test initialization at session boundary. // verify voter initialized with two sessions starting at blocks 1 and 10 @@ -1006,6 +1007,54 @@ async fn should_initialize_voter_at_genesis() { assert_eq!(state, persisted_state); } +#[tokio::test] +async fn should_initialize_voter_at_custom_genesis() { + let keys = &[BeefyKeyring::Alice]; + let validator_set = ValidatorSet::new(make_beefy_ids(keys), 0).unwrap(); + let mut net = BeefyTestNet::new(1); + let backend = net.peer(0).client().as_backend(); + // custom pallet genesis is block number 7 + let custom_pallet_genesis = 7; + let api = TestApi::new(custom_pallet_genesis, &validator_set, GOOD_MMR_ROOT); + + // push 15 blocks with `AuthorityChange` digests every 10 blocks + let hashes = net.generate_blocks_and_sync(15, 10, &validator_set, false).await; + + let mut finality = net.peer(0).client().as_client().finality_notification_stream().fuse(); + + // finalize 3, 5, 8 without justifications + net.peer(0).client().as_client().finalize_block(hashes[3], None).unwrap(); + net.peer(0).client().as_client().finalize_block(hashes[5], None).unwrap(); + net.peer(0).client().as_client().finalize_block(hashes[8], None).unwrap(); + + // load persistent state - nothing in DB, should init at genesis + let persisted_state = voter_init_setup(&mut net, &mut finality, &api).unwrap(); + + // Test initialization at session boundary. + // verify voter initialized with single session starting at block `custom_pallet_genesis` (7) + let sessions = persisted_state.voting_oracle().sessions(); + assert_eq!(sessions.len(), 1); + assert_eq!(sessions[0].session_start(), custom_pallet_genesis); + let rounds = persisted_state.active_round().unwrap(); + assert_eq!(rounds.session_start(), custom_pallet_genesis); + assert_eq!(rounds.validator_set_id(), validator_set.id()); + + // verify next vote target is mandatory block 7 + assert_eq!(persisted_state.best_beefy_block(), 0); + assert_eq!(persisted_state.best_grandpa_block(), 8); + assert_eq!( + persisted_state + .voting_oracle() + .voting_target(persisted_state.best_beefy_block(), 13), + Some(custom_pallet_genesis) + ); + + // verify state also saved to db + assert!(verify_persisted_version(&*backend)); + let state = load_persistent(&*backend).unwrap().unwrap(); + assert_eq!(state, persisted_state); +} + #[tokio::test] async fn should_initialize_voter_when_last_final_is_session_boundary() { let keys = &[BeefyKeyring::Alice]; @@ -1038,8 +1087,9 @@ async fn should_initialize_voter_when_last_final_is_session_boundary() { // Test corner-case where session boundary == last beefy finalized, // expect rounds initialized at last beefy finalized 10. + let api = TestApi::with_validator_set(&validator_set); // load persistent state - nothing in DB, should init at session boundary - let persisted_state = voter_init_setup(&mut net, &mut finality).unwrap(); + let persisted_state = voter_init_setup(&mut net, &mut finality, &api).unwrap(); // verify voter initialized with single session starting at block 10 assert_eq!(persisted_state.voting_oracle().sessions().len(), 1); @@ -1095,8 +1145,9 @@ async fn should_initialize_voter_at_latest_finalized() { // Test initialization at last BEEFY finalized. + let api = TestApi::with_validator_set(&validator_set); // load persistent state - nothing in DB, should init at last BEEFY finalized - let persisted_state = voter_init_setup(&mut net, &mut finality).unwrap(); + let persisted_state = voter_init_setup(&mut net, &mut finality, &api).unwrap(); // verify voter initialized with single session starting at block 12 assert_eq!(persisted_state.voting_oracle().sessions().len(), 1); @@ -1119,3 +1170,37 @@ async fn should_initialize_voter_at_latest_finalized() { let state = load_persistent(&*backend).unwrap().unwrap(); assert_eq!(state, persisted_state); } + +#[tokio::test] +async fn beefy_finalizing_after_pallet_genesis() { + sp_tracing::try_init_simple(); + + let peers = [BeefyKeyring::Alice, BeefyKeyring::Bob]; + let validator_set = ValidatorSet::new(make_beefy_ids(&peers), 0).unwrap(); + let session_len = 10; + let min_block_delta = 1; + let pallet_genesis = 15; + + let mut net = BeefyTestNet::new(2); + + let api = Arc::new(TestApi::new(pallet_genesis, &validator_set, GOOD_MMR_ROOT)); + let beefy_peers = peers.iter().enumerate().map(|(id, key)| (id, key, api.clone())).collect(); + tokio::spawn(initialize_beefy(&mut net, beefy_peers, min_block_delta)); + + // push 42 blocks including `AuthorityChange` digests every 10 blocks. + let hashes = net.generate_blocks_and_sync(42, session_len, &validator_set, true).await; + + let net = Arc::new(Mutex::new(net)); + let peers = peers.into_iter().enumerate(); + + // Minimum BEEFY block delta is 1. + + // GRANDPA finalize blocks leading up to BEEFY pallet genesis -> BEEFY should finalize nothing. + finalize_block_and_wait_for_beefy(&net, peers.clone(), &hashes[1..14], &[]).await; + + // GRANDPA finalize block #16 -> BEEFY should finalize #15 (genesis mandatory) and #16. + finalize_block_and_wait_for_beefy(&net, peers.clone(), &[hashes[16]], &[15, 16]).await; + + // GRANDPA finalize #21 -> BEEFY finalize #20 (mandatory) and #21 + finalize_block_and_wait_for_beefy(&net, peers.clone(), &[hashes[21]], &[20, 21]).await; +} diff --git a/client/beefy/src/worker.rs b/client/beefy/src/worker.rs index 19ab52f520225..4d057bffc0cd9 100644 --- a/client/beefy/src/worker.rs +++ b/client/beefy/src/worker.rs @@ -994,8 +994,8 @@ pub(crate) mod tests { communication::notification::{BeefyBestBlockStream, BeefyVersionedFinalityProofStream}, keystore::tests::Keyring, tests::{ - create_beefy_keystore, get_beefy_streams, make_beefy_ids, two_validators::TestApi, - BeefyPeer, BeefyTestNet, + create_beefy_keystore, get_beefy_streams, make_beefy_ids, BeefyPeer, BeefyTestNet, + TestApi, }, BeefyRPCLinks, KnownPeers, }; @@ -1068,7 +1068,7 @@ pub(crate) mod tests { }; let backend = peer.client().as_backend(); - let api = Arc::new(TestApi {}); + let api = Arc::new(TestApi::with_validator_set(&genesis_validator_set)); let network = peer.network_service().clone(); let known_peers = Arc::new(Mutex::new(KnownPeers::new())); let gossip_validator = Arc::new(GossipValidator::new(known_peers.clone())); diff --git a/frame/beefy/src/lib.rs b/frame/beefy/src/lib.rs index 4cb23107e7843..86c8763a51dd3 100644 --- a/frame/beefy/src/lib.rs +++ b/frame/beefy/src/lib.rs @@ -49,6 +49,7 @@ pub use pallet::*; pub mod pallet { use super::*; use frame_support::pallet_prelude::*; + use frame_system::pallet_prelude::BlockNumberFor; #[pallet::config] pub trait Config: frame_system::Config { @@ -91,15 +92,32 @@ pub mod pallet { pub(super) type NextAuthorities = StorageValue<_, BoundedVec, ValueQuery>; + /// Block number where BEEFY consensus is enabled/started. + /// If changing this, make sure `Self::ValidatorSetId` is also reset to + /// `GENESIS_AUTHORITY_SET_ID` in the state of the new block number configured here. + #[pallet::storage] + #[pallet::getter(fn genesis_block)] + pub(super) type GenesisBlock = + StorageValue<_, Option>, ValueQuery>; + #[pallet::genesis_config] pub struct GenesisConfig { + /// Initial set of BEEFY authorities. pub authorities: Vec, + /// Block number where BEEFY consensus should start. + /// Should match the session where initial authorities are active. + /// *Note:* Ideally use block number where GRANDPA authorities are changed, + /// to guarantee the client gets a finality notification for exactly this block. + pub genesis_block: Option>, } #[cfg(feature = "std")] impl Default for GenesisConfig { fn default() -> Self { - Self { authorities: Vec::new() } + // BEEFY genesis will be first BEEFY-MANDATORY block, + // use block number one instead of chain-genesis. + let genesis_block = Some(sp_runtime::traits::One::one()); + Self { authorities: Vec::new(), genesis_block } } } @@ -110,6 +128,7 @@ pub mod pallet { // we panic here as runtime maintainers can simply reconfigure genesis and restart // the chain easily .expect("Authorities vec too big"); + >::put(&self.genesis_block); } } } diff --git a/primitives/beefy/src/lib.rs b/primitives/beefy/src/lib.rs index eb7b8db89b214..8c219040b3523 100644 --- a/primitives/beefy/src/lib.rs +++ b/primitives/beefy/src/lib.rs @@ -43,7 +43,7 @@ use codec::{Codec, Decode, Encode}; use scale_info::TypeInfo; use sp_application_crypto::RuntimeAppPublic; use sp_core::H256; -use sp_runtime::traits::Hash; +use sp_runtime::traits::{Hash, NumberFor}; use sp_std::prelude::*; /// Key type for BEEFY module. @@ -201,6 +201,9 @@ sp_api::decl_runtime_apis! { /// API necessary for BEEFY voters. pub trait BeefyApi { + /// Return the block number where BEEFY consensus is enabled/started + fn beefy_genesis() -> Option>; + /// Return the current active BEEFY validator set fn validator_set() -> Option>; } diff --git a/test-utils/runtime/src/lib.rs b/test-utils/runtime/src/lib.rs index 1c2d6ec8a0c81..c1a66eb6acb5c 100644 --- a/test-utils/runtime/src/lib.rs +++ b/test-utils/runtime/src/lib.rs @@ -973,6 +973,10 @@ cfg_if! { } impl beefy_primitives::BeefyApi for Runtime { + fn beefy_genesis() -> Option { + None + } + fn validator_set() -> Option> { None } From ff8a71f4450796dfbfa77aae39ccc297b969e700 Mon Sep 17 00:00:00 2001 From: Deepanshu Hooda <43631678+gitofdeepanshu@users.noreply.github.com> Date: Fri, 3 Feb 2023 18:50:12 +0530 Subject: [PATCH 086/162] feat: add event SkepticsChosen event in society (#13291) * feat: add event SkepticsChosen event in society * feat: add test for SkepticsChosen event --- frame/society/src/lib.rs | 10 +++++++--- frame/society/src/tests.rs | 7 +++++++ 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/frame/society/src/lib.rs b/frame/society/src/lib.rs index 0edf00ff80f6e..18152b9e29ec4 100644 --- a/frame/society/src/lib.rs +++ b/frame/society/src/lib.rs @@ -513,6 +513,8 @@ pub mod pallet { Unfounded { founder: T::AccountId }, /// Some funds were deposited into the society account. Deposit { value: BalanceOf }, + /// A group of members has been choosen as Skeptics + SkepticsChosen { skeptics: Vec }, } /// The first member. @@ -1610,12 +1612,14 @@ impl, I: 'static> Pallet { // Select sqrt(n) random members from the society and make them skeptics. let pick_member = - |_| pick_item(&mut rng, &members[..]).expect("exited if members empty; qed"); - for skeptic in (0..members.len().integer_sqrt()).map(pick_member) { + |_| pick_item(&mut rng, &members[..]).expect("exited if members empty; qed").clone(); + let skeptics = (0..members.len().integer_sqrt()).map(pick_member).collect::>(); + skeptics.iter().for_each(|skeptic| { for Bid { who: c, .. } in candidates.iter() { >::insert(c, skeptic, Vote::Skeptic); } - } + }); + Self::deposit_event(Event::::SkepticsChosen { skeptics }); } /// Attempt to slash the payout of some member. Return the total amount that was deducted. diff --git a/frame/society/src/tests.rs b/frame/society/src/tests.rs index 864735aa10cca..0b42f77035776 100644 --- a/frame/society/src/tests.rs +++ b/frame/society/src/tests.rs @@ -211,6 +211,9 @@ fn payout_works() { #[test] fn basic_new_member_skeptic_works() { EnvBuilder::new().execute(|| { + // NOTE: events are not deposited in the genesis event + System::set_block_number(1); + assert_eq!(Strikes::::get(10), 0); assert_ok!(Society::bid(RuntimeOrigin::signed(20), 0)); run_to_block(4); @@ -218,6 +221,10 @@ fn basic_new_member_skeptic_works() { run_to_block(8); assert_eq!(Society::members(), vec![10]); assert_eq!(Strikes::::get(10), 1); + + System::assert_last_event(mock::RuntimeEvent::Society(crate::Event::SkepticsChosen { + skeptics: vec![10], + })); }); } From ca58b7b4a16d3905837eb025501907c858b58894 Mon Sep 17 00:00:00 2001 From: Hussein Ait-Lahcen Date: Fri, 3 Feb 2023 15:21:24 +0100 Subject: [PATCH 087/162] feat(client): significantly increase wasm instance limits (#13298) Following https://github.com/paritytech/substrate/issues/11949, this PR will allow parachains with runtimes bigger than Kusama to use the pooling strategy. --- client/executor/wasmtime/src/runtime.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/executor/wasmtime/src/runtime.rs b/client/executor/wasmtime/src/runtime.rs index a45dfa59b954a..0c3fe228f08d5 100644 --- a/client/executor/wasmtime/src/runtime.rs +++ b/client/executor/wasmtime/src/runtime.rs @@ -376,8 +376,8 @@ fn common_config(semantics: &Semantics) -> std::result::Result Date: Fri, 3 Feb 2023 12:32:55 -0300 Subject: [PATCH 088/162] Remove in-tree bounded types and use bounded-collections crate (#13243) * Remove in-tree bounded types and use bounded-collections crate * Fixes * Bump bounded-collections version * cargo fmt * Bump bounded-collections * Only export non-bounded types at the top level * Fixes * Bump bounded-collections --- Cargo.lock | 17 +- primitives/core/Cargo.toml | 2 + .../core/src/bounded/bounded_btree_map.rs | 625 -------- .../core/src/bounded/bounded_btree_set.rs | 482 ------ primitives/core/src/bounded/bounded_vec.rs | 1305 ----------------- .../core/src/bounded/weak_bounded_vec.rs | 524 ------- primitives/core/src/lib.rs | 244 +-- 7 files changed, 24 insertions(+), 3175 deletions(-) delete mode 100644 primitives/core/src/bounded/bounded_btree_map.rs delete mode 100644 primitives/core/src/bounded/bounded_btree_set.rs delete mode 100644 primitives/core/src/bounded/bounded_vec.rs delete mode 100644 primitives/core/src/bounded/weak_bounded_vec.rs diff --git a/Cargo.lock b/Cargo.lock index dda127fdded77..492c5b15de119 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -699,6 +699,18 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8d696c370c750c948ada61c69a0ee2cbbb9c50b1019ddb86d9317157a99c2cae" +[[package]] +name = "bounded-collections" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de2aff4807e40f478132150d80b031f2461d88f061851afcab537d7600c24120" +dependencies = [ + "log", + "parity-scale-codec", + "scale-info", + "serde", +] + [[package]] name = "bs58" version = "0.4.0" @@ -6722,9 +6734,9 @@ dependencies = [ [[package]] name = "parity-scale-codec" -version = "3.2.2" +version = "3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7ab01d0f889e957861bc65888d5ccbe82c158d0270136ba46820d43837cdf72" +checksum = "c3840933452adf7b3b9145e27086a5a3376c619dca1a21b1e5a5af0d54979bed" dependencies = [ "arrayvec 0.7.2", "bitvec", @@ -9849,6 +9861,7 @@ dependencies = [ "base58", "bitflags", "blake2", + "bounded-collections", "criterion", "dyn-clonable", "ed25519-zebra", diff --git a/primitives/core/Cargo.toml b/primitives/core/Cargo.toml index 5fd838de3538d..7c045377571f6 100644 --- a/primitives/core/Cargo.toml +++ b/primitives/core/Cargo.toml @@ -20,6 +20,7 @@ codec = { package = "parity-scale-codec", version = "3.2.2", default-features = scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } log = { version = "0.4.17", default-features = false } serde = { version = "1.0.136", optional = true, features = ["derive"] } +bounded-collections = { version = "0.1.4", default-features = false } primitive-types = { version = "0.12.0", default-features = false, features = ["codec", "scale-info"] } impl-serde = { version = "0.4.0", optional = true } hash-db = { version = "0.15.2", default-features = false } @@ -80,6 +81,7 @@ std = [ "thiserror", "lazy_static", "parking_lot", + "bounded-collections/std", "primitive-types/std", "primitive-types/serde", "primitive-types/byteorder", diff --git a/primitives/core/src/bounded/bounded_btree_map.rs b/primitives/core/src/bounded/bounded_btree_map.rs deleted file mode 100644 index d2c148d6de9c5..0000000000000 --- a/primitives/core/src/bounded/bounded_btree_map.rs +++ /dev/null @@ -1,625 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 2017-2022 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. - -//! Traits, types and structs to support a bounded BTreeMap. - -use crate::{Get, TryCollect}; -use codec::{Decode, Encode, MaxEncodedLen}; -use sp_std::{borrow::Borrow, collections::btree_map::BTreeMap, marker::PhantomData, ops::Deref}; - -/// A bounded map based on a B-Tree. -/// -/// B-Trees represent a fundamental compromise between cache-efficiency and actually minimizing -/// the amount of work performed in a search. See [`BTreeMap`] for more details. -/// -/// Unlike a standard `BTreeMap`, there is an enforced upper limit to the number of items in the -/// map. All internal operations ensure this bound is respected. -#[derive(Encode, scale_info::TypeInfo)] -#[scale_info(skip_type_params(S))] -pub struct BoundedBTreeMap(BTreeMap, PhantomData); - -impl Decode for BoundedBTreeMap -where - K: Decode + Ord, - V: Decode, - S: Get, -{ - fn decode(input: &mut I) -> Result { - let inner = BTreeMap::::decode(input)?; - if inner.len() > S::get() as usize { - return Err("BoundedBTreeMap exceeds its limit".into()) - } - Ok(Self(inner, PhantomData)) - } - - fn skip(input: &mut I) -> Result<(), codec::Error> { - BTreeMap::::skip(input) - } -} - -impl BoundedBTreeMap -where - S: Get, -{ - /// Get the bound of the type in `usize`. - pub fn bound() -> usize { - S::get() as usize - } -} - -impl BoundedBTreeMap -where - K: Ord, - S: Get, -{ - /// Create `Self` from `t` without any checks. - fn unchecked_from(t: BTreeMap) -> Self { - Self(t, Default::default()) - } - - /// Exactly the same semantics as `BTreeMap::retain`. - /// - /// The is a safe `&mut self` borrow because `retain` can only ever decrease the length of the - /// inner map. - pub fn retain bool>(&mut self, f: F) { - self.0.retain(f) - } - - /// Create a new `BoundedBTreeMap`. - /// - /// Does not allocate. - pub fn new() -> Self { - BoundedBTreeMap(BTreeMap::new(), PhantomData) - } - - /// Consume self, and return the inner `BTreeMap`. - /// - /// This is useful when a mutating API of the inner type is desired, and closure-based mutation - /// such as provided by [`try_mutate`][Self::try_mutate] is inconvenient. - pub fn into_inner(self) -> BTreeMap { - debug_assert!(self.0.len() <= Self::bound()); - self.0 - } - - /// 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 - /// returned. - /// - /// This is essentially a *consuming* shorthand [`Self::into_inner`] -> `...` -> - /// [`Self::try_from`]. - pub fn try_mutate(mut self, mut mutate: impl FnMut(&mut BTreeMap)) -> Option { - mutate(&mut self.0); - (self.0.len() <= Self::bound()).then(move || self) - } - - /// Clears the map, removing all elements. - pub fn clear(&mut self) { - self.0.clear() - } - - /// Return a mutable reference to the value corresponding to the key. - /// - /// The key may be any borrowed form of the map's key type, but the ordering on the borrowed - /// form _must_ match the ordering on the key type. - pub fn get_mut(&mut self, key: &Q) -> Option<&mut V> - where - K: Borrow, - Q: Ord + ?Sized, - { - self.0.get_mut(key) - } - - /// Exactly the same semantics as [`BTreeMap::insert`], but returns an `Err` (and is a noop) if - /// the new length of the map exceeds `S`. - /// - /// In the `Err` case, returns the inserted pair so it can be further used without cloning. - pub fn try_insert(&mut self, key: K, value: V) -> Result, (K, V)> { - if self.len() < Self::bound() || self.0.contains_key(&key) { - Ok(self.0.insert(key, value)) - } else { - Err((key, value)) - } - } - - /// Remove a key from the map, returning the value at the key if the key was previously in the - /// map. - /// - /// The key may be any borrowed form of the map's key type, but the ordering on the borrowed - /// form _must_ match the ordering on the key type. - pub fn remove(&mut self, key: &Q) -> Option - where - K: Borrow, - Q: Ord + ?Sized, - { - self.0.remove(key) - } - - /// Remove a key from the map, returning the value at the key if the key was previously in the - /// map. - /// - /// The key may be any borrowed form of the map's key type, but the ordering on the borrowed - /// form _must_ match the ordering on the key type. - pub fn remove_entry(&mut self, key: &Q) -> Option<(K, V)> - where - K: Borrow, - Q: Ord + ?Sized, - { - self.0.remove_entry(key) - } - - /// Gets a mutable iterator over the entries of the map, sorted by key. - /// - /// See [`BTreeMap::iter_mut`] for more information. - pub fn iter_mut(&mut self) -> sp_std::collections::btree_map::IterMut { - self.0.iter_mut() - } - - /// Consume the map, applying `f` to each of it's values and returning a new map. - pub fn map(self, mut f: F) -> BoundedBTreeMap - where - F: FnMut((&K, V)) -> T, - { - BoundedBTreeMap::::unchecked_from( - self.0 - .into_iter() - .map(|(k, v)| { - let t = f((&k, v)); - (k, t) - }) - .collect(), - ) - } - - /// Consume the map, applying `f` to each of it's values as long as it returns successfully. If - /// an `Err(E)` is ever encountered, the mapping is short circuited and the error is returned; - /// otherwise, a new map is returned in the contained `Ok` value. - pub fn try_map(self, mut f: F) -> Result, E> - where - F: FnMut((&K, V)) -> Result, - { - Ok(BoundedBTreeMap::::unchecked_from( - self.0 - .into_iter() - .map(|(k, v)| (f((&k, v)).map(|t| (k, t)))) - .collect::, _>>()?, - )) - } -} - -impl Default for BoundedBTreeMap -where - K: Ord, - S: Get, -{ - fn default() -> Self { - Self::new() - } -} - -impl Clone for BoundedBTreeMap -where - BTreeMap: Clone, -{ - fn clone(&self) -> Self { - BoundedBTreeMap(self.0.clone(), PhantomData) - } -} - -impl sp_std::fmt::Debug for BoundedBTreeMap -where - BTreeMap: sp_std::fmt::Debug, - S: Get, -{ - fn fmt(&self, f: &mut sp_std::fmt::Formatter<'_>) -> sp_std::fmt::Result { - f.debug_tuple("BoundedBTreeMap").field(&self.0).field(&Self::bound()).finish() - } -} - -impl PartialEq> for BoundedBTreeMap -where - BTreeMap: PartialEq, - S1: Get, - S2: Get, -{ - fn eq(&self, other: &BoundedBTreeMap) -> bool { - S1::get() == S2::get() && self.0 == other.0 - } -} - -impl Eq for BoundedBTreeMap -where - BTreeMap: Eq, - S: Get, -{ -} - -impl PartialEq> for BoundedBTreeMap -where - BTreeMap: PartialEq, -{ - fn eq(&self, other: &BTreeMap) -> bool { - self.0 == *other - } -} - -impl PartialOrd for BoundedBTreeMap -where - BTreeMap: PartialOrd, - S: Get, -{ - fn partial_cmp(&self, other: &Self) -> Option { - self.0.partial_cmp(&other.0) - } -} - -impl Ord for BoundedBTreeMap -where - BTreeMap: Ord, - S: Get, -{ - fn cmp(&self, other: &Self) -> sp_std::cmp::Ordering { - self.0.cmp(&other.0) - } -} - -impl IntoIterator for BoundedBTreeMap { - type Item = (K, V); - type IntoIter = sp_std::collections::btree_map::IntoIter; - - fn into_iter(self) -> Self::IntoIter { - self.0.into_iter() - } -} - -impl<'a, K, V, S> IntoIterator for &'a BoundedBTreeMap { - type Item = (&'a K, &'a V); - type IntoIter = sp_std::collections::btree_map::Iter<'a, K, V>; - - fn into_iter(self) -> Self::IntoIter { - self.0.iter() - } -} - -impl<'a, K, V, S> IntoIterator for &'a mut BoundedBTreeMap { - type Item = (&'a K, &'a mut V); - type IntoIter = sp_std::collections::btree_map::IterMut<'a, K, V>; - - fn into_iter(self) -> Self::IntoIter { - self.0.iter_mut() - } -} - -impl MaxEncodedLen for BoundedBTreeMap -where - K: MaxEncodedLen, - V: MaxEncodedLen, - S: Get, -{ - fn max_encoded_len() -> usize { - Self::bound() - .saturating_mul(K::max_encoded_len().saturating_add(V::max_encoded_len())) - .saturating_add(codec::Compact(S::get()).encoded_size()) - } -} - -impl Deref for BoundedBTreeMap -where - K: Ord, -{ - type Target = BTreeMap; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl AsRef> for BoundedBTreeMap -where - K: Ord, -{ - fn as_ref(&self) -> &BTreeMap { - &self.0 - } -} - -impl From> for BTreeMap -where - K: Ord, -{ - fn from(map: BoundedBTreeMap) -> Self { - map.0 - } -} - -impl TryFrom> for BoundedBTreeMap -where - K: Ord, - S: Get, -{ - type Error = (); - - fn try_from(value: BTreeMap) -> Result { - (value.len() <= Self::bound()) - .then(move || BoundedBTreeMap(value, PhantomData)) - .ok_or(()) - } -} - -impl codec::DecodeLength for BoundedBTreeMap { - fn len(self_encoded: &[u8]) -> Result { - // `BoundedBTreeMap` is stored just a `BTreeMap`, which is stored as a - // `Compact` with its length followed by an iteration of its items. We can just use - // the underlying implementation. - as codec::DecodeLength>::len(self_encoded) - } -} - -impl codec::EncodeLike> for BoundedBTreeMap where - BTreeMap: Encode -{ -} - -impl TryCollect> for I -where - K: Ord, - I: ExactSizeIterator + Iterator, - Bound: Get, -{ - type Error = &'static str; - - fn try_collect(self) -> Result, Self::Error> { - if self.len() > Bound::get() as usize { - Err("iterator length too big") - } else { - Ok(BoundedBTreeMap::::unchecked_from(self.collect::>())) - } - } -} - -#[cfg(test)] -pub mod test { - use super::*; - use crate::ConstU32; - - fn map_from_keys(keys: &[K]) -> BTreeMap - where - K: Ord + Copy, - { - keys.iter().copied().zip(std::iter::repeat(())).collect() - } - - fn boundedmap_from_keys(keys: &[K]) -> BoundedBTreeMap - where - K: Ord + Copy, - S: Get, - { - map_from_keys(keys).try_into().unwrap() - } - - #[test] - fn try_insert_works() { - let mut bounded = boundedmap_from_keys::>(&[1, 2, 3]); - bounded.try_insert(0, ()).unwrap(); - assert_eq!(*bounded, map_from_keys(&[1, 0, 2, 3])); - - assert!(bounded.try_insert(9, ()).is_err()); - assert_eq!(*bounded, map_from_keys(&[1, 0, 2, 3])); - } - - #[test] - fn deref_coercion_works() { - let bounded = boundedmap_from_keys::>(&[1, 2, 3]); - // these methods come from deref-ed vec. - assert_eq!(bounded.len(), 3); - assert!(bounded.iter().next().is_some()); - assert!(!bounded.is_empty()); - } - - #[test] - fn try_mutate_works() { - let bounded = boundedmap_from_keys::>(&[1, 2, 3, 4, 5, 6]); - let bounded = bounded - .try_mutate(|v| { - v.insert(7, ()); - }) - .unwrap(); - assert_eq!(bounded.len(), 7); - assert!(bounded - .try_mutate(|v| { - v.insert(8, ()); - }) - .is_none()); - } - - #[test] - fn btree_map_eq_works() { - let bounded = boundedmap_from_keys::>(&[1, 2, 3, 4, 5, 6]); - assert_eq!(bounded, map_from_keys(&[1, 2, 3, 4, 5, 6])); - } - - #[test] - fn too_big_fail_to_decode() { - let v: Vec<(u32, u32)> = vec![(1, 1), (2, 2), (3, 3), (4, 4), (5, 5)]; - assert_eq!( - BoundedBTreeMap::>::decode(&mut &v.encode()[..]), - Err("BoundedBTreeMap exceeds its limit".into()), - ); - } - - #[test] - fn unequal_eq_impl_insert_works() { - // given a struct with a strange notion of equality - #[derive(Debug)] - struct Unequal(u32, bool); - - impl PartialEq for Unequal { - fn eq(&self, other: &Self) -> bool { - self.0 == other.0 - } - } - impl Eq for Unequal {} - - impl Ord for Unequal { - fn cmp(&self, other: &Self) -> std::cmp::Ordering { - self.0.cmp(&other.0) - } - } - - impl PartialOrd for Unequal { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } - } - - let mut map = BoundedBTreeMap::>::new(); - - // when the set is full - - for i in 0..4 { - map.try_insert(Unequal(i, false), i).unwrap(); - } - - // can't insert a new distinct member - map.try_insert(Unequal(5, false), 5).unwrap_err(); - - // but _can_ insert a distinct member which compares equal, though per the documentation, - // neither the set length nor the actual member are changed, but the value is - map.try_insert(Unequal(0, true), 6).unwrap(); - assert_eq!(map.len(), 4); - let (zero_key, zero_value) = map.get_key_value(&Unequal(0, true)).unwrap(); - assert_eq!(zero_key.0, 0); - assert_eq!(zero_key.1, false); - assert_eq!(*zero_value, 6); - } - - #[test] - fn eq_works() { - // of same type - let b1 = boundedmap_from_keys::>(&[1, 2]); - let b2 = boundedmap_from_keys::>(&[1, 2]); - assert_eq!(b1, b2); - - // of different type, but same value and bound. - crate::parameter_types! { - B1: u32 = 7; - B2: u32 = 7; - } - let b1 = boundedmap_from_keys::(&[1, 2]); - let b2 = boundedmap_from_keys::(&[1, 2]); - assert_eq!(b1, b2); - } - - #[test] - fn can_be_collected() { - let b1 = boundedmap_from_keys::>(&[1, 2, 3, 4]); - let b2: BoundedBTreeMap> = - b1.iter().map(|(k, v)| (k + 1, *v)).try_collect().unwrap(); - assert_eq!(b2.into_iter().map(|(k, _)| k).collect::>(), vec![2, 3, 4, 5]); - - // can also be collected into a collection of length 4. - let b2: BoundedBTreeMap> = - b1.iter().map(|(k, v)| (k + 1, *v)).try_collect().unwrap(); - assert_eq!(b2.into_iter().map(|(k, _)| k).collect::>(), vec![2, 3, 4, 5]); - - // can be mutated further into iterators that are `ExactSizedIterator`. - let b2: BoundedBTreeMap> = - b1.iter().map(|(k, v)| (k + 1, *v)).rev().skip(2).try_collect().unwrap(); - // note that the binary tree will re-sort this, so rev() is not really seen - assert_eq!(b2.into_iter().map(|(k, _)| k).collect::>(), vec![2, 3]); - - let b2: BoundedBTreeMap> = - b1.iter().map(|(k, v)| (k + 1, *v)).take(2).try_collect().unwrap(); - assert_eq!(b2.into_iter().map(|(k, _)| k).collect::>(), vec![2, 3]); - - // but these won't work - let b2: Result>, _> = - b1.iter().map(|(k, v)| (k + 1, *v)).try_collect(); - assert!(b2.is_err()); - - let b2: Result>, _> = - b1.iter().map(|(k, v)| (k + 1, *v)).skip(2).try_collect(); - assert!(b2.is_err()); - } - - #[test] - fn test_iter_mut() { - let mut b1: BoundedBTreeMap> = - [1, 2, 3, 4].into_iter().map(|k| (k, k)).try_collect().unwrap(); - - let b2: BoundedBTreeMap> = - [1, 2, 3, 4].into_iter().map(|k| (k, k * 2)).try_collect().unwrap(); - - b1.iter_mut().for_each(|(_, v)| *v *= 2); - - assert_eq!(b1, b2); - } - - #[test] - fn map_retains_size() { - let b1 = boundedmap_from_keys::>(&[1, 2]); - let b2 = b1.clone(); - - assert_eq!(b1.len(), b2.map(|(_, _)| 5_u32).len()); - } - - #[test] - fn map_maps_properly() { - let b1: BoundedBTreeMap> = - [1, 2, 3, 4].into_iter().map(|k| (k, k * 2)).try_collect().unwrap(); - let b2: BoundedBTreeMap> = - [1, 2, 3, 4].into_iter().map(|k| (k, k)).try_collect().unwrap(); - - assert_eq!(b1, b2.map(|(_, v)| v * 2)); - } - - #[test] - fn try_map_retains_size() { - let b1 = boundedmap_from_keys::>(&[1, 2]); - let b2 = b1.clone(); - - assert_eq!(b1.len(), b2.try_map::<_, (), _>(|(_, _)| Ok(5_u32)).unwrap().len()); - } - - #[test] - fn try_map_maps_properly() { - let b1: BoundedBTreeMap> = - [1, 2, 3, 4].into_iter().map(|k| (k, k * 2)).try_collect().unwrap(); - let b2: BoundedBTreeMap> = - [1, 2, 3, 4].into_iter().map(|k| (k, k)).try_collect().unwrap(); - - assert_eq!(b1, b2.try_map::<_, (), _>(|(_, v)| Ok(v * 2)).unwrap()); - } - - #[test] - fn try_map_short_circuit() { - let b1: BoundedBTreeMap> = - [1, 2, 3, 4].into_iter().map(|k| (k, k)).try_collect().unwrap(); - - assert_eq!(Err("overflow"), b1.try_map(|(_, v)| v.checked_mul(100).ok_or("overflow"))); - } - - #[test] - fn try_map_ok() { - let b1: BoundedBTreeMap> = - [1, 2, 3, 4].into_iter().map(|k| (k, k)).try_collect().unwrap(); - let b2: BoundedBTreeMap> = - [1, 2, 3, 4].into_iter().map(|k| (k, (k as u16) * 100)).try_collect().unwrap(); - - assert_eq!(Ok(b2), b1.try_map(|(_, v)| (v as u16).checked_mul(100_u16).ok_or("overflow"))); - } -} diff --git a/primitives/core/src/bounded/bounded_btree_set.rs b/primitives/core/src/bounded/bounded_btree_set.rs deleted file mode 100644 index 5feac6b7150f0..0000000000000 --- a/primitives/core/src/bounded/bounded_btree_set.rs +++ /dev/null @@ -1,482 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 2022 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. - -//! Traits, types and structs to support a bounded `BTreeSet`. - -use crate::{Get, TryCollect}; -use codec::{Decode, Encode, MaxEncodedLen}; -use sp_std::{borrow::Borrow, collections::btree_set::BTreeSet, marker::PhantomData, ops::Deref}; - -/// A bounded set based on a B-Tree. -/// -/// B-Trees represent a fundamental compromise between cache-efficiency and actually minimizing -/// the amount of work performed in a search. See [`BTreeSet`] for more details. -/// -/// Unlike a standard `BTreeSet`, there is an enforced upper limit to the number of items in the -/// set. All internal operations ensure this bound is respected. -#[derive(Encode, scale_info::TypeInfo)] -#[scale_info(skip_type_params(S))] -pub struct BoundedBTreeSet(BTreeSet, PhantomData); - -impl Decode for BoundedBTreeSet -where - T: Decode + Ord, - S: Get, -{ - fn decode(input: &mut I) -> Result { - let inner = BTreeSet::::decode(input)?; - if inner.len() > S::get() as usize { - return Err("BoundedBTreeSet exceeds its limit".into()) - } - Ok(Self(inner, PhantomData)) - } - - fn skip(input: &mut I) -> Result<(), codec::Error> { - BTreeSet::::skip(input) - } -} - -impl BoundedBTreeSet -where - S: Get, -{ - /// Get the bound of the type in `usize`. - pub fn bound() -> usize { - S::get() as usize - } -} - -impl BoundedBTreeSet -where - T: Ord, - S: Get, -{ - /// Create `Self` from `t` without any checks. - fn unchecked_from(t: BTreeSet) -> Self { - Self(t, Default::default()) - } - - /// Create a new `BoundedBTreeSet`. - /// - /// Does not allocate. - pub fn new() -> Self { - BoundedBTreeSet(BTreeSet::new(), PhantomData) - } - - /// Consume self, and return the inner `BTreeSet`. - /// - /// This is useful when a mutating API of the inner type is desired, and closure-based mutation - /// such as provided by [`try_mutate`][Self::try_mutate] is inconvenient. - pub fn into_inner(self) -> BTreeSet { - debug_assert!(self.0.len() <= Self::bound()); - self.0 - } - - /// 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 - /// returned. - /// - /// This is essentially a *consuming* shorthand [`Self::into_inner`] -> `...` -> - /// [`Self::try_from`]. - pub fn try_mutate(mut self, mut mutate: impl FnMut(&mut BTreeSet)) -> Option { - mutate(&mut self.0); - (self.0.len() <= Self::bound()).then(move || self) - } - - /// Clears the set, removing all elements. - pub fn clear(&mut self) { - self.0.clear() - } - - /// Exactly the same semantics as [`BTreeSet::insert`], but returns an `Err` (and is a noop) if - /// the new length of the set exceeds `S`. - /// - /// In the `Err` case, returns the inserted item so it can be further used without cloning. - pub fn try_insert(&mut self, item: T) -> Result { - if self.len() < Self::bound() || self.0.contains(&item) { - Ok(self.0.insert(item)) - } else { - Err(item) - } - } - - /// Remove an item from the set, returning whether it was previously in the set. - /// - /// The item may be any borrowed form of the set's item type, but the ordering on the borrowed - /// form _must_ match the ordering on the item type. - pub fn remove(&mut self, item: &Q) -> bool - where - T: Borrow, - Q: Ord + ?Sized, - { - self.0.remove(item) - } - - /// Removes and returns the value in the set, if any, that is equal to the given one. - /// - /// The value may be any borrowed form of the set's value type, but the ordering on the borrowed - /// form _must_ match the ordering on the value type. - pub fn take(&mut self, value: &Q) -> Option - where - T: Borrow + Ord, - Q: Ord + ?Sized, - { - self.0.take(value) - } -} - -impl Default for BoundedBTreeSet -where - T: Ord, - S: Get, -{ - fn default() -> Self { - Self::new() - } -} - -impl Clone for BoundedBTreeSet -where - BTreeSet: Clone, -{ - fn clone(&self) -> Self { - BoundedBTreeSet(self.0.clone(), PhantomData) - } -} - -impl sp_std::fmt::Debug for BoundedBTreeSet -where - BTreeSet: sp_std::fmt::Debug, - S: Get, -{ - fn fmt(&self, f: &mut sp_std::fmt::Formatter<'_>) -> sp_std::fmt::Result { - f.debug_tuple("BoundedBTreeSet").field(&self.0).field(&Self::bound()).finish() - } -} - -impl PartialEq> for BoundedBTreeSet -where - BTreeSet: PartialEq, - S1: Get, - S2: Get, -{ - fn eq(&self, other: &BoundedBTreeSet) -> bool { - S1::get() == S2::get() && self.0 == other.0 - } -} - -impl Eq for BoundedBTreeSet -where - BTreeSet: Eq, - S: Get, -{ -} - -impl PartialEq> for BoundedBTreeSet -where - BTreeSet: PartialEq, - S: Get, -{ - fn eq(&self, other: &BTreeSet) -> bool { - self.0 == *other - } -} - -impl PartialOrd for BoundedBTreeSet -where - BTreeSet: PartialOrd, - S: Get, -{ - fn partial_cmp(&self, other: &Self) -> Option { - self.0.partial_cmp(&other.0) - } -} - -impl Ord for BoundedBTreeSet -where - BTreeSet: Ord, - S: Get, -{ - fn cmp(&self, other: &Self) -> sp_std::cmp::Ordering { - self.0.cmp(&other.0) - } -} - -impl IntoIterator for BoundedBTreeSet { - type Item = T; - type IntoIter = sp_std::collections::btree_set::IntoIter; - - fn into_iter(self) -> Self::IntoIter { - self.0.into_iter() - } -} - -impl<'a, T, S> IntoIterator for &'a BoundedBTreeSet { - type Item = &'a T; - type IntoIter = sp_std::collections::btree_set::Iter<'a, T>; - - fn into_iter(self) -> Self::IntoIter { - self.0.iter() - } -} - -impl MaxEncodedLen for BoundedBTreeSet -where - T: MaxEncodedLen, - S: Get, -{ - fn max_encoded_len() -> usize { - Self::bound() - .saturating_mul(T::max_encoded_len()) - .saturating_add(codec::Compact(S::get()).encoded_size()) - } -} - -impl Deref for BoundedBTreeSet -where - T: Ord, -{ - type Target = BTreeSet; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl AsRef> for BoundedBTreeSet -where - T: Ord, -{ - fn as_ref(&self) -> &BTreeSet { - &self.0 - } -} - -impl From> for BTreeSet -where - T: Ord, -{ - fn from(set: BoundedBTreeSet) -> Self { - set.0 - } -} - -impl TryFrom> for BoundedBTreeSet -where - T: Ord, - S: Get, -{ - type Error = (); - - fn try_from(value: BTreeSet) -> Result { - (value.len() <= Self::bound()) - .then(move || BoundedBTreeSet(value, PhantomData)) - .ok_or(()) - } -} - -impl codec::DecodeLength for BoundedBTreeSet { - fn len(self_encoded: &[u8]) -> Result { - // `BoundedBTreeSet` is stored just a `BTreeSet`, which is stored as a - // `Compact` with its length followed by an iteration of its items. We can just use - // the underlying implementation. - as codec::DecodeLength>::len(self_encoded) - } -} - -impl codec::EncodeLike> for BoundedBTreeSet where BTreeSet: Encode {} - -impl TryCollect> for I -where - T: Ord, - I: ExactSizeIterator + Iterator, - Bound: Get, -{ - type Error = &'static str; - - fn try_collect(self) -> Result, Self::Error> { - if self.len() > Bound::get() as usize { - Err("iterator length too big") - } else { - Ok(BoundedBTreeSet::::unchecked_from(self.collect::>())) - } - } -} - -#[cfg(test)] -pub mod test { - use super::*; - use crate::ConstU32; - - fn set_from_keys(keys: &[T]) -> BTreeSet - where - T: Ord + Copy, - { - keys.iter().copied().collect() - } - - fn boundedset_from_keys(keys: &[T]) -> BoundedBTreeSet - where - T: Ord + Copy, - S: Get, - { - set_from_keys(keys).try_into().unwrap() - } - - #[test] - fn try_insert_works() { - let mut bounded = boundedset_from_keys::>(&[1, 2, 3]); - bounded.try_insert(0).unwrap(); - assert_eq!(*bounded, set_from_keys(&[1, 0, 2, 3])); - - assert!(bounded.try_insert(9).is_err()); - assert_eq!(*bounded, set_from_keys(&[1, 0, 2, 3])); - } - - #[test] - fn deref_coercion_works() { - let bounded = boundedset_from_keys::>(&[1, 2, 3]); - // these methods come from deref-ed vec. - assert_eq!(bounded.len(), 3); - assert!(bounded.iter().next().is_some()); - assert!(!bounded.is_empty()); - } - - #[test] - fn try_mutate_works() { - let bounded = boundedset_from_keys::>(&[1, 2, 3, 4, 5, 6]); - let bounded = bounded - .try_mutate(|v| { - v.insert(7); - }) - .unwrap(); - assert_eq!(bounded.len(), 7); - assert!(bounded - .try_mutate(|v| { - v.insert(8); - }) - .is_none()); - } - - #[test] - fn btree_map_eq_works() { - let bounded = boundedset_from_keys::>(&[1, 2, 3, 4, 5, 6]); - assert_eq!(bounded, set_from_keys(&[1, 2, 3, 4, 5, 6])); - } - - #[test] - fn too_big_fail_to_decode() { - let v: Vec = vec![1, 2, 3, 4, 5]; - assert_eq!( - BoundedBTreeSet::>::decode(&mut &v.encode()[..]), - Err("BoundedBTreeSet exceeds its limit".into()), - ); - } - - #[test] - fn unequal_eq_impl_insert_works() { - // given a struct with a strange notion of equality - #[derive(Debug)] - struct Unequal(u32, bool); - - impl PartialEq for Unequal { - fn eq(&self, other: &Self) -> bool { - self.0 == other.0 - } - } - impl Eq for Unequal {} - - impl Ord for Unequal { - fn cmp(&self, other: &Self) -> std::cmp::Ordering { - self.0.cmp(&other.0) - } - } - - impl PartialOrd for Unequal { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } - } - - let mut set = BoundedBTreeSet::>::new(); - - // when the set is full - - for i in 0..4 { - set.try_insert(Unequal(i, false)).unwrap(); - } - - // can't insert a new distinct member - set.try_insert(Unequal(5, false)).unwrap_err(); - - // but _can_ insert a distinct member which compares equal, though per the documentation, - // neither the set length nor the actual member are changed - set.try_insert(Unequal(0, true)).unwrap(); - assert_eq!(set.len(), 4); - let zero_item = set.get(&Unequal(0, true)).unwrap(); - assert_eq!(zero_item.0, 0); - assert_eq!(zero_item.1, false); - } - - #[test] - fn eq_works() { - // of same type - let b1 = boundedset_from_keys::>(&[1, 2]); - let b2 = boundedset_from_keys::>(&[1, 2]); - assert_eq!(b1, b2); - - // of different type, but same value and bound. - crate::parameter_types! { - B1: u32 = 7; - B2: u32 = 7; - } - let b1 = boundedset_from_keys::(&[1, 2]); - let b2 = boundedset_from_keys::(&[1, 2]); - assert_eq!(b1, b2); - } - - #[test] - fn can_be_collected() { - let b1 = boundedset_from_keys::>(&[1, 2, 3, 4]); - let b2: BoundedBTreeSet> = b1.iter().map(|k| k + 1).try_collect().unwrap(); - assert_eq!(b2.into_iter().collect::>(), vec![2, 3, 4, 5]); - - // can also be collected into a collection of length 4. - let b2: BoundedBTreeSet> = b1.iter().map(|k| k + 1).try_collect().unwrap(); - assert_eq!(b2.into_iter().collect::>(), vec![2, 3, 4, 5]); - - // can be mutated further into iterators that are `ExactSizedIterator`. - let b2: BoundedBTreeSet> = - b1.iter().map(|k| k + 1).rev().skip(2).try_collect().unwrap(); - // note that the binary tree will re-sort this, so rev() is not really seen - assert_eq!(b2.into_iter().collect::>(), vec![2, 3]); - - let b2: BoundedBTreeSet> = - b1.iter().map(|k| k + 1).take(2).try_collect().unwrap(); - assert_eq!(b2.into_iter().collect::>(), vec![2, 3]); - - // but these worn't work - let b2: Result>, _> = - b1.iter().map(|k| k + 1).try_collect(); - assert!(b2.is_err()); - - let b2: Result>, _> = - b1.iter().map(|k| k + 1).skip(2).try_collect(); - assert!(b2.is_err()); - } -} diff --git a/primitives/core/src/bounded/bounded_vec.rs b/primitives/core/src/bounded/bounded_vec.rs deleted file mode 100644 index 6e1e1c7cfda64..0000000000000 --- a/primitives/core/src/bounded/bounded_vec.rs +++ /dev/null @@ -1,1305 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 2017-2022 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. - -//! Traits, types and structs to support putting a bounded vector into storage, as a raw value, map -//! or a double map. - -use super::WeakBoundedVec; -use crate::{Get, TryCollect}; -use codec::{Decode, Encode, EncodeLike, MaxEncodedLen}; -use core::{ - ops::{Deref, Index, IndexMut, RangeBounds}, - slice::SliceIndex, -}; -#[cfg(feature = "std")] -use serde::{ - de::{Error, SeqAccess, Visitor}, - Deserialize, Deserializer, Serialize, -}; -use sp_std::{marker::PhantomData, prelude::*}; - -/// A bounded vector. -/// -/// It has implementations for efficient append and length decoding, as with a normal `Vec<_>`, once -/// put into storage as a raw value, map or double-map. -/// -/// As the name suggests, the length of the queue is always bounded. All internal operations ensure -/// this bound is respected. -#[cfg_attr(feature = "std", derive(Serialize), serde(transparent))] -#[derive(Encode, scale_info::TypeInfo)] -#[scale_info(skip_type_params(S))] -pub struct BoundedVec( - pub(super) Vec, - #[cfg_attr(feature = "std", serde(skip_serializing))] PhantomData, -); - -/// Create an object through truncation. -pub trait TruncateFrom { - /// Create an object through truncation. - fn truncate_from(unbound: T) -> Self; -} - -#[cfg(feature = "std")] -impl<'de, T, S: Get> Deserialize<'de> for BoundedVec -where - T: Deserialize<'de>, -{ - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - struct VecVisitor>(PhantomData<(T, S)>); - - impl<'de, T, S: Get> Visitor<'de> for VecVisitor - where - T: Deserialize<'de>, - { - type Value = Vec; - - fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { - formatter.write_str("a sequence") - } - - fn visit_seq(self, mut seq: A) -> Result - where - A: SeqAccess<'de>, - { - let size = seq.size_hint().unwrap_or(0); - let max = match usize::try_from(S::get()) { - Ok(n) => n, - Err(_) => return Err(A::Error::custom("can't convert to usize")), - }; - if size > max { - Err(A::Error::custom("out of bounds")) - } else { - let mut values = Vec::with_capacity(size); - - while let Some(value) = seq.next_element()? { - values.push(value); - if values.len() > max { - return Err(A::Error::custom("out of bounds")) - } - } - - Ok(values) - } - } - } - - let visitor: VecVisitor = VecVisitor(PhantomData); - deserializer - .deserialize_seq(visitor) - .map(|v| BoundedVec::::try_from(v).map_err(|_| Error::custom("out of bounds")))? - } -} - -/// A bounded slice. -/// -/// Similar to a `BoundedVec`, but not owned and cannot be decoded. -#[derive(Encode)] -pub struct BoundedSlice<'a, T, S>(pub(super) &'a [T], PhantomData); - -// This can be replaced with -// #[derive(scale_info::TypeInfo)] -// #[scale_info(skip_type_params(S))] -// again once this issue is fixed in the rust compiler: https://github.com/rust-lang/rust/issues/96956 -// Tracking issues: https://github.com/paritytech/substrate/issues/11915 -impl<'a, T, S> scale_info::TypeInfo for BoundedSlice<'a, T, S> -where - &'a [T]: scale_info::TypeInfo + 'static, - PhantomData: scale_info::TypeInfo + 'static, - T: scale_info::TypeInfo + 'static, - S: 'static, -{ - type Identity = Self; - - fn type_info() -> ::scale_info::Type { - scale_info::Type::builder() - .path(scale_info::Path::new("BoundedSlice", "sp_runtime::bounded::bounded_vec")) - .type_params(<[_]>::into_vec(Box::new([ - scale_info::TypeParameter::new( - "T", - core::option::Option::Some(::scale_info::meta_type::()), - ), - scale_info::TypeParameter::new("S", ::core::option::Option::None), - ]))) - .docs(&[ - "A bounded slice.", - "", - "Similar to a `BoundedVec`, but not owned and cannot be decoded.", - ]) - .composite( - scale_info::build::Fields::unnamed() - .field(|f| f.ty::<&'static [T]>().type_name("&'static[T]").docs(&[])) - .field(|f| f.ty::>().type_name("PhantomData").docs(&[])), - ) - } -} - -// `BoundedSlice`s encode to something which will always decode into a `BoundedVec`, -// `WeakBoundedVec`, or a `Vec`. -impl<'a, T: Encode + Decode, S: Get> EncodeLike> for BoundedSlice<'a, T, S> {} -impl<'a, T: Encode + Decode, S: Get> EncodeLike> - for BoundedSlice<'a, T, S> -{ -} -impl<'a, T: Encode + Decode, S: Get> EncodeLike> for BoundedSlice<'a, T, S> {} - -impl<'a, T, BoundSelf, BoundRhs> PartialEq> - for BoundedSlice<'a, T, BoundSelf> -where - T: PartialEq, - BoundSelf: Get, - BoundRhs: Get, -{ - fn eq(&self, other: &BoundedSlice<'a, T, BoundRhs>) -> bool { - self.0 == other.0 - } -} - -impl<'a, T, BoundSelf, BoundRhs> PartialEq> - for BoundedSlice<'a, T, BoundSelf> -where - T: PartialEq, - BoundSelf: Get, - BoundRhs: Get, -{ - fn eq(&self, other: &BoundedVec) -> bool { - self.0 == other.0 - } -} - -impl<'a, T, BoundSelf, BoundRhs> PartialEq> - for BoundedSlice<'a, T, BoundSelf> -where - T: PartialEq, - BoundSelf: Get, - BoundRhs: Get, -{ - fn eq(&self, other: &WeakBoundedVec) -> bool { - self.0 == other.0 - } -} - -impl<'a, T, S: Get> Eq for BoundedSlice<'a, T, S> where T: Eq {} - -impl<'a, T, BoundSelf, BoundRhs> PartialOrd> - for BoundedSlice<'a, T, BoundSelf> -where - T: PartialOrd, - BoundSelf: Get, - BoundRhs: Get, -{ - fn partial_cmp(&self, other: &BoundedSlice<'a, T, BoundRhs>) -> Option { - self.0.partial_cmp(other.0) - } -} - -impl<'a, T, BoundSelf, BoundRhs> PartialOrd> - for BoundedSlice<'a, T, BoundSelf> -where - T: PartialOrd, - BoundSelf: Get, - BoundRhs: Get, -{ - fn partial_cmp(&self, other: &BoundedVec) -> Option { - self.0.partial_cmp(&*other.0) - } -} - -impl<'a, T, BoundSelf, BoundRhs> PartialOrd> - for BoundedSlice<'a, T, BoundSelf> -where - T: PartialOrd, - BoundSelf: Get, - BoundRhs: Get, -{ - fn partial_cmp(&self, other: &WeakBoundedVec) -> Option { - self.0.partial_cmp(&*other.0) - } -} - -impl<'a, T: Ord, Bound: Get> Ord for BoundedSlice<'a, T, Bound> { - fn cmp(&self, other: &Self) -> sp_std::cmp::Ordering { - self.0.cmp(&other.0) - } -} - -impl<'a, T, S: Get> TryFrom<&'a [T]> for BoundedSlice<'a, T, S> { - type Error = &'a [T]; - fn try_from(t: &'a [T]) -> Result { - if t.len() <= S::get() as usize { - Ok(BoundedSlice(t, PhantomData)) - } else { - Err(t) - } - } -} - -impl<'a, T, S> From> for &'a [T] { - fn from(t: BoundedSlice<'a, T, S>) -> Self { - t.0 - } -} - -impl<'a, T, S: Get> TruncateFrom<&'a [T]> for BoundedSlice<'a, T, S> { - fn truncate_from(unbound: &'a [T]) -> Self { - BoundedSlice::::truncate_from(unbound) - } -} - -impl<'a, T, S> Clone for BoundedSlice<'a, T, S> { - fn clone(&self) -> Self { - BoundedSlice(self.0, PhantomData) - } -} - -impl<'a, T, S> sp_std::fmt::Debug for BoundedSlice<'a, T, S> -where - &'a [T]: sp_std::fmt::Debug, - S: Get, -{ - fn fmt(&self, f: &mut sp_std::fmt::Formatter<'_>) -> sp_std::fmt::Result { - f.debug_tuple("BoundedSlice").field(&self.0).field(&S::get()).finish() - } -} - -// Since a reference `&T` is always `Copy`, so is `BoundedSlice<'a, T, S>`. -impl<'a, T, S> Copy for BoundedSlice<'a, T, S> {} - -// will allow for all immutable operations of `[T]` on `BoundedSlice`. -impl<'a, T, S> Deref for BoundedSlice<'a, T, S> { - type Target = [T]; - - fn deref(&self) -> &Self::Target { - self.0 - } -} - -impl<'a, T, S> sp_std::iter::IntoIterator for BoundedSlice<'a, T, S> { - type Item = &'a T; - type IntoIter = sp_std::slice::Iter<'a, T>; - fn into_iter(self) -> Self::IntoIter { - self.0.iter() - } -} - -impl<'a, T, S: Get> BoundedSlice<'a, T, S> { - /// Create an instance from the first elements of the given slice (or all of it if it is smaller - /// than the length bound). - pub fn truncate_from(s: &'a [T]) -> Self { - Self(&s[0..(s.len().min(S::get() as usize))], PhantomData) - } -} - -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()) - } - Ok(Self(inner, PhantomData)) - } - - fn skip(input: &mut I) -> Result<(), codec::Error> { - Vec::::skip(input) - } -} - -// `BoundedVec`s encode to something which will always decode as a `Vec`. -impl> EncodeLike> for BoundedVec {} - -impl BoundedVec { - /// Create `Self` from `t` without any checks. - fn unchecked_from(t: Vec) -> Self { - Self(t, Default::default()) - } - - /// Consume self, and return the inner `Vec`. Henceforth, the `Vec<_>` can be altered in an - /// arbitrary way. At some point, if the reverse conversion is required, `TryFrom>` can - /// be used. - /// - /// This is useful for cases if you need access to an internal API of the inner `Vec<_>` which - /// is not provided by the wrapper `BoundedVec`. - pub fn into_inner(self) -> Vec { - self.0 - } - - /// Exactly the same semantics as [`slice::sort_by`]. - /// - /// This is safe since sorting cannot change the number of elements in the vector. - pub fn sort_by(&mut self, compare: F) - where - F: FnMut(&T, &T) -> sp_std::cmp::Ordering, - { - self.0.sort_by(compare) - } - - /// Exactly the same semantics as [`slice::sort_by_key`]. - /// - /// This is safe since sorting cannot change the number of elements in the vector. - pub fn sort_by_key(&mut self, f: F) - where - F: FnMut(&T) -> K, - K: sp_std::cmp::Ord, - { - self.0.sort_by_key(f) - } - - /// Exactly the same semantics as [`slice::sort`]. - /// - /// This is safe since sorting cannot change the number of elements in the vector. - pub fn sort(&mut self) - where - T: sp_std::cmp::Ord, - { - self.0.sort() - } - - /// Exactly the same semantics as `Vec::remove`. - /// - /// # Panics - /// - /// Panics if `index` is out of bounds. - pub fn remove(&mut self, index: usize) -> T { - self.0.remove(index) - } - - /// Exactly the same semantics as `slice::swap_remove`. - /// - /// # Panics - /// - /// Panics if `index` is out of bounds. - pub fn swap_remove(&mut self, index: usize) -> T { - self.0.swap_remove(index) - } - - /// Exactly the same semantics as `Vec::retain`. - pub fn retain bool>(&mut self, f: F) { - self.0.retain(f) - } - - /// Exactly the same semantics as `slice::get_mut`. - pub fn get_mut>( - &mut self, - index: I, - ) -> Option<&mut >::Output> { - self.0.get_mut(index) - } - - /// Exactly the same semantics as `Vec::truncate`. - /// - /// This is safe because `truncate` can never increase the length of the internal vector. - pub fn truncate(&mut self, s: usize) { - self.0.truncate(s); - } - - /// Exactly the same semantics as `Vec::pop`. - /// - /// This is safe since popping can only shrink the inner vector. - pub fn pop(&mut self) -> Option { - self.0.pop() - } - - /// Exactly the same semantics as [`slice::iter_mut`]. - pub fn iter_mut(&mut self) -> core::slice::IterMut<'_, T> { - self.0.iter_mut() - } - - /// Exactly the same semantics as [`slice::last_mut`]. - pub fn last_mut(&mut self) -> Option<&mut T> { - self.0.last_mut() - } - - /// Exact same semantics as [`Vec::drain`]. - pub fn drain(&mut self, range: R) -> sp_std::vec::Drain<'_, T> - where - R: RangeBounds, - { - self.0.drain(range) - } -} - -impl> From> for Vec { - fn from(x: BoundedVec) -> Vec { - x.0 - } -} - -impl> BoundedVec { - /// Pre-allocate `capacity` items in self. - /// - /// If `capacity` is greater than [`Self::bound`], then the minimum of the two is used. - pub fn with_bounded_capacity(capacity: usize) -> Self { - let capacity = capacity.min(Self::bound()); - Self(Vec::with_capacity(capacity), Default::default()) - } - - /// Allocate self with the maximum possible capacity. - pub fn with_max_capacity() -> Self { - Self::with_bounded_capacity(Self::bound()) - } - - /// Consume and truncate the vector `v` in order to create a new instance of `Self` from it. - pub fn truncate_from(mut v: Vec) -> Self { - v.truncate(Self::bound()); - Self::unchecked_from(v) - } - - /// Get the bound of the type in `usize`. - pub fn bound() -> usize { - S::get() as usize - } - - /// Returns true of this collection is full. - pub fn is_full(&self) -> bool { - self.len() >= Self::bound() - } - - /// Forces the insertion of `element` into `self` retaining all items with index at least - /// `index`. - /// - /// If `index == 0` and `self.len() == Self::bound()`, then this is a no-op. - /// - /// If `Self::bound() < index` or `self.len() < index`, then this is also a no-op. - /// - /// Returns `Ok(maybe_removed)` if the item was inserted, where `maybe_removed` is - /// `Some(removed)` if an item was removed to make room for the new one. Returns `Err(())` if - /// `element` cannot be inserted. - pub fn force_insert_keep_right( - &mut self, - index: usize, - mut element: T, - ) -> Result, ()> { - // Check against panics. - if Self::bound() < index || self.len() < index { - Err(()) - } else if self.len() < Self::bound() { - // Cannot panic since self.len() >= index; - self.0.insert(index, element); - Ok(None) - } else { - if index == 0 { - return Err(()) - } - sp_std::mem::swap(&mut self[0], &mut element); - // `[0..index] cannot panic since self.len() >= index. - // `rotate_left(1)` cannot panic because there is at least 1 element. - self[0..index].rotate_left(1); - Ok(Some(element)) - } - } - - /// Forces the insertion of `element` into `self` retaining all items with index at most - /// `index`. - /// - /// If `index == Self::bound()` and `self.len() == Self::bound()`, then this is a no-op. - /// - /// If `Self::bound() < index` or `self.len() < index`, then this is also a no-op. - /// - /// Returns `Ok(maybe_removed)` if the item was inserted, where `maybe_removed` is - /// `Some(removed)` if an item was removed to make room for the new one. Returns `Err(())` if - /// `element` cannot be inserted. - pub fn force_insert_keep_left(&mut self, index: usize, element: T) -> Result, ()> { - // Check against panics. - if Self::bound() < index || self.len() < index || Self::bound() == 0 { - return Err(()) - } - // Noop condition. - if Self::bound() == index && self.len() <= Self::bound() { - return Err(()) - } - let maybe_removed = if self.is_full() { - // defensive-only: since we are at capacity, this is a noop. - self.0.truncate(Self::bound()); - // if we truncate anything, it will be the last one. - self.0.pop() - } else { - None - }; - - // Cannot panic since `self.len() >= index`; - self.0.insert(index, element); - Ok(maybe_removed) - } - - /// Move the position of an item from one location to another in the slice. - /// - /// Except for the item being moved, the order of the slice remains the same. - /// - /// - `index` is the location of the item to be moved. - /// - `insert_position` is the index of the item in the slice which should *immediately follow* - /// the item which is being moved. - /// - /// Returns `true` of the operation was successful, otherwise `false` if a noop. - pub fn slide(&mut self, index: usize, insert_position: usize) -> bool { - // Check against panics. - if self.len() <= index || self.len() < insert_position || index == usize::MAX { - return false - } - // Noop conditions. - if index == insert_position || index + 1 == insert_position { - return false - } - if insert_position < index && index < self.len() { - // --- --- --- === === === === @@@ --- --- --- - // ^-- N ^O^ - // ... - // /-----<<<-----\ - // --- --- --- === === === === @@@ --- --- --- - // >>> >>> >>> >>> - // ... - // --- --- --- @@@ === === === === --- --- --- - // ^N^ - self[insert_position..index + 1].rotate_right(1); - return true - } else if insert_position > 0 && index + 1 < insert_position { - // Note that the apparent asymmetry of these two branches is due to the - // fact that the "new" position is the position to be inserted *before*. - // --- --- --- @@@ === === === === --- --- --- - // ^O^ ^-- N - // ... - // /----->>>-----\ - // --- --- --- @@@ === === === === --- --- --- - // <<< <<< <<< <<< - // ... - // --- --- --- === === === === @@@ --- --- --- - // ^N^ - self[index..insert_position].rotate_left(1); - return true - } - - debug_assert!(false, "all noop conditions should have been covered above"); - false - } - - /// Forces the insertion of `s` into `self` truncating first if necessary. - /// - /// Infallible, but if the bound is zero, then it's a no-op. - pub fn force_push(&mut self, element: T) { - if Self::bound() > 0 { - self.0.truncate(Self::bound() as usize - 1); - self.0.push(element); - } - } - - /// Same as `Vec::resize`, but if `size` is more than [`Self::bound`], then [`Self::bound`] is - /// used. - pub fn bounded_resize(&mut self, size: usize, value: T) - where - T: Clone, - { - let size = size.min(Self::bound()); - self.0.resize(size, value); - } - - /// Exactly the same semantics as [`Vec::extend`], but returns an error and does nothing if the - /// length of the outcome is larger than the bound. - pub fn try_extend( - &mut self, - with: impl IntoIterator + ExactSizeIterator, - ) -> Result<(), ()> { - if with.len().saturating_add(self.len()) <= Self::bound() { - self.0.extend(with); - Ok(()) - } else { - Err(()) - } - } - - /// Exactly the same semantics as [`Vec::append`], but returns an error and does nothing if the - /// length of the outcome is larger than the bound. - pub fn try_append(&mut self, other: &mut Vec) -> Result<(), ()> { - if other.len().saturating_add(self.len()) <= Self::bound() { - self.0.append(other); - Ok(()) - } else { - Err(()) - } - } - - /// 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 - /// returned. - /// - /// This is essentially a *consuming* shorthand [`Self::into_inner`] -> `...` -> - /// [`Self::try_from`]. - pub fn try_mutate(mut self, mut mutate: impl FnMut(&mut Vec)) -> Option { - mutate(&mut self.0); - (self.0.len() <= Self::bound()).then(move || self) - } - - /// Exactly the same semantics as [`Vec::insert`], but returns an `Err` (and is a noop) if the - /// new length of the vector exceeds `S`. - /// - /// # Panics - /// - /// Panics if `index > len`. - pub fn try_insert(&mut self, index: usize, element: T) -> Result<(), T> { - if self.len() < Self::bound() { - self.0.insert(index, element); - Ok(()) - } else { - Err(element) - } - } - - /// Exactly the same semantics as [`Vec::push`], but returns an `Err` (and is a noop) if the - /// new length of the vector exceeds `S`. - /// - /// # Panics - /// - /// Panics if the new capacity exceeds isize::MAX bytes. - pub fn try_push(&mut self, element: T) -> Result<(), T> { - if self.len() < Self::bound() { - self.0.push(element); - Ok(()) - } else { - Err(element) - } - } -} - -impl BoundedVec { - /// Return a [`BoundedSlice`] with the content and bound of [`Self`]. - pub fn as_bounded_slice(&self) -> BoundedSlice { - BoundedSlice(&self.0[..], PhantomData::default()) - } -} - -impl Default for BoundedVec { - fn default() -> Self { - // the bound cannot be below 0, which is satisfied by an empty vector - Self::unchecked_from(Vec::default()) - } -} - -impl sp_std::fmt::Debug for BoundedVec -where - Vec: sp_std::fmt::Debug, - S: Get, -{ - fn fmt(&self, f: &mut sp_std::fmt::Formatter<'_>) -> sp_std::fmt::Result { - f.debug_tuple("BoundedVec").field(&self.0).field(&Self::bound()).finish() - } -} - -impl Clone for BoundedVec -where - T: Clone, -{ - fn clone(&self) -> Self { - // bound is retained - Self::unchecked_from(self.0.clone()) - } -} - -impl> TryFrom> for BoundedVec { - type Error = Vec; - fn try_from(t: Vec) -> Result { - if t.len() <= Self::bound() { - // explicit check just above - Ok(Self::unchecked_from(t)) - } else { - Err(t) - } - } -} - -impl> TruncateFrom> for BoundedVec { - fn truncate_from(unbound: Vec) -> Self { - BoundedVec::::truncate_from(unbound) - } -} - -// It is okay to give a non-mutable reference of the inner vec to anyone. -impl AsRef> for BoundedVec { - fn as_ref(&self) -> &Vec { - &self.0 - } -} - -impl AsRef<[T]> for BoundedVec { - fn as_ref(&self) -> &[T] { - &self.0 - } -} - -impl AsMut<[T]> for BoundedVec { - fn as_mut(&mut self) -> &mut [T] { - &mut self.0 - } -} - -// will allow for all immutable operations of `Vec` on `BoundedVec`. -impl Deref for BoundedVec { - type Target = Vec; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -// Allows for indexing similar to a normal `Vec`. Can panic if out of bound. -impl Index for BoundedVec -where - I: SliceIndex<[T]>, -{ - type Output = I::Output; - - #[inline] - fn index(&self, index: I) -> &Self::Output { - self.0.index(index) - } -} - -impl IndexMut for BoundedVec -where - I: SliceIndex<[T]>, -{ - #[inline] - fn index_mut(&mut self, index: I) -> &mut Self::Output { - self.0.index_mut(index) - } -} - -impl sp_std::iter::IntoIterator for BoundedVec { - type Item = T; - type IntoIter = sp_std::vec::IntoIter; - fn into_iter(self) -> Self::IntoIter { - self.0.into_iter() - } -} - -impl<'a, T, S> sp_std::iter::IntoIterator for &'a BoundedVec { - type Item = &'a T; - type IntoIter = sp_std::slice::Iter<'a, T>; - fn into_iter(self) -> Self::IntoIter { - self.0.iter() - } -} - -impl<'a, T, S> sp_std::iter::IntoIterator for &'a mut BoundedVec { - type Item = &'a mut T; - type IntoIter = sp_std::slice::IterMut<'a, T>; - fn into_iter(self) -> Self::IntoIter { - self.0.iter_mut() - } -} - -impl codec::DecodeLength for BoundedVec { - fn len(self_encoded: &[u8]) -> Result { - // `BoundedVec` stored just a `Vec`, thus the length is at the beginning in - // `Compact` form, and same implementation as `Vec` can be used. - as codec::DecodeLength>::len(self_encoded) - } -} - -impl PartialEq> for BoundedVec -where - T: PartialEq, - BoundSelf: Get, - BoundRhs: Get, -{ - fn eq(&self, rhs: &BoundedVec) -> bool { - self.0 == rhs.0 - } -} - -impl PartialEq> for BoundedVec -where - T: PartialEq, - BoundSelf: Get, - BoundRhs: Get, -{ - fn eq(&self, rhs: &WeakBoundedVec) -> bool { - self.0 == rhs.0 - } -} - -impl<'a, T, BoundSelf, BoundRhs> PartialEq> - for BoundedVec -where - T: PartialEq, - BoundSelf: Get, - BoundRhs: Get, -{ - fn eq(&self, rhs: &BoundedSlice<'a, T, BoundRhs>) -> bool { - self.0 == rhs.0 - } -} - -impl<'a, T: PartialEq, S: Get> PartialEq<&'a [T]> for BoundedSlice<'a, T, S> { - fn eq(&self, other: &&'a [T]) -> bool { - &self.0 == other - } -} - -impl> PartialEq> for BoundedVec { - fn eq(&self, other: &Vec) -> bool { - &self.0 == other - } -} - -impl> Eq for BoundedVec where T: Eq {} - -impl PartialOrd> for BoundedVec -where - T: PartialOrd, - BoundSelf: Get, - BoundRhs: Get, -{ - fn partial_cmp(&self, other: &BoundedVec) -> Option { - self.0.partial_cmp(&other.0) - } -} - -impl PartialOrd> for BoundedVec -where - T: PartialOrd, - BoundSelf: Get, - BoundRhs: Get, -{ - fn partial_cmp(&self, other: &WeakBoundedVec) -> Option { - self.0.partial_cmp(&other.0) - } -} - -impl<'a, T, BoundSelf, BoundRhs> PartialOrd> - for BoundedVec -where - T: PartialOrd, - BoundSelf: Get, - BoundRhs: Get, -{ - fn partial_cmp(&self, other: &BoundedSlice<'a, T, BoundRhs>) -> Option { - (&*self.0).partial_cmp(other.0) - } -} - -impl> Ord for BoundedVec { - fn cmp(&self, other: &Self) -> sp_std::cmp::Ordering { - self.0.cmp(&other.0) - } -} - -impl MaxEncodedLen for BoundedVec -where - T: MaxEncodedLen, - S: Get, - BoundedVec: Encode, -{ - fn max_encoded_len() -> usize { - // BoundedVec encodes like Vec which encodes like [T], which is a compact u32 - // plus each item in the slice: - // See: https://docs.substrate.io/reference/scale-codec/ - codec::Compact(S::get()) - .encoded_size() - .saturating_add(Self::bound().saturating_mul(T::max_encoded_len())) - } -} - -impl TryCollect> for I -where - I: ExactSizeIterator + Iterator, - Bound: Get, -{ - type Error = &'static str; - - fn try_collect(self) -> Result, Self::Error> { - if self.len() > Bound::get() as usize { - Err("iterator length too big") - } else { - Ok(BoundedVec::::unchecked_from(self.collect::>())) - } - } -} - -#[cfg(test)] -pub mod test { - use super::*; - use crate::{bounded_vec, ConstU32}; - - #[test] - fn slice_truncate_from_works() { - let bounded = BoundedSlice::>::truncate_from(&[1, 2, 3, 4, 5]); - assert_eq!(bounded.deref(), &[1, 2, 3, 4]); - let bounded = BoundedSlice::>::truncate_from(&[1, 2, 3, 4]); - assert_eq!(bounded.deref(), &[1, 2, 3, 4]); - let bounded = BoundedSlice::>::truncate_from(&[1, 2, 3]); - assert_eq!(bounded.deref(), &[1, 2, 3]); - } - - #[test] - fn slide_works() { - let mut b: BoundedVec> = bounded_vec![0, 1, 2, 3, 4, 5]; - assert!(b.slide(1, 5)); - assert_eq!(*b, vec![0, 2, 3, 4, 1, 5]); - assert!(b.slide(4, 0)); - assert_eq!(*b, vec![1, 0, 2, 3, 4, 5]); - assert!(b.slide(0, 2)); - assert_eq!(*b, vec![0, 1, 2, 3, 4, 5]); - assert!(b.slide(1, 6)); - assert_eq!(*b, vec![0, 2, 3, 4, 5, 1]); - assert!(b.slide(0, 6)); - assert_eq!(*b, vec![2, 3, 4, 5, 1, 0]); - assert!(b.slide(5, 0)); - assert_eq!(*b, vec![0, 2, 3, 4, 5, 1]); - assert!(!b.slide(6, 0)); - assert!(!b.slide(7, 0)); - assert_eq!(*b, vec![0, 2, 3, 4, 5, 1]); - - let mut c: BoundedVec> = bounded_vec![0, 1, 2]; - assert!(!c.slide(1, 5)); - assert_eq!(*c, vec![0, 1, 2]); - assert!(!c.slide(4, 0)); - assert_eq!(*c, vec![0, 1, 2]); - assert!(!c.slide(3, 0)); - assert_eq!(*c, vec![0, 1, 2]); - assert!(c.slide(2, 0)); - assert_eq!(*c, vec![2, 0, 1]); - } - - #[test] - fn slide_noops_work() { - let mut b: BoundedVec> = bounded_vec![0, 1, 2, 3, 4, 5]; - assert!(!b.slide(3, 3)); - assert_eq!(*b, vec![0, 1, 2, 3, 4, 5]); - assert!(!b.slide(3, 4)); - assert_eq!(*b, vec![0, 1, 2, 3, 4, 5]); - } - - #[test] - fn force_insert_keep_left_works() { - let mut b: BoundedVec> = bounded_vec![]; - assert_eq!(b.force_insert_keep_left(1, 10), Err(())); - assert!(b.is_empty()); - - assert_eq!(b.force_insert_keep_left(0, 30), Ok(None)); - assert_eq!(b.force_insert_keep_left(0, 10), Ok(None)); - assert_eq!(b.force_insert_keep_left(1, 20), Ok(None)); - assert_eq!(b.force_insert_keep_left(3, 40), Ok(None)); - assert_eq!(*b, vec![10, 20, 30, 40]); - // at capacity. - assert_eq!(b.force_insert_keep_left(4, 41), Err(())); - assert_eq!(*b, vec![10, 20, 30, 40]); - assert_eq!(b.force_insert_keep_left(3, 31), Ok(Some(40))); - assert_eq!(*b, vec![10, 20, 30, 31]); - assert_eq!(b.force_insert_keep_left(1, 11), Ok(Some(31))); - assert_eq!(*b, vec![10, 11, 20, 30]); - assert_eq!(b.force_insert_keep_left(0, 1), Ok(Some(30))); - assert_eq!(*b, vec![1, 10, 11, 20]); - - let mut z: BoundedVec> = bounded_vec![]; - assert!(z.is_empty()); - assert_eq!(z.force_insert_keep_left(0, 10), Err(())); - assert!(z.is_empty()); - } - - #[test] - fn force_insert_keep_right_works() { - let mut b: BoundedVec> = bounded_vec![]; - assert_eq!(b.force_insert_keep_right(1, 10), Err(())); - assert!(b.is_empty()); - - assert_eq!(b.force_insert_keep_right(0, 30), Ok(None)); - assert_eq!(b.force_insert_keep_right(0, 10), Ok(None)); - assert_eq!(b.force_insert_keep_right(1, 20), Ok(None)); - assert_eq!(b.force_insert_keep_right(3, 40), Ok(None)); - assert_eq!(*b, vec![10, 20, 30, 40]); - - // at capacity. - assert_eq!(b.force_insert_keep_right(0, 0), Err(())); - assert_eq!(*b, vec![10, 20, 30, 40]); - assert_eq!(b.force_insert_keep_right(1, 11), Ok(Some(10))); - assert_eq!(*b, vec![11, 20, 30, 40]); - assert_eq!(b.force_insert_keep_right(3, 31), Ok(Some(11))); - assert_eq!(*b, vec![20, 30, 31, 40]); - assert_eq!(b.force_insert_keep_right(4, 41), Ok(Some(20))); - assert_eq!(*b, vec![30, 31, 40, 41]); - - assert_eq!(b.force_insert_keep_right(5, 69), Err(())); - assert_eq!(*b, vec![30, 31, 40, 41]); - - let mut z: BoundedVec> = bounded_vec![]; - assert!(z.is_empty()); - assert_eq!(z.force_insert_keep_right(0, 10), Err(())); - assert!(z.is_empty()); - } - - #[test] - fn bound_returns_correct_value() { - assert_eq!(BoundedVec::>::bound(), 7); - } - - #[test] - fn try_insert_works() { - let mut bounded: BoundedVec> = bounded_vec![1, 2, 3]; - bounded.try_insert(1, 0).unwrap(); - assert_eq!(*bounded, vec![1, 0, 2, 3]); - - assert!(bounded.try_insert(0, 9).is_err()); - assert_eq!(*bounded, vec![1, 0, 2, 3]); - } - - #[test] - fn constructor_macro_works() { - // With values. Use some brackets to make sure the macro doesn't expand. - let bv: BoundedVec<(u32, u32), ConstU32<3>> = bounded_vec![(1, 2), (1, 2), (1, 2)]; - assert_eq!(bv, vec![(1, 2), (1, 2), (1, 2)]); - - // With repetition. - let bv: BoundedVec<(u32, u32), ConstU32<3>> = bounded_vec![(1, 2); 3]; - assert_eq!(bv, vec![(1, 2), (1, 2), (1, 2)]); - } - - #[test] - #[should_panic(expected = "insertion index (is 9) should be <= len (is 3)")] - fn try_inert_panics_if_oob() { - let mut bounded: BoundedVec> = bounded_vec![1, 2, 3]; - bounded.try_insert(9, 0).unwrap(); - } - - #[test] - fn try_push_works() { - let mut bounded: BoundedVec> = bounded_vec![1, 2, 3]; - bounded.try_push(0).unwrap(); - assert_eq!(*bounded, vec![1, 2, 3, 0]); - - assert!(bounded.try_push(9).is_err()); - } - - #[test] - fn deref_vec_coercion_works() { - let bounded: BoundedVec> = bounded_vec![1, 2, 3]; - // these methods come from deref-ed vec. - assert_eq!(bounded.len(), 3); - assert!(bounded.iter().next().is_some()); - assert!(!bounded.is_empty()); - } - - #[test] - fn deref_slice_coercion_works() { - let bounded = BoundedSlice::>::try_from(&[1, 2, 3][..]).unwrap(); - // these methods come from deref-ed slice. - assert_eq!(bounded.len(), 3); - assert!(bounded.iter().next().is_some()); - assert!(!bounded.is_empty()); - } - - #[test] - fn try_mutate_works() { - let bounded: BoundedVec> = bounded_vec![1, 2, 3, 4, 5, 6]; - let bounded = bounded.try_mutate(|v| v.push(7)).unwrap(); - assert_eq!(bounded.len(), 7); - assert!(bounded.try_mutate(|v| v.push(8)).is_none()); - } - - #[test] - fn slice_indexing_works() { - let bounded: BoundedVec> = bounded_vec![1, 2, 3, 4, 5, 6]; - assert_eq!(&bounded[0..=2], &[1, 2, 3]); - } - - #[test] - fn vec_eq_works() { - let bounded: BoundedVec> = bounded_vec![1, 2, 3, 4, 5, 6]; - assert_eq!(bounded, vec![1, 2, 3, 4, 5, 6]); - } - - #[test] - fn too_big_vec_fail_to_decode() { - let v: Vec = vec![1, 2, 3, 4, 5]; - assert_eq!( - BoundedVec::>::decode(&mut &v.encode()[..]), - Err("BoundedVec exceeds its limit".into()), - ); - } - - #[test] - fn eq_works() { - // of same type - let b1: BoundedVec> = bounded_vec![1, 2, 3]; - let b2: BoundedVec> = bounded_vec![1, 2, 3]; - assert_eq!(b1, b2); - - // of different type, but same value and bound. - crate::parameter_types! { - B1: u32 = 7; - B2: u32 = 7; - } - let b1: BoundedVec = bounded_vec![1, 2, 3]; - let b2: BoundedVec = bounded_vec![1, 2, 3]; - assert_eq!(b1, b2); - } - - #[test] - fn ord_works() { - use std::cmp::Ordering; - let b1: BoundedVec> = bounded_vec![1, 2, 3]; - let b2: BoundedVec> = bounded_vec![1, 3, 2]; - - // ordering for vec is lexicographic. - assert_eq!(b1.cmp(&b2), Ordering::Less); - assert_eq!(b1.cmp(&b2), b1.into_inner().cmp(&b2.into_inner())); - } - - #[test] - fn try_extend_works() { - let mut b: BoundedVec> = bounded_vec![1, 2, 3]; - - assert!(b.try_extend(vec![4].into_iter()).is_ok()); - assert_eq!(*b, vec![1, 2, 3, 4]); - - assert!(b.try_extend(vec![5].into_iter()).is_ok()); - assert_eq!(*b, vec![1, 2, 3, 4, 5]); - - assert!(b.try_extend(vec![6].into_iter()).is_err()); - assert_eq!(*b, vec![1, 2, 3, 4, 5]); - - let mut b: BoundedVec> = bounded_vec![1, 2, 3]; - assert!(b.try_extend(vec![4, 5].into_iter()).is_ok()); - assert_eq!(*b, vec![1, 2, 3, 4, 5]); - - let mut b: BoundedVec> = bounded_vec![1, 2, 3]; - assert!(b.try_extend(vec![4, 5, 6].into_iter()).is_err()); - assert_eq!(*b, vec![1, 2, 3]); - } - - #[test] - fn test_serializer() { - let c: BoundedVec> = bounded_vec![0, 1, 2]; - assert_eq!(serde_json::json!(&c).to_string(), r#"[0,1,2]"#); - } - - #[test] - fn test_deserializer() { - let c: BoundedVec> = serde_json::from_str(r#"[0,1,2]"#).unwrap(); - - assert_eq!(c.len(), 3); - assert_eq!(c[0], 0); - assert_eq!(c[1], 1); - assert_eq!(c[2], 2); - } - - #[test] - fn test_deserializer_failed() { - let c: Result>, serde_json::error::Error> = - serde_json::from_str(r#"[0,1,2,3,4,5]"#); - - match c { - Err(msg) => assert_eq!(msg.to_string(), "out of bounds at line 1 column 11"), - _ => unreachable!("deserializer must raise error"), - } - } - - #[test] - fn bounded_vec_try_from_works() { - assert!(BoundedVec::>::try_from(vec![0]).is_ok()); - assert!(BoundedVec::>::try_from(vec![0, 1]).is_ok()); - assert!(BoundedVec::>::try_from(vec![0, 1, 2]).is_err()); - } - - #[test] - fn bounded_slice_try_from_works() { - assert!(BoundedSlice::>::try_from(&[0][..]).is_ok()); - assert!(BoundedSlice::>::try_from(&[0, 1][..]).is_ok()); - assert!(BoundedSlice::>::try_from(&[0, 1, 2][..]).is_err()); - } - - #[test] - fn can_be_collected() { - let b1: BoundedVec> = bounded_vec![1, 2, 3, 4]; - let b2: BoundedVec> = b1.iter().map(|x| x + 1).try_collect().unwrap(); - assert_eq!(b2, vec![2, 3, 4, 5]); - - // can also be collected into a collection of length 4. - let b2: BoundedVec> = b1.iter().map(|x| x + 1).try_collect().unwrap(); - assert_eq!(b2, vec![2, 3, 4, 5]); - - // can be mutated further into iterators that are `ExactSizedIterator`. - let b2: BoundedVec> = - b1.iter().map(|x| x + 1).rev().try_collect().unwrap(); - assert_eq!(b2, vec![5, 4, 3, 2]); - - let b2: BoundedVec> = - b1.iter().map(|x| x + 1).rev().skip(2).try_collect().unwrap(); - assert_eq!(b2, vec![3, 2]); - let b2: BoundedVec> = - b1.iter().map(|x| x + 1).rev().skip(2).try_collect().unwrap(); - assert_eq!(b2, vec![3, 2]); - - let b2: BoundedVec> = - b1.iter().map(|x| x + 1).rev().take(2).try_collect().unwrap(); - assert_eq!(b2, vec![5, 4]); - let b2: BoundedVec> = - b1.iter().map(|x| x + 1).rev().take(2).try_collect().unwrap(); - assert_eq!(b2, vec![5, 4]); - - // but these worn't work - let b2: Result>, _> = b1.iter().map(|x| x + 1).try_collect(); - assert!(b2.is_err()); - - let b2: Result>, _> = - b1.iter().map(|x| x + 1).rev().take(2).try_collect(); - assert!(b2.is_err()); - } - - #[test] - fn bounded_vec_debug_works() { - let bound = BoundedVec::>::truncate_from(vec![1, 2, 3]); - assert_eq!(format!("{:?}", bound), "BoundedVec([1, 2, 3], 5)"); - } - - #[test] - fn bounded_slice_debug_works() { - let bound = BoundedSlice::>::truncate_from(&[1, 2, 3]); - assert_eq!(format!("{:?}", bound), "BoundedSlice([1, 2, 3], 5)"); - } - - #[test] - fn bounded_vec_sort_by_key_works() { - let mut v: BoundedVec> = bounded_vec![-5, 4, 1, -3, 2]; - // Sort by absolute value. - v.sort_by_key(|k| k.abs()); - assert_eq!(v, vec![1, 2, -3, 4, -5]); - } - - #[test] - fn bounded_vec_truncate_from_works() { - let unbound = vec![1, 2, 3, 4, 5]; - let bound = BoundedVec::>::truncate_from(unbound.clone()); - assert_eq!(bound, vec![1, 2, 3]); - } - - #[test] - fn bounded_slice_truncate_from_works() { - let unbound = [1, 2, 3, 4, 5]; - let bound = BoundedSlice::>::truncate_from(&unbound); - assert_eq!(bound, &[1, 2, 3][..]); - } - - #[test] - fn bounded_slice_partialeq_slice_works() { - let unbound = [1, 2, 3]; - let bound = BoundedSlice::>::truncate_from(&unbound); - - assert_eq!(bound, &unbound[..]); - assert!(bound == &unbound[..]); - } -} diff --git a/primitives/core/src/bounded/weak_bounded_vec.rs b/primitives/core/src/bounded/weak_bounded_vec.rs deleted file mode 100644 index 5aff35f010c8b..0000000000000 --- a/primitives/core/src/bounded/weak_bounded_vec.rs +++ /dev/null @@ -1,524 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 2017-2022 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. - -//! Traits, types and structs to support putting a bounded vector into storage, as a raw value, map -//! or a double map. - -use super::{BoundedSlice, BoundedVec}; -use crate::Get; -use codec::{Decode, Encode, MaxEncodedLen}; -use core::{ - ops::{Deref, Index, IndexMut}, - slice::SliceIndex, -}; -#[cfg(feature = "std")] -use serde::{ - de::{Error, SeqAccess, Visitor}, - Deserialize, Deserializer, Serialize, -}; -use sp_std::{marker::PhantomData, prelude::*}; - -/// A weakly bounded vector. -/// -/// It has implementations for efficient append and length decoding, as with a normal `Vec<_>`, once -/// put into storage as a raw value, map or double-map. -/// -/// The length of the vec is not strictly bounded. Decoding a vec with more element that the bound -/// is accepted, and some method allow to bypass the restriction with warnings. -#[cfg_attr(feature = "std", derive(Serialize), serde(transparent))] -#[derive(Encode, scale_info::TypeInfo)] -#[scale_info(skip_type_params(S))] -pub struct WeakBoundedVec( - pub(super) Vec, - #[cfg_attr(feature = "std", serde(skip_serializing))] PhantomData, -); - -#[cfg(feature = "std")] -impl<'de, T, S: Get> Deserialize<'de> for WeakBoundedVec -where - T: Deserialize<'de>, -{ - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - struct VecVisitor>(PhantomData<(T, S)>); - - impl<'de, T, S: Get> Visitor<'de> for VecVisitor - where - T: Deserialize<'de>, - { - type Value = Vec; - - fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { - formatter.write_str("a sequence") - } - - fn visit_seq(self, mut seq: A) -> Result - where - A: SeqAccess<'de>, - { - let size = seq.size_hint().unwrap_or(0); - let max = match usize::try_from(S::get()) { - Ok(n) => n, - Err(_) => return Err(A::Error::custom("can't convert to usize")), - }; - if size > max { - log::warn!( - target: "runtime", - "length of a bounded vector while deserializing is not respected.", - ); - } - let mut values = Vec::with_capacity(size); - - while let Some(value) = seq.next_element()? { - values.push(value); - if values.len() > max { - log::warn!( - target: "runtime", - "length of a bounded vector while deserializing is not respected.", - ); - } - } - - Ok(values) - } - } - - let visitor: VecVisitor = VecVisitor(PhantomData); - deserializer.deserialize_seq(visitor).map(|v| { - WeakBoundedVec::::try_from(v).map_err(|_| Error::custom("out of bounds")) - })? - } -} - -impl> Decode for WeakBoundedVec { - fn decode(input: &mut I) -> Result { - let inner = Vec::::decode(input)?; - Ok(Self::force_from(inner, Some("decode"))) - } - - fn skip(input: &mut I) -> Result<(), codec::Error> { - Vec::::skip(input) - } -} - -impl WeakBoundedVec { - /// Create `Self` from `t` without any checks. - fn unchecked_from(t: Vec) -> Self { - Self(t, Default::default()) - } - - /// Consume self, and return the inner `Vec`. Henceforth, the `Vec<_>` can be altered in an - /// arbitrary way. At some point, if the reverse conversion is required, `TryFrom>` can - /// be used. - /// - /// This is useful for cases if you need access to an internal API of the inner `Vec<_>` which - /// is not provided by the wrapper `WeakBoundedVec`. - pub fn into_inner(self) -> Vec { - self.0 - } - - /// Exactly the same semantics as [`Vec::remove`]. - /// - /// # Panics - /// - /// Panics if `index` is out of bounds. - pub fn remove(&mut self, index: usize) -> T { - self.0.remove(index) - } - - /// Exactly the same semantics as [`Vec::swap_remove`]. - /// - /// # Panics - /// - /// Panics if `index` is out of bounds. - pub fn swap_remove(&mut self, index: usize) -> T { - self.0.swap_remove(index) - } - - /// Exactly the same semantics as [`Vec::retain`]. - pub fn retain bool>(&mut self, f: F) { - self.0.retain(f) - } - - /// Exactly the same semantics as [`slice::get_mut`]. - pub fn get_mut>( - &mut self, - index: I, - ) -> Option<&mut >::Output> { - self.0.get_mut(index) - } -} - -impl> WeakBoundedVec { - /// Get the bound of the type in `usize`. - pub fn bound() -> usize { - 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 { - if t.len() > Self::bound() { - log::warn!( - target: "runtime", - "length of a bounded vector in scope {} is not respected.", - scope.unwrap_or("UNKNOWN"), - ); - } - - Self::unchecked_from(t) - } - - /// 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 - /// returned. - /// - /// This is essentially a *consuming* shorthand [`Self::into_inner`] -> `...` -> - /// [`Self::try_from`]. - pub fn try_mutate(mut self, mut mutate: impl FnMut(&mut Vec)) -> Option { - mutate(&mut self.0); - (self.0.len() <= Self::bound()).then(move || self) - } - - /// Exactly the same semantics as [`Vec::insert`], but returns an `Err` (and is a noop) if the - /// new length of the vector exceeds `S`. - /// - /// # Panics - /// - /// Panics if `index > len`. - pub fn try_insert(&mut self, index: usize, element: T) -> Result<(), ()> { - if self.len() < Self::bound() { - self.0.insert(index, element); - Ok(()) - } else { - Err(()) - } - } - - /// Exactly the same semantics as [`Vec::push`], but returns an `Err` (and is a noop) if the - /// new length of the vector exceeds `S`. - /// - /// # Panics - /// - /// Panics if the new capacity exceeds isize::MAX bytes. - pub fn try_push(&mut self, element: T) -> Result<(), ()> { - if self.len() < Self::bound() { - self.0.push(element); - Ok(()) - } else { - Err(()) - } - } -} - -impl Default for WeakBoundedVec { - fn default() -> Self { - // the bound cannot be below 0, which is satisfied by an empty vector - Self::unchecked_from(Vec::default()) - } -} - -impl sp_std::fmt::Debug for WeakBoundedVec -where - Vec: sp_std::fmt::Debug, - S: Get, -{ - fn fmt(&self, f: &mut sp_std::fmt::Formatter<'_>) -> sp_std::fmt::Result { - f.debug_tuple("WeakBoundedVec").field(&self.0).field(&Self::bound()).finish() - } -} - -impl Clone for WeakBoundedVec -where - T: Clone, -{ - fn clone(&self) -> Self { - // bound is retained - Self::unchecked_from(self.0.clone()) - } -} - -impl> TryFrom> for WeakBoundedVec { - type Error = (); - fn try_from(t: Vec) -> Result { - if t.len() <= Self::bound() { - // explicit check just above - Ok(Self::unchecked_from(t)) - } else { - Err(()) - } - } -} - -// It is okay to give a non-mutable reference of the inner vec to anyone. -impl AsRef> for WeakBoundedVec { - fn as_ref(&self) -> &Vec { - &self.0 - } -} - -impl AsRef<[T]> for WeakBoundedVec { - fn as_ref(&self) -> &[T] { - &self.0 - } -} - -impl AsMut<[T]> for WeakBoundedVec { - fn as_mut(&mut self) -> &mut [T] { - &mut self.0 - } -} - -// will allow for immutable all operations of `Vec` on `WeakBoundedVec`. -impl Deref for WeakBoundedVec { - type Target = Vec; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -// Allows for indexing similar to a normal `Vec`. Can panic if out of bound. -impl Index for WeakBoundedVec -where - I: SliceIndex<[T]>, -{ - type Output = I::Output; - - #[inline] - fn index(&self, index: I) -> &Self::Output { - self.0.index(index) - } -} - -impl IndexMut for WeakBoundedVec -where - I: SliceIndex<[T]>, -{ - #[inline] - fn index_mut(&mut self, index: I) -> &mut Self::Output { - self.0.index_mut(index) - } -} - -impl sp_std::iter::IntoIterator for WeakBoundedVec { - type Item = T; - type IntoIter = sp_std::vec::IntoIter; - fn into_iter(self) -> Self::IntoIter { - self.0.into_iter() - } -} - -impl<'a, T, S> sp_std::iter::IntoIterator for &'a WeakBoundedVec { - type Item = &'a T; - type IntoIter = sp_std::slice::Iter<'a, T>; - fn into_iter(self) -> Self::IntoIter { - self.0.iter() - } -} - -impl<'a, T, S> sp_std::iter::IntoIterator for &'a mut WeakBoundedVec { - type Item = &'a mut T; - type IntoIter = sp_std::slice::IterMut<'a, T>; - fn into_iter(self) -> Self::IntoIter { - self.0.iter_mut() - } -} - -impl codec::DecodeLength for WeakBoundedVec { - fn len(self_encoded: &[u8]) -> Result { - // `WeakBoundedVec` stored just a `Vec`, thus the length is at the beginning in - // `Compact` form, and same implementation as `Vec` can be used. - as codec::DecodeLength>::len(self_encoded) - } -} - -impl PartialEq> for WeakBoundedVec -where - T: PartialEq, - BoundSelf: Get, - BoundRhs: Get, -{ - fn eq(&self, rhs: &WeakBoundedVec) -> bool { - self.0 == rhs.0 - } -} - -impl PartialEq> for WeakBoundedVec -where - T: PartialEq, - BoundSelf: Get, - BoundRhs: Get, -{ - fn eq(&self, rhs: &BoundedVec) -> bool { - self.0 == rhs.0 - } -} - -impl<'a, T, BoundSelf, BoundRhs> PartialEq> - for WeakBoundedVec -where - T: PartialEq, - BoundSelf: Get, - BoundRhs: Get, -{ - fn eq(&self, rhs: &BoundedSlice<'a, T, BoundRhs>) -> bool { - self.0 == rhs.0 - } -} - -impl> PartialEq> for WeakBoundedVec { - fn eq(&self, other: &Vec) -> bool { - &self.0 == other - } -} - -impl> Eq for WeakBoundedVec where T: Eq {} - -impl PartialOrd> - for WeakBoundedVec -where - T: PartialOrd, - BoundSelf: Get, - BoundRhs: Get, -{ - fn partial_cmp(&self, other: &WeakBoundedVec) -> Option { - self.0.partial_cmp(&other.0) - } -} - -impl PartialOrd> for WeakBoundedVec -where - T: PartialOrd, - BoundSelf: Get, - BoundRhs: Get, -{ - fn partial_cmp(&self, other: &BoundedVec) -> Option { - self.0.partial_cmp(&other.0) - } -} - -impl<'a, T, BoundSelf, BoundRhs> PartialOrd> - for WeakBoundedVec -where - T: PartialOrd, - BoundSelf: Get, - BoundRhs: Get, -{ - fn partial_cmp(&self, other: &BoundedSlice<'a, T, BoundRhs>) -> Option { - (&*self.0).partial_cmp(other.0) - } -} - -impl> Ord for WeakBoundedVec { - fn cmp(&self, other: &Self) -> sp_std::cmp::Ordering { - self.0.cmp(&other.0) - } -} - -impl MaxEncodedLen for WeakBoundedVec -where - T: MaxEncodedLen, - S: Get, - WeakBoundedVec: Encode, -{ - fn max_encoded_len() -> usize { - // WeakBoundedVec encodes like Vec which encodes like [T], which is a compact u32 - // plus each item in the slice: - // See: https://docs.substrate.io/reference/scale-codec/ - codec::Compact(S::get()) - .encoded_size() - .saturating_add(Self::bound().saturating_mul(T::max_encoded_len())) - } -} - -#[cfg(test)] -pub mod test { - use super::*; - use crate::ConstU32; - - #[test] - fn bound_returns_correct_value() { - assert_eq!(WeakBoundedVec::>::bound(), 7); - } - - #[test] - fn try_insert_works() { - let mut bounded: WeakBoundedVec> = vec![1, 2, 3].try_into().unwrap(); - bounded.try_insert(1, 0).unwrap(); - assert_eq!(*bounded, vec![1, 0, 2, 3]); - - assert!(bounded.try_insert(0, 9).is_err()); - assert_eq!(*bounded, vec![1, 0, 2, 3]); - } - - #[test] - #[should_panic(expected = "insertion index (is 9) should be <= len (is 3)")] - fn try_inert_panics_if_oob() { - let mut bounded: WeakBoundedVec> = vec![1, 2, 3].try_into().unwrap(); - bounded.try_insert(9, 0).unwrap(); - } - - #[test] - fn try_push_works() { - let mut bounded: WeakBoundedVec> = vec![1, 2, 3].try_into().unwrap(); - bounded.try_push(0).unwrap(); - assert_eq!(*bounded, vec![1, 2, 3, 0]); - - assert!(bounded.try_push(9).is_err()); - } - - #[test] - fn deref_coercion_works() { - let bounded: WeakBoundedVec> = vec![1, 2, 3].try_into().unwrap(); - // these methods come from deref-ed vec. - assert_eq!(bounded.len(), 3); - assert!(bounded.iter().next().is_some()); - assert!(!bounded.is_empty()); - } - - #[test] - fn try_mutate_works() { - let bounded: WeakBoundedVec> = vec![1, 2, 3, 4, 5, 6].try_into().unwrap(); - let bounded = bounded.try_mutate(|v| v.push(7)).unwrap(); - assert_eq!(bounded.len(), 7); - assert!(bounded.try_mutate(|v| v.push(8)).is_none()); - } - - #[test] - fn slice_indexing_works() { - let bounded: WeakBoundedVec> = vec![1, 2, 3, 4, 5, 6].try_into().unwrap(); - assert_eq!(&bounded[0..=2], &[1, 2, 3]); - } - - #[test] - fn vec_eq_works() { - let bounded: WeakBoundedVec> = vec![1, 2, 3, 4, 5, 6].try_into().unwrap(); - assert_eq!(bounded, vec![1, 2, 3, 4, 5, 6]); - } - - #[test] - fn too_big_succeed_to_decode() { - let v: Vec = vec![1, 2, 3, 4, 5]; - let w = WeakBoundedVec::>::decode(&mut &v.encode()[..]).unwrap(); - assert_eq!(v, *w); - } -} diff --git a/primitives/core/src/lib.rs b/primitives/core/src/lib.rs index 80e14b84d3ff4..13dbad66be9ff 100644 --- a/primitives/core/src/lib.rs +++ b/primitives/core/src/lib.rs @@ -51,7 +51,6 @@ pub mod hashing; #[cfg(feature = "full_crypto")] pub use hashing::{blake2_128, blake2_256, keccak_256, twox_128, twox_256, twox_64}; -pub mod bounded; pub mod crypto; pub mod hexdisplay; @@ -81,6 +80,13 @@ pub use self::hasher::blake2::Blake2Hasher; pub use self::hasher::keccak::KeccakHasher; pub use hash_db::Hasher; +pub use bounded_collections as bounded; +#[cfg(feature = "std")] +pub use bounded_collections::{bounded_btree_map, bounded_vec}; +pub use bounded_collections::{ + parameter_types, ConstBool, ConstI128, ConstI16, ConstI32, ConstI64, ConstI8, ConstU128, + ConstU16, ConstU32, ConstU64, ConstU8, Get, GetDefault, TryCollect, TypedGet, +}; pub use sp_storage as storage; #[doc(hidden)] @@ -387,242 +393,6 @@ macro_rules! impl_maybe_marker { // everybody. pub const MAX_POSSIBLE_ALLOCATION: u32 = 33554432; // 2^25 bytes, 32 MiB -/// A trait for querying a single value from a type defined in the trait. -/// -/// It is not required that the value is constant. -pub trait TypedGet { - /// The type which is returned. - type Type; - /// Return the current value. - fn get() -> Self::Type; -} - -/// A trait for querying a single value from a type. -/// -/// It is not required that the value is constant. -pub trait Get { - /// Return the current value. - fn get() -> T; -} - -impl Get for () { - fn get() -> T { - T::default() - } -} - -/// Implement Get by returning Default for any type that implements Default. -pub struct GetDefault; -impl Get for GetDefault { - fn get() -> T { - T::default() - } -} - -macro_rules! impl_const_get { - ($name:ident, $t:ty) => { - #[doc = "Const getter for a basic type."] - #[derive($crate::RuntimeDebug)] - pub struct $name; - impl Get<$t> for $name { - fn get() -> $t { - T - } - } - impl Get> for $name { - fn get() -> Option<$t> { - Some(T) - } - } - impl TypedGet for $name { - type Type = $t; - fn get() -> $t { - T - } - } - }; -} - -impl_const_get!(ConstBool, bool); -impl_const_get!(ConstU8, u8); -impl_const_get!(ConstU16, u16); -impl_const_get!(ConstU32, u32); -impl_const_get!(ConstU64, u64); -impl_const_get!(ConstU128, u128); -impl_const_get!(ConstI8, i8); -impl_const_get!(ConstI16, i16); -impl_const_get!(ConstI32, i32); -impl_const_get!(ConstI64, i64); -impl_const_get!(ConstI128, i128); - -/// Try and collect into a collection `C`. -pub trait TryCollect { - /// The error type that gets returned when a collection can't be made from `self`. - type Error; - /// Consume self and try to collect the results into `C`. - /// - /// This is useful in preventing the undesirable `.collect().try_into()` call chain on - /// collections that need to be converted into a bounded type (e.g. `BoundedVec`). - fn try_collect(self) -> Result; -} - -/// Create new implementations of the [`Get`](crate::Get) trait. -/// -/// The so-called parameter type can be created in four different ways: -/// -/// - Using `const` to create a parameter type that provides a `const` getter. It is required that -/// the `value` is const. -/// -/// - Declare the parameter type without `const` to have more freedom when creating the value. -/// -/// NOTE: A more substantial version of this macro is available in `frame_support` crate which -/// allows mutable and persistant variants. -/// -/// # Examples -/// -/// ``` -/// # use sp_core::Get; -/// # use sp_core::parameter_types; -/// // This function cannot be used in a const context. -/// fn non_const_expression() -> u64 { 99 } -/// -/// const FIXED_VALUE: u64 = 10; -/// parameter_types! { -/// pub const Argument: u64 = 42 + FIXED_VALUE; -/// /// Visibility of the type is optional -/// OtherArgument: u64 = non_const_expression(); -/// } -/// -/// trait Config { -/// type Parameter: Get; -/// type OtherParameter: Get; -/// } -/// -/// struct Runtime; -/// impl Config for Runtime { -/// type Parameter = Argument; -/// type OtherParameter = OtherArgument; -/// } -/// ``` -/// -/// # Invalid example: -/// -/// ```compile_fail -/// # use sp_core::Get; -/// # use sp_core::parameter_types; -/// // This function cannot be used in a const context. -/// fn non_const_expression() -> u64 { 99 } -/// -/// parameter_types! { -/// pub const Argument: u64 = non_const_expression(); -/// } -/// ``` -#[macro_export] -macro_rules! parameter_types { - ( - $( #[ $attr:meta ] )* - $vis:vis const $name:ident: $type:ty = $value:expr; - $( $rest:tt )* - ) => ( - $( #[ $attr ] )* - $vis struct $name; - $crate::parameter_types!(@IMPL_CONST $name , $type , $value); - $crate::parameter_types!( $( $rest )* ); - ); - ( - $( #[ $attr:meta ] )* - $vis:vis $name:ident: $type:ty = $value:expr; - $( $rest:tt )* - ) => ( - $( #[ $attr ] )* - $vis struct $name; - $crate::parameter_types!(@IMPL $name, $type, $value); - $crate::parameter_types!( $( $rest )* ); - ); - () => (); - (@IMPL_CONST $name:ident, $type:ty, $value:expr) => { - impl $name { - /// Returns the value of this parameter type. - pub const fn get() -> $type { - $value - } - } - - impl> $crate::Get for $name { - fn get() -> I { - I::from(Self::get()) - } - } - - impl $crate::TypedGet for $name { - type Type = $type; - fn get() -> $type { - Self::get() - } - } - }; - (@IMPL $name:ident, $type:ty, $value:expr) => { - impl $name { - /// Returns the value of this parameter type. - pub fn get() -> $type { - $value - } - } - - impl> $crate::Get for $name { - fn get() -> I { - I::from(Self::get()) - } - } - - impl $crate::TypedGet for $name { - type Type = $type; - fn get() -> $type { - Self::get() - } - } - }; -} - -/// Build a bounded vec from the given literals. -/// -/// The type of the outcome must be known. -/// -/// Will not handle any errors and just panic if the given literals cannot fit in the corresponding -/// bounded vec type. Thus, this is only suitable for testing and non-consensus code. -#[macro_export] -#[cfg(feature = "std")] -macro_rules! bounded_vec { - ($ ($values:expr),* $(,)?) => { - { - $crate::sp_std::vec![$($values),*].try_into().unwrap() - } - }; - ( $value:expr ; $repetition:expr ) => { - { - $crate::sp_std::vec![$value ; $repetition].try_into().unwrap() - } - } -} - -/// Build a bounded btree-map from the given literals. -/// -/// The type of the outcome must be known. -/// -/// Will not handle any errors and just panic if the given literals cannot fit in the corresponding -/// bounded vec type. Thus, this is only suitable for testing and non-consensus code. -#[macro_export] -#[cfg(feature = "std")] -macro_rules! bounded_btree_map { - ($ ( $key:expr => $value:expr ),* $(,)?) => { - { - $crate::TryCollect::<$crate::bounded::BoundedBTreeMap<_, _, _>>::try_collect( - $crate::sp_std::vec![$(($key, $value)),*].into_iter() - ).unwrap() - } - }; -} - /// Generates a macro for checking if a certain feature is enabled. /// /// These feature checking macros can be used to conditionally enable/disable code in a dependent From f28e182225ee4d8b8b872c58d5ccec590b381f2d Mon Sep 17 00:00:00 2001 From: Ankan Date: Sun, 5 Feb 2023 17:46:20 +0100 Subject: [PATCH 089/162] some new definitions --- frame/staking/src/mock.rs | 1 + frame/staking/src/pallet/mod.rs | 73 +++++++++++++++++++++++++++++---- 2 files changed, 67 insertions(+), 7 deletions(-) diff --git a/frame/staking/src/mock.rs b/frame/staking/src/mock.rs index 81b48694fae99..cd3f111ca026e 100644 --- a/frame/staking/src/mock.rs +++ b/frame/staking/src/mock.rs @@ -294,6 +294,7 @@ impl crate::pallet::pallet::Config for Test { type EraPayout = ConvertCurve; type NextNewSession = Session; type MaxNominatorRewardedPerValidator = MaxNominatorRewardedPerValidator; + type MaxExposurePageSize = MaxNominatorRewardedPerValidator; type OffendingValidatorsThreshold = OffendingValidatorsThreshold; type ElectionProvider = onchain::OnChainExecution; type GenesisElectionProvider = Self::ElectionProvider; diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index d3d5839697c5c..8067de36d7c67 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -201,15 +201,24 @@ pub mod pallet { /// guess. type NextNewSession: EstimateNextNewSession; - /// The maximum number of nominators rewarded for each validator. + /// The maximum number of nominators rewarded for each validator when using + /// `ErasStakersClipped`. /// - /// A reward payout is restricted to a maximum of `MaxNominatorRewardedPerValidator` - /// nominators in a single call. This used to limit the i/o cost for the nominator payout. - /// See call `payout_stakers` for more details. - // TODO(ank4n): Should we change this name? Breaking changes! + /// For older non-paged exposure, a reward payout is restricted to the top + /// `MaxNominatorRewardedPerValidator` nominators. This is to limit the i/o cost for the + /// nominator payout. + // TODO(ank4n) #[deprecated(note = "This constant is no longer used and will be removed in the future.")] #[pallet::constant] type MaxNominatorRewardedPerValidator: Get; + /// The maximum size of each `T::ExposurePage`. + /// + /// An `ExposurePage` is bounded to a maximum of `MaxExposurePageSize` nominators. The + /// actual page size is a dynamic value that is determined by the storage item + /// `T::ExposurePageSize`. + #[pallet::constant] + type MaxExposurePageSize: 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; @@ -466,6 +475,12 @@ pub mod pallet { ValueQuery, >; + /// The nominator count each `ExposurePage` is capped at. + /// + /// This cannot be greater than `T::MaxExposurePageSize`. + #[pallet::storage] + pub type ExposurePageSize = StorageValue<_, u32, OptionQuery>; + /// Paginated exposure of a validator at given era. /// /// This is keyed first by the era index to allow bulk deletion, then the tuple of stash account @@ -1655,7 +1670,7 @@ pub mod pallet { Ok(()) } - /// Pay out all the stakers behind a single validator for a single era and page. + /// Pay out next page of the stakers behind a validator for the given era. /// /// - `validator_stash` is the stash account of the validator. /// - `era` may be any era between `[current_era - history_depth; current_era]`. @@ -1665,7 +1680,7 @@ pub mod pallet { /// The origin of this call must be _Signed_. Any account can call this function, even if /// it is not one of the stakers. /// - /// If a validator has more than `T::MaxMaxNominatorRewardedPerValidator` nominators backing + /// If a validator has more than `T::MaxNominatorRewardedPerValidator` nominators backing /// them, then the list of nominators is paged, with each page being capped at /// `T::MaxNominatorRewardedPerValidator`. If a validator has more than one page of /// nominators, the call needs to be made for each page separately in order for all the @@ -1988,6 +2003,50 @@ pub mod pallet { MinCommission::::put(new); Ok(()) } + + /// Pay out a page of the stakers behind a validator for the given era and page. + /// + /// - `validator_stash` is the stash account of the validator. + /// - `era` may be any era between `[current_era - history_depth; current_era]`. + /// - `page` is the page index of nominators to pay out with value between 0 and + /// `num_nominators / T::MaxNominatorRewardedPerValidator`. + /// + /// The origin of this call must be _Signed_. Any account can call this function, even if + /// it is not one of the stakers. + /// + /// If a validator has more than `T::MaxNominatorRewardedPerValidator` nominators backing + /// them, then the list of nominators is paged, with each page being capped at + /// `T::MaxNominatorRewardedPerValidator`. If a validator has more than one page of + /// nominators, the call needs to be made for each page separately in order for all the + /// nominators backing a validator receive the reward. The nominators are not sorted across + /// pages and so it should not be assumed the highest staker would be on the topmost page + /// and vice versa. If rewards are not claimed in `${HistoryDepth}` eras, they are lost. + /// + /// # + /// - Time complexity: at most O(MaxNominatorRewardedPerValidator). + /// - Contains a limited number of reads and writes. + /// ----------- + /// N is the Number of payouts for the validator (including the validator) + /// Weight: + /// - Reward Destination Staked: O(N) + /// - Reward Destination Controller (Creating): O(N) + /// + /// NOTE: weights are assuming that payouts are made to alive stash account (Staked). + /// Paying even a dead controller is cheaper weight-wise. We don't do any refunds here. + /// # + #[pallet::call_index(26)] + #[pallet::weight(T::WeightInfo::payout_stakers_alive_staked( + T::MaxNominatorRewardedPerValidator::get() + ))] + pub fn payout_stakers_by_page( + origin: OriginFor, + validator_stash: T::AccountId, + era: EraIndex, + page: PageIndex, + ) -> DispatchResultWithPostInfo { + ensure_signed(origin)?; + Self::do_payout_stakers(validator_stash, era, page) + } } } From ab79cd3aa50f449034dee62d1d6b9cb507048e3e Mon Sep 17 00:00:00 2001 From: Ankan Date: Sun, 5 Feb 2023 18:39:59 +0100 Subject: [PATCH 090/162] new call to payout staekers by page --- frame/staking/src/lib.rs | 1 + frame/staking/src/mock.rs | 2 +- frame/staking/src/pallet/impls.rs | 56 ++++++++++++++++++++++ frame/staking/src/pallet/mod.rs | 31 ++++++++---- frame/staking/src/tests.rs | 80 +++++++++++++++---------------- 5 files changed, 119 insertions(+), 51 deletions(-) diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index 9b75b0b7d4f34..12fd67951256a 100644 --- a/frame/staking/src/lib.rs +++ b/frame/staking/src/lib.rs @@ -778,6 +778,7 @@ pub struct ExposurePage { #[codec(compact)] pub page_total: Balance, /// The portions of nominators stashes that are exposed. + /// TODO(ank4n): BoundedVec touches lot of code, skip for now. pub others: Vec>, } diff --git a/frame/staking/src/mock.rs b/frame/staking/src/mock.rs index cd3f111ca026e..bf66c06bbb44d 100644 --- a/frame/staking/src/mock.rs +++ b/frame/staking/src/mock.rs @@ -760,7 +760,7 @@ pub(crate) fn make_all_reward_payment(era: EraIndex) { for validator_controller in validators_with_reward.iter().filter_map(Staking::bonded) { let ledger = >::get(&validator_controller).unwrap(); for page in 0..EraInfo::::get_page_count(era, &ledger.stash) { - assert_ok!(Staking::payout_stakers( + assert_ok!(Staking::payout_stakers_by_page( RuntimeOrigin::signed(1337), ledger.stash, era, diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index faf807eee8275..253a1e97f372b 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -131,9 +131,65 @@ impl Pallet { Ok(used_weight) } + fn validate_payout_stakers( + validator_stash: T::AccountId, + era: EraIndex, + ) -> Result<(), Error> { + // Validate input data + let current_era = CurrentEra::::get().ok_or_else(|| { + Error::::InvalidEraToReward + })?; + + let history_depth = T::HistoryDepth::get(); + ensure!( + era <= current_era && era >= current_era.saturating_sub(history_depth), + Error::::InvalidEraToReward + ); + + // ensure!( + // page < EraInfo::::get_page_count(era, &validator_stash), + // Error::::InvalidPage.with_weight(T::WeightInfo::payout_stakers_alive_staked(0)) + // ); + + // Note: if era has no reward to be claimed, era may be future. better not to update + // `ledger.legacy_claimed_rewards` in this case. + let era_payout = >::get(&era).ok_or_else(|| { + Error::::InvalidEraToReward + })?; + + let controller = Self::bonded(&validator_stash).ok_or_else(|| { + Error::::NotStash + })?; + let mut ledger = >::get(&controller).ok_or(Error::::NotController)?; + + // // clean up legacy claimed rewards + ledger + .legacy_claimed_rewards + .retain(|&x| x >= current_era.saturating_sub(history_depth)); + >::insert(&controller, &ledger); + + // if EraInfo::::is_rewards_claimed_temp(era, &ledger, &ledger.stash, page) { + // Error::::AlreadyClaimed + // .with_weight(T::WeightInfo::payout_stakers_alive_staked(0)) + // } + + + Ok(()) + } + + + pub(super) fn do_payout_stakers( validator_stash: T::AccountId, era: EraIndex, + ) -> DispatchResultWithPostInfo { + EraInfo::::get_page_count(era, &validator_stash); + Self::do_payout_stakers_by_page(validator_stash, era, 0) + } + + pub(super) fn do_payout_stakers_by_page( + validator_stash: T::AccountId, + era: EraIndex, page: PageIndex, ) -> DispatchResultWithPostInfo { // Validate input data diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index 8067de36d7c67..2031993aea82e 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -207,7 +207,8 @@ pub mod pallet { /// For older non-paged exposure, a reward payout is restricted to the top /// `MaxNominatorRewardedPerValidator` nominators. This is to limit the i/o cost for the /// nominator payout. - // TODO(ank4n) #[deprecated(note = "This constant is no longer used and will be removed in the future.")] + // TODO(ank4n) #[deprecated(note = "This constant is no longer used and will be removed in + // the future.")] #[pallet::constant] type MaxNominatorRewardedPerValidator: Get; @@ -667,7 +668,7 @@ pub mod pallet { /// This is only used for paged rewards. Once older non-paged rewards are no longer /// relevant, `is_rewards_claimed_temp` can be removed and this function can be made public. fn is_rewards_claimed(era: EraIndex, validator: &T::AccountId, page: PageIndex) -> bool { - ClaimedRewards::::get(era, validator).iter().any(|&p| page == p) + ClaimedRewards::::get(era, validator).binary_search(&page).is_ok() } /// Get exposure info for a validator at a given era and page. @@ -720,9 +721,18 @@ pub mod pallet { validator: &T::AccountId, page: PageIndex, ) { - ClaimedRewards::::mutate(era, validator, |pages| { - pages.push(page); - }) + let mut claimed_pages = ClaimedRewards::::get(era, validator); + let search = claimed_pages.binary_search(&page); + // this should never be called if the reward has already been claimed + debug_assert!(search.is_err()); + + match search { + Err(index) => { + claimed_pages.insert(index, page); + ClaimedRewards::::insert(era, validator, claimed_pages); + }, + _ => {}, + } } /// Store exposure for elected validators at start of an era. @@ -1674,12 +1684,14 @@ pub mod pallet { /// /// - `validator_stash` is the stash account of the validator. /// - `era` may be any era between `[current_era - history_depth; current_era]`. - /// - `page` is the page index of nominators to pay out with value between 0 and - /// `num_nominators / T::MaxNominatorRewardedPerValidator`. + /// `num_nominators / T::ExposurePageSize`. /// /// The origin of this call must be _Signed_. Any account can call this function, even if /// it is not one of the stakers. /// + /// This pays out the earliest exposure page not claimed for the era. If all pages are + /// claimed, it returns an error `InvalidPage`. + /// /// If a validator has more than `T::MaxNominatorRewardedPerValidator` nominators backing /// them, then the list of nominators is paged, with each page being capped at /// `T::MaxNominatorRewardedPerValidator`. If a validator has more than one page of @@ -1708,10 +1720,9 @@ pub mod pallet { origin: OriginFor, validator_stash: T::AccountId, era: EraIndex, - page: PageIndex, ) -> DispatchResultWithPostInfo { ensure_signed(origin)?; - Self::do_payout_stakers(validator_stash, era, page) + Self::do_payout_stakers(validator_stash, era) } /// Rebond a portion of the stash scheduled to be unlocked. @@ -2045,7 +2056,7 @@ pub mod pallet { page: PageIndex, ) -> DispatchResultWithPostInfo { ensure_signed(origin)?; - Self::do_payout_stakers(validator_stash, era, page) + Self::do_payout_stakers_by_page(validator_stash, era, page) } } } diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index 307c3996a82b6..073c6fffc0f6a 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -2207,7 +2207,7 @@ fn reward_validator_slashing_validator_does_not_overflow() { ErasStakers::::insert(0, 11, &exposure); ErasStakersOverview::::insert(0, 11, exposure_overview); ErasValidatorReward::::insert(0, stake); - assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, 0, 0)); + assert_ok!(Staking::payout_stakers_by_page(RuntimeOrigin::signed(1337), 11, 0, 0)); assert_eq!(Balances::total_balance(&11), stake * 2); // Set staker @@ -3576,19 +3576,19 @@ fn claim_reward_at_the_last_era_and_no_double_claim_and_invalid_claim() { // Last kept is 1: assert!(current_era - HistoryDepth::get() == 1); assert_noop!( - Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, 0, 0), + Staking::payout_stakers_by_page(RuntimeOrigin::signed(1337), 11, 0, 0), // Fail: Era out of history Error::::InvalidEraToReward.with_weight(err_weight) ); - assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, 1, 0)); - assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, 2, 0)); + assert_ok!(Staking::payout_stakers_by_page(RuntimeOrigin::signed(1337), 11, 1, 0)); + assert_ok!(Staking::payout_stakers_by_page(RuntimeOrigin::signed(1337), 11, 2, 0)); assert_noop!( - Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, 2, 0), + Staking::payout_stakers_by_page(RuntimeOrigin::signed(1337), 11, 2, 0), // Fail: Double claim Error::::AlreadyClaimed.with_weight(err_weight) ); assert_noop!( - Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, active_era, 0), + Staking::payout_stakers_by_page(RuntimeOrigin::signed(1337), 11, active_era, 0), // Fail: Era not finished yet Error::::InvalidEraToReward.with_weight(err_weight) ); @@ -3740,7 +3740,7 @@ fn test_nominators_are_rewarded_for_all_exposure_page() { } #[test] -fn test_multi_page_payout_stakers() { +fn test_multi_page_payout_stakers_by_page() { // Test that payout_stakers work in general and that it pays the correct amount of reward. ExtBuilder::default().has_stakers(false).build_and_execute(|| { let balance = 1000; @@ -3784,7 +3784,7 @@ fn test_multi_page_payout_stakers() { let controller_balance_before_p0_payout = Balances::free_balance(&10); // Payout rewards for first exposure page - assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, 1, 0)); + assert_ok!(Staking::payout_stakers_by_page(RuntimeOrigin::signed(1337), 11, 1, 0)); let controller_balance_after_p0_payout = Balances::free_balance(&10); @@ -3796,7 +3796,7 @@ fn test_multi_page_payout_stakers() { assert!(controller_balance_after_p0_payout > controller_balance_before_p0_payout); // Payout the second and last page of nominators - assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, 1, 1)); + assert_ok!(Staking::payout_stakers_by_page(RuntimeOrigin::signed(1337), 11, 1, 1)); // verify the validator was not rewarded the second time assert_eq!(Balances::free_balance(&10), controller_balance_after_p0_payout); @@ -3883,7 +3883,7 @@ fn test_multi_page_payout_stakers() { } // verify only page 0 is marked as claimed - assert_ok!(Staking::payout_stakers( + assert_ok!(Staking::payout_stakers_by_page( RuntimeOrigin::signed(1337), 11, first_claimable_reward_era, @@ -3892,7 +3892,7 @@ fn test_multi_page_payout_stakers() { assert_eq!(Staking::claimed_rewards(first_claimable_reward_era, &11), vec![0]); // verify page 0 and 1 are marked as claimed - assert_ok!(Staking::payout_stakers( + assert_ok!(Staking::payout_stakers_by_page( RuntimeOrigin::signed(1337), 11, first_claimable_reward_era, @@ -3901,19 +3901,19 @@ fn test_multi_page_payout_stakers() { assert_eq!(Staking::claimed_rewards(first_claimable_reward_era, &11), vec![0, 1]); // verify only page 0 is marked as claimed - assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, last_reward_era, 0)); + assert_ok!(Staking::payout_stakers_by_page(RuntimeOrigin::signed(1337), 11, last_reward_era, 0)); assert_eq!(Staking::claimed_rewards(last_reward_era, &11), vec![0]); // verify page 0 and 1 are marked as claimed - assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, last_reward_era, 1)); + assert_ok!(Staking::payout_stakers_by_page(RuntimeOrigin::signed(1337), 11, last_reward_era, 1)); assert_eq!(Staking::claimed_rewards(last_reward_era, &11), vec![0, 1]); // Out of order claims works. - assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, 69, 0)); + assert_ok!(Staking::payout_stakers_by_page(RuntimeOrigin::signed(1337), 11, 69, 0)); assert_eq!(Staking::claimed_rewards(69, &11), vec![0]); - assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, 23, 1)); + assert_ok!(Staking::payout_stakers_by_page(RuntimeOrigin::signed(1337), 11, 23, 1)); assert_eq!(Staking::claimed_rewards(23, &11), vec![1]); - assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, 42, 0)); + assert_ok!(Staking::payout_stakers_by_page(RuntimeOrigin::signed(1337), 11, 42, 0)); assert_eq!(Staking::claimed_rewards(42, &11), vec![0]); }); } @@ -3944,12 +3944,12 @@ fn payout_stakers_handles_basic_errors() { // Wrong Era, too big assert_noop!( - Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, 2, 0), + Staking::payout_stakers_by_page(RuntimeOrigin::signed(1337), 11, 2, 0), Error::::InvalidEraToReward.with_weight(err_weight) ); // Wrong Staker assert_noop!( - Staking::payout_stakers(RuntimeOrigin::signed(1337), 10, 1, 0), + Staking::payout_stakers_by_page(RuntimeOrigin::signed(1337), 10, 1, 0), Error::::NotStash.with_weight(err_weight) ); @@ -3969,7 +3969,7 @@ fn payout_stakers_handles_basic_errors() { // to payout era starting from expected_start_reward_era=19 through // expected_last_reward_era=98 (80 total eras), but not 18 or 99. assert_noop!( - Staking::payout_stakers( + Staking::payout_stakers_by_page( RuntimeOrigin::signed(1337), 11, expected_start_reward_era - 1, @@ -3978,7 +3978,7 @@ fn payout_stakers_handles_basic_errors() { Error::::InvalidEraToReward.with_weight(err_weight) ); assert_noop!( - Staking::payout_stakers( + Staking::payout_stakers_by_page( RuntimeOrigin::signed(1337), 11, expected_last_reward_era + 1, @@ -3986,13 +3986,13 @@ fn payout_stakers_handles_basic_errors() { ), Error::::InvalidEraToReward.with_weight(err_weight) ); - assert_ok!(Staking::payout_stakers( + assert_ok!(Staking::payout_stakers_by_page( RuntimeOrigin::signed(1337), 11, expected_start_reward_era, 0 )); - assert_ok!(Staking::payout_stakers( + assert_ok!(Staking::payout_stakers_by_page( RuntimeOrigin::signed(1337), 11, expected_last_reward_era, @@ -4000,7 +4000,7 @@ fn payout_stakers_handles_basic_errors() { )); // can call page 1 - assert_ok!(Staking::payout_stakers( + assert_ok!(Staking::payout_stakers_by_page( RuntimeOrigin::signed(1337), 11, expected_last_reward_era, @@ -4009,23 +4009,23 @@ fn payout_stakers_handles_basic_errors() { // Can't claim again assert_noop!( - Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, expected_start_reward_era, 0), + Staking::payout_stakers_by_page(RuntimeOrigin::signed(1337), 11, expected_start_reward_era, 0), Error::::AlreadyClaimed.with_weight(err_weight) ); assert_noop!( - Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, expected_last_reward_era, 0), + Staking::payout_stakers_by_page(RuntimeOrigin::signed(1337), 11, expected_last_reward_era, 0), Error::::AlreadyClaimed.with_weight(err_weight) ); assert_noop!( - Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, expected_last_reward_era, 1), + Staking::payout_stakers_by_page(RuntimeOrigin::signed(1337), 11, expected_last_reward_era, 1), Error::::AlreadyClaimed.with_weight(err_weight) ); // invalid page assert_noop!( - Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, expected_last_reward_era, 2), + Staking::payout_stakers_by_page(RuntimeOrigin::signed(1337), 11, expected_last_reward_era, 2), Error::::InvalidPage.with_weight(err_weight) ); }); @@ -4063,7 +4063,7 @@ fn test_commission_paid_only_once() { let controller_balance_before_p0_payout = Balances::free_balance(&10); // Payout rewards for first exposure page - assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, 1, 0)); + assert_ok!(Staking::payout_stakers_by_page(RuntimeOrigin::signed(1337), 11, 1, 0)); let controller_balance_after_p0_payout = Balances::free_balance(&10); @@ -4075,7 +4075,7 @@ fn test_commission_paid_only_once() { ); for i in 1..4 { - assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, 1, i)); + assert_ok!(Staking::payout_stakers_by_page(RuntimeOrigin::signed(1337), 11, 1, i)); // no reward paid to validator for pages other than 0 Balances::free_balance(&10); } @@ -4124,7 +4124,7 @@ fn payout_stakers_handles_weight_refund() { // Collect payouts when there are no nominators let call = - TestCall::Staking(StakingCall::payout_stakers { validator_stash: 11, era: 1, page: 0 }); + TestCall::Staking(StakingCall::payout_stakers_by_page { validator_stash: 11, era: 1, page: 0 }); let info = call.get_dispatch_info(); let result = call.dispatch(RuntimeOrigin::signed(20)); assert_ok!(result); @@ -4138,7 +4138,7 @@ fn payout_stakers_handles_weight_refund() { // Collect payouts for an era where the validator did not receive any points. let call = - TestCall::Staking(StakingCall::payout_stakers { validator_stash: 11, era: 2, page: 0 }); + TestCall::Staking(StakingCall::payout_stakers_by_page { validator_stash: 11, era: 2, page: 0 }); let info = call.get_dispatch_info(); let result = call.dispatch(RuntimeOrigin::signed(20)); assert_ok!(result); @@ -4152,7 +4152,7 @@ fn payout_stakers_handles_weight_refund() { // Collect payouts when the validator has `half_max_nom_rewarded` nominators. let call = - TestCall::Staking(StakingCall::payout_stakers { validator_stash: 11, era: 3, page: 0 }); + TestCall::Staking(StakingCall::payout_stakers_by_page { validator_stash: 11, era: 3, page: 0 }); let info = call.get_dispatch_info(); let result = call.dispatch(RuntimeOrigin::signed(20)); assert_ok!(result); @@ -4176,7 +4176,7 @@ fn payout_stakers_handles_weight_refund() { // Collect payouts when the validator had `half_max_nom_rewarded` nominators. let call = - TestCall::Staking(StakingCall::payout_stakers { validator_stash: 11, era: 5, page: 0 }); + TestCall::Staking(StakingCall::payout_stakers_by_page { validator_stash: 11, era: 5, page: 0 }); let info = call.get_dispatch_info(); let result = call.dispatch(RuntimeOrigin::signed(20)); assert_ok!(result); @@ -4184,7 +4184,7 @@ fn payout_stakers_handles_weight_refund() { // Try and collect payouts for an era that has already been collected. let call = - TestCall::Staking(StakingCall::payout_stakers { validator_stash: 11, era: 5, page: 0 }); + TestCall::Staking(StakingCall::payout_stakers_by_page { validator_stash: 11, era: 5, page: 0 }); let info = call.get_dispatch_info(); let result = call.dispatch(RuntimeOrigin::signed(20)); assert!(result.is_err()); @@ -4326,7 +4326,7 @@ fn payout_creates_controller() { // compute and ensure the reward amount is greater than zero. let _ = current_total_payout_for_duration(reward_time_per_era()); mock::start_active_era(2); - assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, 1, 0)); + assert_ok!(Staking::payout_stakers_by_page(RuntimeOrigin::signed(1337), 11, 1, 0)); // Controller is created assert!(Balances::free_balance(1337) > 0); @@ -4354,7 +4354,7 @@ fn payout_to_any_account_works() { // compute and ensure the reward amount is greater than zero. let _ = current_total_payout_for_duration(reward_time_per_era()); mock::start_active_era(2); - assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, 1, 0)); + assert_ok!(Staking::payout_stakers_by_page(RuntimeOrigin::signed(1337), 11, 1, 0)); // Payment is successful assert!(Balances::free_balance(42) > 0); @@ -5891,7 +5891,7 @@ fn test_legacy_claimed_rewards_is_checked_at_reward_payout() { // verify rewards for era 1 cannot be claimed assert_noop!( - Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, 1, 0), + Staking::payout_stakers_by_page(RuntimeOrigin::signed(1337), 11, 1, 0), Error::::AlreadyClaimed .with_weight(::WeightInfo::payout_stakers_alive_staked(0)), ); @@ -5906,7 +5906,7 @@ fn test_legacy_claimed_rewards_is_checked_at_reward_payout() { ); // verify rewards for era 2 can be claimed - assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, 2, 0)); + assert_ok!(Staking::payout_stakers_by_page(RuntimeOrigin::signed(1337), 11, 2, 0)); assert_eq!( EraInfo::::is_rewards_claimed_temp( 2, @@ -6018,10 +6018,10 @@ fn test_validator_exposure_is_backward_compatible_with_non_paged_rewards_payout( assert_eq!(EraInfo::::get_page_count(1, &11), 1); // payout for page 0 works - assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, 0, 0)); + assert_ok!(Staking::payout_stakers_by_page(RuntimeOrigin::signed(1337), 11, 0, 0)); // payout for page 1 fails assert_noop!( - Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, 0, 1), + Staking::payout_stakers_by_page(RuntimeOrigin::signed(1337), 11, 0, 1), Error::::InvalidPage .with_weight(::WeightInfo::payout_stakers_alive_staked(0)) ); From 50690ffb3cc0a2db9e0b1a78c579cfb6dcde57f2 Mon Sep 17 00:00:00 2001 From: Ankan Date: Sun, 5 Feb 2023 18:42:09 +0100 Subject: [PATCH 091/162] fix benchmark --- frame/staking/src/benchmarking.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/frame/staking/src/benchmarking.rs b/frame/staking/src/benchmarking.rs index 9d492fad5e9c2..d7b62dff86868 100644 --- a/frame/staking/src/benchmarking.rs +++ b/frame/staking/src/benchmarking.rs @@ -565,7 +565,7 @@ benchmarks! { let balance = T::Currency::free_balance(controller); ensure!(balance.is_zero(), "Controller has balance, but should be dead."); } - }: payout_stakers(RawOrigin::Signed(caller), validator, current_era, 0) + }: payout_stakers_by_page(RawOrigin::Signed(caller), validator, current_era, 0) verify { let balance_after = T::Currency::free_balance(&validator_controller); ensure!( @@ -598,7 +598,7 @@ benchmarks! { let balance = T::Currency::free_balance(stash); nominator_balances_before.push(balance); } - }: payout_stakers(RawOrigin::Signed(caller), validator.clone(), current_era, 0) + }: payout_stakers_by_page(RawOrigin::Signed(caller), validator.clone(), current_era, 0) verify { let balance_after = T::Currency::free_balance(&validator); ensure!( @@ -639,7 +639,7 @@ benchmarks! { nominator_balances_before.push(balance); } - }: payout_stakers(RawOrigin::Signed(caller), validator.clone(), current_era, 1) + }: payout_stakers_by_page(RawOrigin::Signed(caller), validator.clone(), current_era, 1) verify { let balance_after = T::Currency::free_balance(&validator); @@ -803,7 +803,7 @@ benchmarks! { let caller: T::AccountId = whitelisted_caller(); let origin = RawOrigin::Signed(caller); let calls: Vec<_> = payout_calls_arg.iter().map(|arg| - Call::::payout_stakers { validator_stash: arg.0.clone(), era: arg.1, page: 0 }.encode() + Call::::payout_stakers_by_page { validator_stash: arg.0.clone(), era: arg.1, page: 0 }.encode() ).collect(); }: { for call in calls { @@ -1036,7 +1036,7 @@ mod tests { let current_era = CurrentEra::::get().unwrap(); let original_free_balance = Balances::free_balance(&validator_stash); - assert_ok!(Staking::payout_stakers( + assert_ok!(Staking::payout_stakers_by_page( RuntimeOrigin::signed(1337), validator_stash, current_era, From 664c374986951d84ec01e98e7c7b5f3d6428cccb Mon Sep 17 00:00:00 2001 From: Ankan Date: Sun, 5 Feb 2023 19:21:40 +0100 Subject: [PATCH 092/162] keep payout_stakers backward compatible --- frame/staking/src/pallet/impls.rs | 61 ++++++------------------------- frame/staking/src/pallet/mod.rs | 37 +++++++++++++++++++ 2 files changed, 48 insertions(+), 50 deletions(-) diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index 253a1e97f372b..835778a7c71c7 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -131,60 +131,21 @@ impl Pallet { Ok(used_weight) } - fn validate_payout_stakers( - validator_stash: T::AccountId, - era: EraIndex, - ) -> Result<(), Error> { - // Validate input data - let current_era = CurrentEra::::get().ok_or_else(|| { - Error::::InvalidEraToReward - })?; - - let history_depth = T::HistoryDepth::get(); - ensure!( - era <= current_era && era >= current_era.saturating_sub(history_depth), - Error::::InvalidEraToReward - ); - - // ensure!( - // page < EraInfo::::get_page_count(era, &validator_stash), - // Error::::InvalidPage.with_weight(T::WeightInfo::payout_stakers_alive_staked(0)) - // ); - - // Note: if era has no reward to be claimed, era may be future. better not to update - // `ledger.legacy_claimed_rewards` in this case. - let era_payout = >::get(&era).ok_or_else(|| { - Error::::InvalidEraToReward - })?; - - let controller = Self::bonded(&validator_stash).ok_or_else(|| { - Error::::NotStash - })?; - let mut ledger = >::get(&controller).ok_or(Error::::NotController)?; - - // // clean up legacy claimed rewards - ledger - .legacy_claimed_rewards - .retain(|&x| x >= current_era.saturating_sub(history_depth)); - >::insert(&controller, &ledger); - - // if EraInfo::::is_rewards_claimed_temp(era, &ledger, &ledger.stash, page) { - // Error::::AlreadyClaimed - // .with_weight(T::WeightInfo::payout_stakers_alive_staked(0)) - // } - - - Ok(()) - } - - - pub(super) fn do_payout_stakers( validator_stash: T::AccountId, era: EraIndex, ) -> DispatchResultWithPostInfo { - EraInfo::::get_page_count(era, &validator_stash); - Self::do_payout_stakers_by_page(validator_stash, era, 0) + let controller = Self::bonded(&validator_stash).ok_or_else(|| { + Error::::NotStash.with_weight(T::WeightInfo::payout_stakers_alive_staked(0)) + })?; + let ledger = >::get(&controller).ok_or(Error::::NotController)?; + let page = EraInfo::::get_next_claimable_page(era, &validator_stash, &ledger) + .ok_or_else(|| { + Error::::AlreadyClaimed + .with_weight(T::WeightInfo::payout_stakers_alive_staked(0)) + })?; + + Self::do_payout_stakers_by_page(validator_stash, era, page) } pub(super) fn do_payout_stakers_by_page( diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index 2031993aea82e..5baab36a910a3 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -701,6 +701,43 @@ pub mod pallet { >::get(&era, validator).page_count.max(1) } + /// Returns the next page that can be claimed or `None` if nothing to claim. + // TODO(ank4n): Test and refactor + pub(crate) fn get_next_claimable_page( + era: EraIndex, + validator: &T::AccountId, + ledger: &StakingLedger, + ) -> Option { + if Self::is_non_paged_exposure(era, validator) { + return match ledger.legacy_claimed_rewards.binary_search(&era) { + // already claimed + Ok(_) => None, + // Non-paged exposure is considered as a single page + Err(_) => Some(0), + } + } + + // Find next claimable page of paged exposure. + let page_count = Self::get_page_count(era, validator); + let claimed_pages = ClaimedRewards::::get(era, validator); + let claimed_page_count = claimed_pages.len() as PageIndex; + + // find the first page that is not claimed. + for page in 0..claimed_page_count as PageIndex { + debug_assert!(page <= claimed_pages[page as usize]); + if page < claimed_pages[page as usize] { + return Some(page) + } + } + // all pages are claimed + return if claimed_page_count < page_count { Some(claimed_page_count) } else { None } + } + + /// Checks if exposure is paged or not. + fn is_non_paged_exposure(era: EraIndex, validator: &T::AccountId) -> bool { + >::contains_key(&era, validator) + } + /// Returns validator commission for this era and page. pub(crate) fn get_validator_commission( era: EraIndex, From bf412530effab3da81f47b98371224af237fcaff Mon Sep 17 00:00:00 2001 From: Ankan Date: Sun, 5 Feb 2023 20:05:01 +0100 Subject: [PATCH 093/162] split exposure by ExposurePageSize --- frame/staking/src/pallet/mod.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index 5baab36a910a3..c61fee5172811 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -779,9 +779,14 @@ pub mod pallet { exposure: Exposure>, ) { >::insert(era, &validator, &exposure); + // FIXME(ankan) Should we sort exposure.others for backward compatibility? + + let page_size = >::get() + .unwrap_or_else(|| T::MaxExposurePageSize::get()) + .clamp(1, T::MaxExposurePageSize::get()); let (exposure_overview, exposure_pages) = - exposure.into_pages(T::MaxNominatorRewardedPerValidator::get()); + exposure.into_pages(page_size); >::insert(era, &validator, &exposure_overview); exposure_pages.iter().enumerate().for_each(|(page, paged_exposure)| { From caeb7817ff28f5166a5f5373415d6431ee84fce4 Mon Sep 17 00:00:00 2001 From: Ankan Date: Sun, 5 Feb 2023 23:26:37 +0100 Subject: [PATCH 094/162] return both overview and page --- frame/staking/src/pallet/impls.rs | 8 +-- frame/staking/src/pallet/mod.rs | 29 +++++++-- frame/staking/src/tests.rs | 100 ++++++++++++++++++++++-------- 3 files changed, 102 insertions(+), 35 deletions(-) diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index 835778a7c71c7..b0ab97e7c59e9 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -205,7 +205,7 @@ impl Pallet { // Then look at the validator, figure out the proportion of their reward // which goes to them and each of their nominators. - let exposure = EraInfo::::get_validator_exposure(era, &ledger.stash, page); + let (exposure_overview, exposure_page) = EraInfo::::get_validator_exposure(era, &ledger.stash, page); let era_reward_points = >::get(&era); let total_reward_points = era_reward_points.total; let validator_reward_points = era_reward_points @@ -232,7 +232,7 @@ impl Pallet { let validator_leftover_payout = validator_total_payout - validator_commission_payout; // Now let's calculate how this is split to the validator. - let validator_exposure_part = Perbill::from_rational(exposure.own, exposure.total); + let validator_exposure_part = Perbill::from_rational(exposure_overview.own, exposure_overview.total); let validator_staking_payout = validator_exposure_part * validator_leftover_payout; Self::deposit_event(Event::::PayoutStarted { @@ -259,8 +259,8 @@ impl Pallet { // Lets now calculate how this is split to the nominators. // Reward only the clipped exposures. Note this is not necessarily sorted. - for nominator in exposure.others.iter() { - let nominator_exposure_part = Perbill::from_rational(nominator.value, exposure.total); + for nominator in exposure_page.others.iter() { + let nominator_exposure_part = Perbill::from_rational(nominator.value, exposure_overview.total); let nominator_reward: BalanceOf = nominator_exposure_part * validator_leftover_payout; diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index c61fee5172811..0c878586e41c2 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -679,20 +679,40 @@ pub mod pallet { era: EraIndex, validator: &T::AccountId, page: PageIndex, - ) -> Exposure> { + ) -> (ExposureOverview>, ExposurePage>) { return match >::get(era, (validator, page)) { // only return clipped exposure if page zero and no paged exposure entry - None if page == 0 => >::get(&era, validator), + None if page == 0 => Self::get_clipped_exposure_as_page(era, validator), Some(exposure_page) => { let overview = >::get(&era, validator); // own stake is included only once in the first page. let own = if page == 0 { overview.own } else { Zero::zero() }; - Exposure { total: overview.total, own, others: exposure_page.others } + (ExposureOverview { + own, + ..overview + }, exposure_page) }, _ => Default::default(), } } + /// Get clipped exposure and convert it as `ExposurePage`. + fn get_clipped_exposure_as_page( + era: EraIndex, + validator: &T::AccountId, + ) -> (ExposureOverview>, ExposurePage>) { + let exposure = >::get(&era, validator); + ( + ExposureOverview { + total: exposure.total, + own: exposure.own, + nominator_count: exposure.others.len() as u32, + page_count: 1, + }, + ExposurePage { page_total: exposure.total, others: exposure.others }, + ) + } + /// Returns the number of pages of exposure a validator has for the given era. /// /// This will always return at minimum one count of exposure to be backward compatible to @@ -785,8 +805,7 @@ pub mod pallet { .unwrap_or_else(|| T::MaxExposurePageSize::get()) .clamp(1, T::MaxExposurePageSize::get()); - let (exposure_overview, exposure_pages) = - exposure.into_pages(page_size); + let (exposure_overview, exposure_pages) = exposure.into_pages(page_size); >::insert(era, &validator, &exposure_overview); exposure_pages.iter().enumerate().for_each(|(page, paged_exposure)| { diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index 073c6fffc0f6a..4025787df3213 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -3770,14 +3770,14 @@ fn test_multi_page_payout_stakers_by_page() { // verify the exposures are calculated correctly. let actual_exposure_0 = EraInfo::::get_validator_exposure(1, &11, 0); - assert_eq!(actual_exposure_0.total, total_exposure); - assert_eq!(actual_exposure_0.own, 1000); - assert_eq!(actual_exposure_0.others.len(), 64); + assert_eq!(actual_exposure_0.0.total, total_exposure); + assert_eq!(actual_exposure_0.0.own, 1000); + assert_eq!(actual_exposure_0.1.others.len(), 64); let actual_exposure_1 = EraInfo::::get_validator_exposure(1, &11, 1); - assert_eq!(actual_exposure_1.total, total_exposure); + assert_eq!(actual_exposure_1.0.total, total_exposure); // own stake is only included once in the first page - assert_eq!(actual_exposure_1.own, 0); - assert_eq!(actual_exposure_1.others.len(), 100 - 64); + assert_eq!(actual_exposure_1.0.own, 0); + assert_eq!(actual_exposure_1.1.others.len(), 100 - 64); let pre_payout_total_issuance = Balances::total_issuance(); RewardOnUnbalanceWasCalled::set(false); @@ -3901,11 +3901,21 @@ fn test_multi_page_payout_stakers_by_page() { assert_eq!(Staking::claimed_rewards(first_claimable_reward_era, &11), vec![0, 1]); // verify only page 0 is marked as claimed - assert_ok!(Staking::payout_stakers_by_page(RuntimeOrigin::signed(1337), 11, last_reward_era, 0)); + assert_ok!(Staking::payout_stakers_by_page( + RuntimeOrigin::signed(1337), + 11, + last_reward_era, + 0 + )); assert_eq!(Staking::claimed_rewards(last_reward_era, &11), vec![0]); // verify page 0 and 1 are marked as claimed - assert_ok!(Staking::payout_stakers_by_page(RuntimeOrigin::signed(1337), 11, last_reward_era, 1)); + assert_ok!(Staking::payout_stakers_by_page( + RuntimeOrigin::signed(1337), + 11, + last_reward_era, + 1 + )); assert_eq!(Staking::claimed_rewards(last_reward_era, &11), vec![0, 1]); // Out of order claims works. @@ -4009,23 +4019,43 @@ fn payout_stakers_handles_basic_errors() { // Can't claim again assert_noop!( - Staking::payout_stakers_by_page(RuntimeOrigin::signed(1337), 11, expected_start_reward_era, 0), + Staking::payout_stakers_by_page( + RuntimeOrigin::signed(1337), + 11, + expected_start_reward_era, + 0 + ), Error::::AlreadyClaimed.with_weight(err_weight) ); assert_noop!( - Staking::payout_stakers_by_page(RuntimeOrigin::signed(1337), 11, expected_last_reward_era, 0), + Staking::payout_stakers_by_page( + RuntimeOrigin::signed(1337), + 11, + expected_last_reward_era, + 0 + ), Error::::AlreadyClaimed.with_weight(err_weight) ); assert_noop!( - Staking::payout_stakers_by_page(RuntimeOrigin::signed(1337), 11, expected_last_reward_era, 1), + Staking::payout_stakers_by_page( + RuntimeOrigin::signed(1337), + 11, + expected_last_reward_era, + 1 + ), Error::::AlreadyClaimed.with_weight(err_weight) ); // invalid page assert_noop!( - Staking::payout_stakers_by_page(RuntimeOrigin::signed(1337), 11, expected_last_reward_era, 2), + Staking::payout_stakers_by_page( + RuntimeOrigin::signed(1337), + 11, + expected_last_reward_era, + 2 + ), Error::::InvalidPage.with_weight(err_weight) ); }); @@ -4123,8 +4153,11 @@ fn payout_stakers_handles_weight_refund() { start_active_era(2); // Collect payouts when there are no nominators - let call = - TestCall::Staking(StakingCall::payout_stakers_by_page { validator_stash: 11, era: 1, page: 0 }); + let call = TestCall::Staking(StakingCall::payout_stakers_by_page { + validator_stash: 11, + era: 1, + page: 0, + }); let info = call.get_dispatch_info(); let result = call.dispatch(RuntimeOrigin::signed(20)); assert_ok!(result); @@ -4137,8 +4170,11 @@ fn payout_stakers_handles_weight_refund() { start_active_era(3); // Collect payouts for an era where the validator did not receive any points. - let call = - TestCall::Staking(StakingCall::payout_stakers_by_page { validator_stash: 11, era: 2, page: 0 }); + let call = TestCall::Staking(StakingCall::payout_stakers_by_page { + validator_stash: 11, + era: 2, + page: 0, + }); let info = call.get_dispatch_info(); let result = call.dispatch(RuntimeOrigin::signed(20)); assert_ok!(result); @@ -4151,8 +4187,11 @@ fn payout_stakers_handles_weight_refund() { start_active_era(4); // Collect payouts when the validator has `half_max_nom_rewarded` nominators. - let call = - TestCall::Staking(StakingCall::payout_stakers_by_page { validator_stash: 11, era: 3, page: 0 }); + let call = TestCall::Staking(StakingCall::payout_stakers_by_page { + validator_stash: 11, + era: 3, + page: 0, + }); let info = call.get_dispatch_info(); let result = call.dispatch(RuntimeOrigin::signed(20)); assert_ok!(result); @@ -4175,16 +4214,22 @@ fn payout_stakers_handles_weight_refund() { start_active_era(6); // Collect payouts when the validator had `half_max_nom_rewarded` nominators. - let call = - TestCall::Staking(StakingCall::payout_stakers_by_page { validator_stash: 11, era: 5, page: 0 }); + let call = TestCall::Staking(StakingCall::payout_stakers_by_page { + validator_stash: 11, + era: 5, + page: 0, + }); let info = call.get_dispatch_info(); let result = call.dispatch(RuntimeOrigin::signed(20)); assert_ok!(result); assert_eq!(extract_actual_weight(&result, &info), max_nom_rewarded_weight); // Try and collect payouts for an era that has already been collected. - let call = - TestCall::Staking(StakingCall::payout_stakers_by_page { validator_stash: 11, era: 5, page: 0 }); + let call = TestCall::Staking(StakingCall::payout_stakers_by_page { + validator_stash: 11, + era: 5, + page: 0, + }); let info = call.get_dispatch_info(); let result = call.dispatch(RuntimeOrigin::signed(20)); assert!(result.is_err()); @@ -5980,11 +6025,11 @@ fn test_validator_exposure_is_backward_compatible_with_non_paged_rewards_payout( ); // verify `EraInfo` returns page from paged storage assert_eq!( - EraInfo::::get_validator_exposure(1, &11, 0).others, + EraInfo::::get_validator_exposure(1, &11, 0).1.others, actual_exposure_page_0.others ); assert_eq!( - EraInfo::::get_validator_exposure(1, &11, 1).others, + EraInfo::::get_validator_exposure(1, &11, 1).1.others, actual_exposure_page_1.others ); assert_eq!(EraInfo::::get_page_count(1, &11), 2); @@ -6006,11 +6051,14 @@ fn test_validator_exposure_is_backward_compatible_with_non_paged_rewards_payout( // verify `EraInfo` returns exposure from clipped storage assert!(matches!( EraInfo::::get_validator_exposure(1, &11, 0), - Exposure { + (ExposureOverview { own, + page_count, + .. + }, ExposurePage { others, .. - } if others == clipped_exposure && own == 1000)); + }) if others == clipped_exposure && own == 1000 && page_count == 1)); // for pages other than 0, clipped storage returns empty exposure assert_eq!(EraInfo::::get_validator_exposure(1, &11, 1), Default::default()); From 3b9acbf993a16fa32b933148c15fb9c393c3da9d Mon Sep 17 00:00:00 2001 From: Ankan Date: Sun, 5 Feb 2023 23:34:30 +0100 Subject: [PATCH 095/162] fmt --- frame/staking/src/pallet/impls.rs | 9 ++++++--- frame/staking/src/pallet/mod.rs | 5 +---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index b0ab97e7c59e9..247e43de755d2 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -205,7 +205,8 @@ impl Pallet { // Then look at the validator, figure out the proportion of their reward // which goes to them and each of their nominators. - let (exposure_overview, exposure_page) = EraInfo::::get_validator_exposure(era, &ledger.stash, page); + let (exposure_overview, exposure_page) = + EraInfo::::get_validator_exposure(era, &ledger.stash, page); let era_reward_points = >::get(&era); let total_reward_points = era_reward_points.total; let validator_reward_points = era_reward_points @@ -232,7 +233,8 @@ impl Pallet { let validator_leftover_payout = validator_total_payout - validator_commission_payout; // Now let's calculate how this is split to the validator. - let validator_exposure_part = Perbill::from_rational(exposure_overview.own, exposure_overview.total); + let validator_exposure_part = + Perbill::from_rational(exposure_overview.own, exposure_overview.total); let validator_staking_payout = validator_exposure_part * validator_leftover_payout; Self::deposit_event(Event::::PayoutStarted { @@ -260,7 +262,8 @@ impl Pallet { // Lets now calculate how this is split to the nominators. // Reward only the clipped exposures. Note this is not necessarily sorted. for nominator in exposure_page.others.iter() { - let nominator_exposure_part = Perbill::from_rational(nominator.value, exposure_overview.total); + let nominator_exposure_part = + Perbill::from_rational(nominator.value, exposure_overview.total); let nominator_reward: BalanceOf = nominator_exposure_part * validator_leftover_payout; diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index 0c878586e41c2..eae444f00a6f1 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -687,10 +687,7 @@ pub mod pallet { let overview = >::get(&era, validator); // own stake is included only once in the first page. let own = if page == 0 { overview.own } else { Zero::zero() }; - (ExposureOverview { - own, - ..overview - }, exposure_page) + (ExposureOverview { own, ..overview }, exposure_page) }, _ => Default::default(), } From 9ab601aa1ec980b3a0c4249070bb0c8ff0eb6623 Mon Sep 17 00:00:00 2001 From: Ankan <10196091+Ank4n@users.noreply.github.com> Date: Mon, 6 Feb 2023 10:47:38 +0100 Subject: [PATCH 096/162] Update frame/staking/README.md Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> --- frame/staking/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frame/staking/README.md b/frame/staking/README.md index 2958ecf8dc2fb..043dc2088c0c1 100644 --- a/frame/staking/README.md +++ b/frame/staking/README.md @@ -88,7 +88,7 @@ An account can become a nominator via the [`nominate`](https://docs.rs/pallet-st The **reward and slashing** procedure is the core of the Staking module, attempting to _embrace 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 +Rewards must be claimed for each era before it gets too old by [`HistoryDeth`] using the `payout_stakers` call. Any account can call `payout_stakers`, which pays the reward to the validator as well as its nominators. Rewards are paged to maximum of [`Config::MaxNominatorRewardedPerValidator`] nominators per call. Each page of staker payout needs to be called separately to ensure all nominators are From 7f24aa12274004c467ac48929406fd8008e6728f Mon Sep 17 00:00:00 2001 From: Ankan Date: Mon, 6 Feb 2023 21:51:12 +0100 Subject: [PATCH 097/162] introduce exposure extension --- frame/staking/src/lib.rs | 43 +++++++++++++++++++++++++++++++ frame/staking/src/pallet/impls.rs | 14 ++++++---- frame/staking/src/pallet/mod.rs | 36 ++++++++++---------------- frame/staking/src/tests.rs | 40 ++++++++++++---------------- 4 files changed, 82 insertions(+), 51 deletions(-) diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index 12fd67951256a..7f804e07d6bd2 100644 --- a/frame/staking/src/lib.rs +++ b/frame/staking/src/lib.rs @@ -817,6 +817,49 @@ impl Default for ExposureOverview { } } +#[derive(Encode, Decode, RuntimeDebug, TypeInfo, PartialEq, Eq)] +struct ExposureExt { + exposure_overview: ExposureOverview, + exposure_page: ExposurePage, +} + +impl ExposureExt { + pub fn from_clipped(exposure: Exposure) -> Self { + Self { + exposure_overview: ExposureOverview { + total: exposure.total, + own: exposure.own, + nominator_count: exposure.others.len() as u32, + page_count: 1, + }, + exposure_page: ExposurePage { page_total: exposure.total, others: exposure.others }, + } + } + pub fn total(&self) -> Balance { + self.exposure_overview.total + } + + pub fn own(&self) -> Balance { + self.exposure_overview.own + } + + pub fn nominator_count(&self) -> u32 { + self.exposure_overview.nominator_count + } + + pub fn page_count(&self) -> PageIndex { + self.exposure_overview.page_count + } + + pub fn page_total(&self) -> Balance { + self.exposure_page.page_total + } + + pub fn others(&self) -> &Vec> { + &self.exposure_page.others + } +} + /// A pending slash record. The value of the slash has been computed but not applied yet, /// rather deferred for several eras. #[derive(Encode, Decode, RuntimeDebug, TypeInfo)] diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index 247e43de755d2..375b01ec5f4d1 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -196,6 +196,12 @@ impl Pallet { EraInfo::::set_rewards_as_claimed(era, &ledger.stash, page); } + let exposure = + EraInfo::::get_validator_exposure(era, &ledger.stash, page).ok_or_else(|| { + Error::::InvalidEraToReward + .with_weight(T::WeightInfo::payout_stakers_alive_staked(0)) + })?; + // Input data seems good, no errors allowed after this point // Get Era reward points. It has TOTAL and INDIVIDUAL @@ -205,8 +211,6 @@ impl Pallet { // Then look at the validator, figure out the proportion of their reward // which goes to them and each of their nominators. - let (exposure_overview, exposure_page) = - EraInfo::::get_validator_exposure(era, &ledger.stash, page); let era_reward_points = >::get(&era); let total_reward_points = era_reward_points.total; let validator_reward_points = era_reward_points @@ -234,7 +238,7 @@ impl Pallet { let validator_leftover_payout = validator_total_payout - validator_commission_payout; // Now let's calculate how this is split to the validator. let validator_exposure_part = - Perbill::from_rational(exposure_overview.own, exposure_overview.total); + Perbill::from_rational(exposure.own(), exposure.total()); let validator_staking_payout = validator_exposure_part * validator_leftover_payout; Self::deposit_event(Event::::PayoutStarted { @@ -261,9 +265,9 @@ impl Pallet { // Lets now calculate how this is split to the nominators. // Reward only the clipped exposures. Note this is not necessarily sorted. - for nominator in exposure_page.others.iter() { + for nominator in exposure.others().iter() { let nominator_exposure_part = - Perbill::from_rational(nominator.value, exposure_overview.total); + Perbill::from_rational(nominator.value, exposure.total()); let nominator_reward: BalanceOf = nominator_exposure_part * validator_leftover_payout; diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index eae444f00a6f1..b7f4e0decfb8c 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -59,7 +59,7 @@ pub(crate) const SPECULATIVE_NUM_SPANS: u32 = 32; pub mod pallet { use frame_election_provider_support::ElectionDataProvider; - use crate::{BenchmarkingConfig, ExposureOverview}; + use crate::{BenchmarkingConfig, ExposureExt, ExposureOverview}; use super::*; @@ -679,35 +679,25 @@ pub mod pallet { era: EraIndex, validator: &T::AccountId, page: PageIndex, - ) -> (ExposureOverview>, ExposurePage>) { + ) -> Option>> { return match >::get(era, (validator, page)) { - // only return clipped exposure if page zero and no paged exposure entry - None if page == 0 => Self::get_clipped_exposure_as_page(era, validator), + // return clipped exposure if page zero and paged exposure does not exist + None if page == 0 => + Some(ExposureExt::from_clipped(>::get(era, validator))), + + // return paged exposure if it exists Some(exposure_page) => { let overview = >::get(&era, validator); // own stake is included only once in the first page. let own = if page == 0 { overview.own } else { Zero::zero() }; - (ExposureOverview { own, ..overview }, exposure_page) - }, - _ => Default::default(), - } - } - /// Get clipped exposure and convert it as `ExposurePage`. - fn get_clipped_exposure_as_page( - era: EraIndex, - validator: &T::AccountId, - ) -> (ExposureOverview>, ExposurePage>) { - let exposure = >::get(&era, validator); - ( - ExposureOverview { - total: exposure.total, - own: exposure.own, - nominator_count: exposure.others.len() as u32, - page_count: 1, + Some(ExposureExt { + exposure_overview: ExposureOverview { own, ..overview }, + exposure_page, + }) }, - ExposurePage { page_total: exposure.total, others: exposure.others }, - ) + _ => None, + } } /// Returns the number of pages of exposure a validator has for the given era. diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index 4025787df3213..04af407f06de1 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -3769,15 +3769,15 @@ fn test_multi_page_payout_stakers_by_page() { mock::start_active_era(2); // verify the exposures are calculated correctly. - let actual_exposure_0 = EraInfo::::get_validator_exposure(1, &11, 0); - assert_eq!(actual_exposure_0.0.total, total_exposure); - assert_eq!(actual_exposure_0.0.own, 1000); - assert_eq!(actual_exposure_0.1.others.len(), 64); - let actual_exposure_1 = EraInfo::::get_validator_exposure(1, &11, 1); - assert_eq!(actual_exposure_1.0.total, total_exposure); + let actual_exposure_0 = EraInfo::::get_validator_exposure(1, &11, 0).unwrap(); + assert_eq!(actual_exposure_0.total(), total_exposure); + assert_eq!(actual_exposure_0.own(), 1000); + assert_eq!(actual_exposure_0.others().len(), 64); + let actual_exposure_1 = EraInfo::::get_validator_exposure(1, &11, 1).unwrap(); + assert_eq!(actual_exposure_1.total(), total_exposure); // own stake is only included once in the first page - assert_eq!(actual_exposure_1.0.own, 0); - assert_eq!(actual_exposure_1.1.others.len(), 100 - 64); + assert_eq!(actual_exposure_1.own(), 0); + assert_eq!(actual_exposure_1.others().len(), 100 - 64); let pre_payout_total_issuance = Balances::total_issuance(); RewardOnUnbalanceWasCalled::set(false); @@ -6025,12 +6025,12 @@ fn test_validator_exposure_is_backward_compatible_with_non_paged_rewards_payout( ); // verify `EraInfo` returns page from paged storage assert_eq!( - EraInfo::::get_validator_exposure(1, &11, 0).1.others, - actual_exposure_page_0.others + EraInfo::::get_validator_exposure(1, &11, 0).unwrap().others(), + &actual_exposure_page_0.others ); assert_eq!( - EraInfo::::get_validator_exposure(1, &11, 1).1.others, - actual_exposure_page_1.others + EraInfo::::get_validator_exposure(1, &11, 1).unwrap().others(), + &actual_exposure_page_1.others ); assert_eq!(EraInfo::::get_page_count(1, &11), 2); @@ -6049,19 +6049,13 @@ fn test_validator_exposure_is_backward_compatible_with_non_paged_rewards_payout( ); // verify `EraInfo` returns exposure from clipped storage - assert!(matches!( - EraInfo::::get_validator_exposure(1, &11, 0), - (ExposureOverview { - own, - page_count, - .. - }, ExposurePage { - others, - .. - }) if others == clipped_exposure && own == 1000 && page_count == 1)); + let actual_exposure = EraInfo::::get_validator_exposure(1, &11, 0).unwrap(); + assert_eq!(actual_exposure.others(), &clipped_exposure); + assert_eq!(actual_exposure.own(), 1000); + assert_eq!(actual_exposure.page_count(), 1); // for pages other than 0, clipped storage returns empty exposure - assert_eq!(EraInfo::::get_validator_exposure(1, &11, 1), Default::default()); + assert_eq!(EraInfo::::get_validator_exposure(1, &11, 1), None); // page size is 1 for clipped storage assert_eq!(EraInfo::::get_page_count(1, &11), 1); From 1bf6161cffa08e5ced0e2c01a7c7c74f2722d2d7 Mon Sep 17 00:00:00 2001 From: Ankan Date: Mon, 6 Feb 2023 21:54:41 +0100 Subject: [PATCH 098/162] doc --- frame/staking/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index 7f804e07d6bd2..44db7a94923e5 100644 --- a/frame/staking/src/lib.rs +++ b/frame/staking/src/lib.rs @@ -817,6 +817,7 @@ impl Default for ExposureOverview { } } +/// Extended view of Exposure comprising of `ExposureOverview` and a single page of `ExposurePage`. #[derive(Encode, Decode, RuntimeDebug, TypeInfo, PartialEq, Eq)] struct ExposureExt { exposure_overview: ExposureOverview, From 21dff2012a6de66f4ab4a08f28d6dae95e191bfc Mon Sep 17 00:00:00 2001 From: Ankan Date: Mon, 6 Feb 2023 21:55:11 +0100 Subject: [PATCH 099/162] format --- frame/staking/src/pallet/impls.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index 375b01ec5f4d1..b386e34181383 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -237,8 +237,7 @@ impl Pallet { let validator_leftover_payout = validator_total_payout - validator_commission_payout; // Now let's calculate how this is split to the validator. - let validator_exposure_part = - Perbill::from_rational(exposure.own(), exposure.total()); + let validator_exposure_part = Perbill::from_rational(exposure.own(), exposure.total()); let validator_staking_payout = validator_exposure_part * validator_leftover_payout; Self::deposit_event(Event::::PayoutStarted { @@ -266,8 +265,7 @@ impl Pallet { // Lets now calculate how this is split to the nominators. // Reward only the clipped exposures. Note this is not necessarily sorted. for nominator in exposure.others().iter() { - let nominator_exposure_part = - Perbill::from_rational(nominator.value, exposure.total()); + let nominator_exposure_part = Perbill::from_rational(nominator.value, exposure.total()); let nominator_reward: BalanceOf = nominator_exposure_part * validator_leftover_payout; From 171d43b06841b6d55a98270443314b3f4792a1bf Mon Sep 17 00:00:00 2001 From: Ankan Date: Mon, 6 Feb 2023 22:12:26 +0100 Subject: [PATCH 100/162] pay commission in parts; failing tests --- frame/staking/src/pallet/impls.rs | 10 +++++++--- frame/staking/src/pallet/mod.rs | 6 ------ 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index b386e34181383..f27384e7779b8 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -232,13 +232,17 @@ impl Pallet { // This is how much validator + nominators are entitled to. let validator_total_payout = validator_total_reward_part * era_payout; - let validator_commission = EraInfo::::get_validator_commission(era, &ledger.stash, page); - let validator_commission_payout = validator_commission * validator_total_payout; + let validator_commission = EraInfo::::get_validator_commission(era, &ledger.stash); + // total commission validator takes across all nominator pages + let validator_total_commission_payout = validator_commission * validator_total_payout; - let validator_leftover_payout = validator_total_payout - validator_commission_payout; + let validator_leftover_payout = validator_total_payout - validator_total_commission_payout; // Now let's calculate how this is split to the validator. let validator_exposure_part = Perbill::from_rational(exposure.own(), exposure.total()); let validator_staking_payout = validator_exposure_part * validator_leftover_payout; + let page_stake_part = Perbill::from_rational(exposure.page_total(), exposure.total()); + // validator commission is paid out in fraction across pages proportional to the page stake. + let validator_commission_payout = page_stake_part * validator_total_commission_payout; Self::deposit_event(Event::::PayoutStarted { era_index: era, diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index b7f4e0decfb8c..265789beae0f6 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -749,13 +749,7 @@ pub mod pallet { pub(crate) fn get_validator_commission( era: EraIndex, validator_stash: &T::AccountId, - page: PageIndex, ) -> Perbill { - if page != 0 { - // commission is only paid in the first page - return Zero::zero() - } - >::get(&era, validator_stash).commission } From 263894be1070c00d5bc484c6af2ef3298b3b0862 Mon Sep 17 00:00:00 2001 From: Ankan Date: Mon, 6 Feb 2023 22:40:44 +0100 Subject: [PATCH 101/162] verify commission are paid across pages --- frame/staking/src/benchmarking.rs | 49 ------------------------------- frame/staking/src/lib.rs | 11 +++---- frame/staking/src/pallet/impls.rs | 14 ++++----- frame/staking/src/tests.rs | 25 +++++++++------- frame/staking/src/weights.rs | 46 +---------------------------- 5 files changed, 26 insertions(+), 119 deletions(-) diff --git a/frame/staking/src/benchmarking.rs b/frame/staking/src/benchmarking.rs index d7b62dff86868..86559861db3ae 100644 --- a/frame/staking/src/benchmarking.rs +++ b/frame/staking/src/benchmarking.rs @@ -614,55 +614,6 @@ benchmarks! { } } - payout_stakers_nominators_only { - let n in 1 .. T::MaxNominatorRewardedPerValidator::get() as u32; - // create nominators between MaxNominatorRewardedPerValidator+1 .. =2 * MaxNominatorRewardedPerValidator - let nominator_lower_bound = T::MaxNominatorRewardedPerValidator::get(); - let nominator_upper_bound = 2 * T::MaxNominatorRewardedPerValidator::get(); - - let (validator, nominators) = create_validator_with_nominators::( - nominator_lower_bound + n, - nominator_upper_bound as u32, - false, - RewardDestination::Staked, - )?; - - let current_era = CurrentEra::::get().unwrap(); - // set the commission for this particular era as well. - >::insert(current_era, validator.clone(), >::validators(&validator)); - - let caller = whitelisted_caller(); - let balance_before = T::Currency::free_balance(&validator); - let mut nominator_balances_before = Vec::new(); - for (stash, _) in &nominators { - let balance = T::Currency::free_balance(stash); - nominator_balances_before.push(balance); - } - - }: payout_stakers_by_page(RawOrigin::Signed(caller), validator.clone(), current_era, 1) - verify { - let balance_after = T::Currency::free_balance(&validator); - - ensure!( - balance_before == balance_after, - "Validator should not have received payout for pages other than 0.", - ); - - let mut nominator_payout_count = 0; - for ((stash, _), balance_before) in nominators.iter().zip(nominator_balances_before.iter()) { - let balance_after = T::Currency::free_balance(stash); - if balance_before < &balance_after { - nominator_payout_count += 1; - } - } - - ensure!( - nominator_payout_count == n, - "n nominators must have been paid.", - ); - } - - rebond { let l in 1 .. T::MaxUnlockingChunks::get() as u32; diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index 44db7a94923e5..4983d29db9028 100644 --- a/frame/staking/src/lib.rs +++ b/frame/staking/src/lib.rs @@ -824,7 +824,7 @@ struct ExposureExt { exposure_page: ExposurePage, } -impl ExposureExt { +impl ExposureExt { pub fn from_clipped(exposure: Exposure) -> Self { Self { exposure_overview: ExposureOverview { @@ -844,16 +844,13 @@ impl ExposureExt { self.exposure_overview.own } - pub fn nominator_count(&self) -> u32 { - self.exposure_overview.nominator_count - } - pub fn page_count(&self) -> PageIndex { self.exposure_overview.page_count } - pub fn page_total(&self) -> Balance { - self.exposure_page.page_total + // Returns the total stake of this page. + pub fn current_total(&self) -> Balance { + self.exposure_page.page_total + self.exposure_overview.own } pub fn others(&self) -> &Vec> { diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index f27384e7779b8..2f688d47af1a1 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -240,9 +240,13 @@ impl Pallet { // Now let's calculate how this is split to the validator. let validator_exposure_part = Perbill::from_rational(exposure.own(), exposure.total()); let validator_staking_payout = validator_exposure_part * validator_leftover_payout; - let page_stake_part = Perbill::from_rational(exposure.page_total(), exposure.total()); + let page_stake_part = Perbill::from_rational(exposure.current_total(), exposure.total()); // validator commission is paid out in fraction across pages proportional to the page stake. let validator_commission_payout = page_stake_part * validator_total_commission_payout; + println!( + "validator_commission_payout: {:?}, validator_total_commission_payout: {:?}, exposure_total: {:?}, exposure_page_total: {:?}, page_count: {:?}, own: {:?}", + validator_commission_payout, validator_total_commission_payout, exposure.total(), exposure.current_total(), exposure.page_count(), exposure.own() + ); Self::deposit_event(Event::::PayoutStarted { era_index: era, @@ -287,13 +291,7 @@ impl Pallet { T::Reward::on_unbalanced(total_imbalance); debug_assert!(nominator_payout_count <= T::MaxNominatorRewardedPerValidator::get()); - let payout_weight = if page == 0 { - T::WeightInfo::payout_stakers_alive_staked(nominator_payout_count) - } else { - T::WeightInfo::payout_stakers_nominators_only(nominator_payout_count) - }; - - Ok(Some(payout_weight).into()) + Ok(Some(T::WeightInfo::payout_stakers_alive_staked(nominator_payout_count)).into()) } /// Update the ledger for a controller. diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index 04af407f06de1..f071a547b0960 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -4062,7 +4062,7 @@ fn payout_stakers_handles_basic_errors() { } #[test] -fn test_commission_paid_only_once() { +fn test_commission_paid_across_pages() { ExtBuilder::default().has_stakers(false).build_and_execute(|| { let balance = 1; let commission = 50; @@ -4091,24 +4091,29 @@ fn test_commission_paid_only_once() { let payout = current_total_payout_for_duration(reward_time_per_era()); mock::start_active_era(2); - let controller_balance_before_p0_payout = Balances::free_balance(&10); + let initial_balance = Balances::free_balance(&10); // Payout rewards for first exposure page assert_ok!(Staking::payout_stakers_by_page(RuntimeOrigin::signed(1337), 11, 1, 0)); let controller_balance_after_p0_payout = Balances::free_balance(&10); - // half of the payout goes to validator since commission is 50% - assert_eq_error_rate!( - controller_balance_after_p0_payout, - controller_balance_before_p0_payout + payout / 2, - 1, - ); + // some commission is paid + assert!(initial_balance < controller_balance_after_p0_payout); + // payout all pages for i in 1..4 { + let before_balance = Balances::free_balance(&10); assert_ok!(Staking::payout_stakers_by_page(RuntimeOrigin::signed(1337), 11, 1, i)); - // no reward paid to validator for pages other than 0 - Balances::free_balance(&10); + let after_balance = Balances::free_balance(&10); + // some commission is paid for every page + assert!(before_balance < after_balance); } + + assert_eq_error_rate!( + Balances::free_balance(&10), + initial_balance + payout / 2, + 1, + ); }); } diff --git a/frame/staking/src/weights.rs b/frame/staking/src/weights.rs index dea9175460e0a..2a3b04d7c555f 100644 --- a/frame/staking/src/weights.rs +++ b/frame/staking/src/weights.rs @@ -68,7 +68,6 @@ pub trait WeightInfo { fn cancel_deferred_slash(s: u32, ) -> Weight; fn payout_stakers_dead_controller(n: u32, ) -> Weight; fn payout_stakers_alive_staked(n: u32, ) -> Weight; - fn payout_stakers_nominators_only(n: u32, ) -> Weight; fn rebond(l: u32, ) -> Weight; fn reap_stash(s: u32, ) -> Weight; fn new_era(v: u32, n: u32, ) -> Weight; @@ -349,28 +348,7 @@ impl WeightInfo for SubstrateWeight { .saturating_add(T::DbWeight::get().writes(4)) .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(n.into()))) } - // Storage: Staking CurrentEra (r:1 w:0) - // Storage: Staking ErasStakersOverview (r:1 w:0) - // Storage: Staking ErasValidatorReward (r:1 w:0) - // Storage: Staking Bonded (r:2 w:0) - // Storage: Staking Ledger (r:2 w:2) - // Storage: Staking ClaimedRewards (r:1 w:1) - // Storage: Staking ErasStakersPaged (r:1 w:0) - // Storage: Staking ErasRewardPoints (r:1 w:0) - // Storage: Staking Payee (r:2 w:0) - // Storage: Balances Locks (r:2 w:2) - // Storage: System Account (r:2 w:2) - /// The range of component `n` is `[1, 256]`. - fn payout_stakers_nominators_only(n: u32, ) -> Weight { - // Minimum execution time: 272_243 nanoseconds. - Weight::from_ref_time(228_003_618) - // Standard Error: 35_442 - .saturating_add(Weight::from_ref_time(34_057_392).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(11)) - .saturating_add(T::DbWeight::get().reads((5_u64).saturating_mul(n.into()))) - .saturating_add(T::DbWeight::get().writes(4)) - .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(n.into()))) - } + // Storage: Staking Ledger (r:1 w:1) // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) @@ -796,28 +774,6 @@ impl WeightInfo for () { .saturating_add(RocksDbWeight::get().writes(4)) .saturating_add(RocksDbWeight::get().writes((3_u64).saturating_mul(n.into()))) } - // Storage: Staking CurrentEra (r:1 w:0) - // Storage: Staking ErasStakersOverview (r:1 w:0) - // Storage: Staking ErasValidatorReward (r:1 w:0) - // Storage: Staking Bonded (r:2 w:0) - // Storage: Staking Ledger (r:2 w:2) - // Storage: Staking ClaimedRewards (r:1 w:1) - // Storage: Staking ErasStakersPaged (r:1 w:0) - // Storage: Staking ErasRewardPoints (r:1 w:0) - // Storage: Staking Payee (r:2 w:0) - // Storage: Balances Locks (r:2 w:2) - // Storage: System Account (r:2 w:2) - /// The range of component `n` is `[1, 256]`. - fn payout_stakers_nominators_only(n: u32, ) -> Weight { - // Minimum execution time: 272_243 nanoseconds. - Weight::from_ref_time(228_003_618) - // Standard Error: 35_442 - .saturating_add(Weight::from_ref_time(34_057_392).saturating_mul(n.into())) - .saturating_add(RocksDbWeight::get().reads(11)) - .saturating_add(RocksDbWeight::get().reads((5_u64).saturating_mul(n.into()))) - .saturating_add(RocksDbWeight::get().writes(4)) - .saturating_add(RocksDbWeight::get().writes((3_u64).saturating_mul(n.into()))) - } // Storage: Staking Ledger (r:1 w:1) // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) From 78f94bc2ca1455a16bbf52bf0c4f717a776b070c Mon Sep 17 00:00:00 2001 From: Ankan Date: Mon, 6 Feb 2023 22:41:46 +0100 Subject: [PATCH 102/162] fmt --- frame/staking/src/pallet/impls.rs | 4 ---- frame/staking/src/tests.rs | 6 +----- 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index 2f688d47af1a1..994a6b55f8355 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -243,10 +243,6 @@ impl Pallet { let page_stake_part = Perbill::from_rational(exposure.current_total(), exposure.total()); // validator commission is paid out in fraction across pages proportional to the page stake. let validator_commission_payout = page_stake_part * validator_total_commission_payout; - println!( - "validator_commission_payout: {:?}, validator_total_commission_payout: {:?}, exposure_total: {:?}, exposure_page_total: {:?}, page_count: {:?}, own: {:?}", - validator_commission_payout, validator_total_commission_payout, exposure.total(), exposure.current_total(), exposure.page_count(), exposure.own() - ); Self::deposit_event(Event::::PayoutStarted { era_index: era, diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index f071a547b0960..b83fb78738a20 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -4109,11 +4109,7 @@ fn test_commission_paid_across_pages() { assert!(before_balance < after_balance); } - assert_eq_error_rate!( - Balances::free_balance(&10), - initial_balance + payout / 2, - 1, - ); + assert_eq_error_rate!(Balances::free_balance(&10), initial_balance + payout / 2, 1,); }); } From 806e6565335250b0fffd58d0426baa963f973622 Mon Sep 17 00:00:00 2001 From: Ankan Date: Mon, 6 Feb 2023 22:45:44 +0100 Subject: [PATCH 103/162] docs --- frame/staking/src/lib.rs | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index 4983d29db9028..2d8790cdfe743 100644 --- a/frame/staking/src/lib.rs +++ b/frame/staking/src/lib.rs @@ -825,6 +825,7 @@ struct ExposureExt { } impl ExposureExt { + /// Create a new instance of `ExposureExt` from legacy clipped exposures. pub fn from_clipped(exposure: Exposure) -> Self { Self { exposure_overview: ExposureOverview { @@ -836,23 +837,23 @@ impl ExposureExt Balance { self.exposure_overview.total } - pub fn own(&self) -> Balance { - self.exposure_overview.own - } - - pub fn page_count(&self) -> PageIndex { - self.exposure_overview.page_count - } - - // Returns the total stake of this page. + /// Returns total exposure of this validator for current page pub fn current_total(&self) -> Balance { self.exposure_page.page_total + self.exposure_overview.own } + /// Returns validator's own stake that is exposed + pub fn own(&self) -> Balance { + self.exposure_overview.own + } + + /// Returns the portions of nominators stashes that are exposed in this page pub fn others(&self) -> &Vec> { &self.exposure_page.others } From e8260563dcc2bc9e356781d9e4f72c19589cfcf7 Mon Sep 17 00:00:00 2001 From: Ankan Date: Mon, 6 Feb 2023 22:47:54 +0100 Subject: [PATCH 104/162] fix test --- frame/staking/src/lib.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index 2d8790cdfe743..563cd06ca8626 100644 --- a/frame/staking/src/lib.rs +++ b/frame/staking/src/lib.rs @@ -853,10 +853,16 @@ impl ExposureExt &Vec> { &self.exposure_page.others } + + /// Returns the number of pages of nominators stashes that are exposed. + #[allow(dead_code)] + pub fn page_count(&self) -> PageIndex { + self.exposure_overview.page_count + } } /// A pending slash record. The value of the slash has been computed but not applied yet, From 5ae9ee80006fcc108e8a7f19475a1fb8496ee4a1 Mon Sep 17 00:00:00 2001 From: Ankan Date: Tue, 7 Feb 2023 17:52:44 +0100 Subject: [PATCH 105/162] only use one constant --- frame/staking/src/mock.rs | 1 - frame/staking/src/pallet/mod.rs | 31 +++++++++++++++---------------- 2 files changed, 15 insertions(+), 17 deletions(-) diff --git a/frame/staking/src/mock.rs b/frame/staking/src/mock.rs index bf66c06bbb44d..5bd9c46bbdde3 100644 --- a/frame/staking/src/mock.rs +++ b/frame/staking/src/mock.rs @@ -294,7 +294,6 @@ impl crate::pallet::pallet::Config for Test { type EraPayout = ConvertCurve; type NextNewSession = Session; type MaxNominatorRewardedPerValidator = MaxNominatorRewardedPerValidator; - type MaxExposurePageSize = MaxNominatorRewardedPerValidator; type OffendingValidatorsThreshold = OffendingValidatorsThreshold; type ElectionProvider = onchain::OnChainExecution; type GenesisElectionProvider = Self::ElectionProvider; diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index 265789beae0f6..b813136e12864 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -201,24 +201,23 @@ pub mod pallet { /// guess. type NextNewSession: EstimateNextNewSession; - /// The maximum number of nominators rewarded for each validator when using - /// `ErasStakersClipped`. + /// The maximum size of each `T::ExposurePage`. + /// + /// An `ExposurePage` is bounded to a maximum of `MaxNominatorRewardedPerValidator` + /// nominators. The actual page size is a dynamic value that is determined by the storage + /// item `T::ExposurePageSize`. /// - /// For older non-paged exposure, a reward payout is restricted to the top + /// For older non-paged exposure, a reward payout was restricted to the top /// `MaxNominatorRewardedPerValidator` nominators. This is to limit the i/o cost for the /// nominator payout. - // TODO(ank4n) #[deprecated(note = "This constant is no longer used and will be removed in - // the future.")] - #[pallet::constant] - type MaxNominatorRewardedPerValidator: Get; - - /// The maximum size of each `T::ExposurePage`. /// - /// An `ExposurePage` is bounded to a maximum of `MaxExposurePageSize` nominators. The - /// actual page size is a dynamic value that is determined by the storage item - /// `T::ExposurePageSize`. + /// The name is a bit misleading, because historically we used to reward the top + /// `MaxNominatorRewardedPerValidator` nominators by stake when we did not had paged + /// exposures. In future we should rename this to something like `ExposurePageSize` when we + /// are ready to get rid of `ErasStakersClipped`. + /// Refer issue: #13034 #[pallet::constant] - type MaxExposurePageSize: Get; + type MaxNominatorRewardedPerValidator: Get; /// The fraction of the validator set that is safe to be offending. /// After the threshold is reached a new era will be forced. @@ -478,7 +477,7 @@ pub mod pallet { /// The nominator count each `ExposurePage` is capped at. /// - /// This cannot be greater than `T::MaxExposurePageSize`. + /// This cannot be greater than `T::MaxNominatorRewardedPerValidator`. #[pallet::storage] pub type ExposurePageSize = StorageValue<_, u32, OptionQuery>; @@ -783,8 +782,8 @@ pub mod pallet { // FIXME(ankan) Should we sort exposure.others for backward compatibility? let page_size = >::get() - .unwrap_or_else(|| T::MaxExposurePageSize::get()) - .clamp(1, T::MaxExposurePageSize::get()); + .unwrap_or_else(|| T::MaxNominatorRewardedPerValidator::get()) + .clamp(1, T::MaxNominatorRewardedPerValidator::get()); let (exposure_overview, exposure_pages) = exposure.into_pages(page_size); From 641d1124078b92b2ec7743e0ff42e9ea197079df Mon Sep 17 00:00:00 2001 From: Ankan Date: Tue, 7 Feb 2023 18:21:29 +0100 Subject: [PATCH 106/162] payout_stakers still work nicely --- frame/staking/src/tests.rs | 228 +++++++++++++++++++++++++++++++++++++ 1 file changed, 228 insertions(+) diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index b83fb78738a20..01fd13b8f7ffe 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -3928,6 +3928,234 @@ fn test_multi_page_payout_stakers_by_page() { }); } +#[test] +//todo +fn test_multi_page_payout_stakers_backward_compatible() { + // Test that payout_stakers work in general and that it pays the correct amount of reward. + ExtBuilder::default().has_stakers(false).build_and_execute(|| { + let balance = 1000; + // Track the exposure of the validator and all nominators. + let mut total_exposure = balance; + // Create a validator: + bond_validator(11, 10, balance); // Default(64) + assert_eq!(Validators::::count(), 1); + + let err_weight = ::WeightInfo::payout_stakers_alive_staked(0); + + // Create nominators, targeting stash of validators + for i in 0..100 { + let bond_amount = balance + i as Balance; + bond_nominator(1000 + i, 100 + i, bond_amount, vec![11]); + // with multi page reward payout, payout exposure is same as total exposure. + total_exposure += bond_amount; + } + + mock::start_active_era(1); + Staking::reward_by_ids(vec![(11, 1)]); + + // Since `MaxNominatorRewardedPerValidator = 64`, there are two pages of validator exposure. + assert_eq!(EraInfo::::get_page_count(1, &11), 2); + + // compute and ensure the reward amount is greater than zero. + let payout = current_total_payout_for_duration(reward_time_per_era()); + mock::start_active_era(2); + + // verify the exposures are calculated correctly. + let actual_exposure_0 = EraInfo::::get_validator_exposure(1, &11, 0).unwrap(); + assert_eq!(actual_exposure_0.total(), total_exposure); + assert_eq!(actual_exposure_0.own(), 1000); + assert_eq!(actual_exposure_0.others().len(), 64); + let actual_exposure_1 = EraInfo::::get_validator_exposure(1, &11, 1).unwrap(); + assert_eq!(actual_exposure_1.total(), total_exposure); + // own stake is only included once in the first page + assert_eq!(actual_exposure_1.own(), 0); + assert_eq!(actual_exposure_1.others().len(), 100 - 64); + + let pre_payout_total_issuance = Balances::total_issuance(); + RewardOnUnbalanceWasCalled::set(false); + + let controller_balance_before_p0_payout = Balances::free_balance(&10); + // Payout rewards for first exposure page + assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, 1)); + // page 0 is claimed + assert_noop!( + Staking::payout_stakers_by_page(RuntimeOrigin::signed(1337), 11, 1, 0), + Error::::AlreadyClaimed.with_weight(err_weight) + ); + + let controller_balance_after_p0_payout = Balances::free_balance(&10); + + // verify rewards have been paid out but still some left + assert!(Balances::total_issuance() > pre_payout_total_issuance); + assert!(Balances::total_issuance() < pre_payout_total_issuance + payout); + + // verify the validator has been rewarded + assert!(controller_balance_after_p0_payout > controller_balance_before_p0_payout); + + // This should payout the second and last page of nominators + assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, 1)); + + // cannot claim any more pages + assert_noop!( + Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, 1), + Error::::AlreadyClaimed.with_weight(err_weight) + ); + + // verify the validator was not rewarded the second time + assert_eq!(Balances::free_balance(&10), controller_balance_after_p0_payout); + + // verify all rewards have been paid out + assert_eq_error_rate!(Balances::total_issuance(), pre_payout_total_issuance + payout, 2); + assert!(RewardOnUnbalanceWasCalled::get()); + + // verify all nominators of validator 11 are paid out, including the validator + // Validator payout goes to controller. + assert!(Balances::free_balance(&10) > balance); + for i in 0..100 { + assert!(Balances::free_balance(&(100 + i)) > balance + i as Balance); + } + + // verify we no longer track rewards in `legacy_claimed_rewards` vec + let ledger = Staking::ledger(&10); + assert_eq!( + Staking::ledger(&10), + Some(StakingLedger { + stash: 11, + total: 1000, + active: 1000, + unlocking: Default::default(), + legacy_claimed_rewards: bounded_vec![] + }) + ); + + // verify rewards are tracked to prevent double claims + for page in 0..EraInfo::::get_page_count(1, &11) { + assert_eq!( + EraInfo::::is_rewards_claimed_temp(1, ledger.as_ref().unwrap(), &11, page), + true + ); + } + + for i in 3..16 { + Staking::reward_by_ids(vec![(11, 1)]); + + // compute and ensure the reward amount is greater than zero. + let payout = current_total_payout_for_duration(reward_time_per_era()); + let pre_payout_total_issuance = Balances::total_issuance(); + + mock::start_active_era(i); + RewardOnUnbalanceWasCalled::set(false); + mock::make_all_reward_payment(i - 1); + assert_eq_error_rate!( + Balances::total_issuance(), + pre_payout_total_issuance + payout, + 2 + ); + assert!(RewardOnUnbalanceWasCalled::get()); + + // verify we track rewards for each era and page + for page in 0..EraInfo::::get_page_count(i - 1, &11) { + assert_eq!( + EraInfo::::is_rewards_claimed_temp( + i - 1, + Staking::ledger(&10).as_ref().unwrap(), + &11, + page + ), + true + ); + } + } + + assert_eq!(Staking::claimed_rewards(14, &11), vec![0, 1]); + + let last_era = 99; + let history_depth = HistoryDepth::get(); + let last_reward_era = last_era - 1; + let first_claimable_reward_era = last_era - history_depth; + for i in 16..=last_era { + Staking::reward_by_ids(vec![(11, 1)]); + // compute and ensure the reward amount is greater than zero. + let _ = current_total_payout_for_duration(reward_time_per_era()); + mock::start_active_era(i); + } + + // verify we clean up history as we go + for era in 0..15 { + assert_eq!(Staking::claimed_rewards(era, &11), Vec::::new()); + } + + // verify only page 0 is marked as claimed + assert_ok!(Staking::payout_stakers( + RuntimeOrigin::signed(1337), + 11, + first_claimable_reward_era + )); + assert_eq!(Staking::claimed_rewards(first_claimable_reward_era, &11), vec![0]); + + // verify page 0 and 1 are marked as claimed + assert_ok!(Staking::payout_stakers( + RuntimeOrigin::signed(1337), + 11, + first_claimable_reward_era, + )); + assert_eq!(Staking::claimed_rewards(first_claimable_reward_era, &11), vec![0, 1]); + + // change order and verify only page 1 is marked as claimed + assert_ok!(Staking::payout_stakers_by_page( + RuntimeOrigin::signed(1337), + 11, + last_reward_era, + 1 + )); + assert_eq!(Staking::claimed_rewards(last_reward_era, &11), vec![1]); + + // verify page 0 is claimed even when explicit page is not passed + assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, last_reward_era,)); + + assert_eq!(Staking::claimed_rewards(last_reward_era, &11), vec![0, 1]); + + // cannot claim any more pages + assert_noop!( + Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, last_reward_era), + Error::::AlreadyClaimed.with_weight(err_weight) + ); + + // Create 4 nominator pages + for i in 100..200 { + let bond_amount = balance + i as Balance; + bond_nominator(1000 + i, 100 + i, bond_amount, vec![11]); + } + + let test_era = last_era + 1; + mock::start_active_era(test_era); + + Staking::reward_by_ids(vec![(11, 1)]); + // compute and ensure the reward amount is greater than zero. + let _ = current_total_payout_for_duration(reward_time_per_era()); + mock::start_active_era(test_era + 1); + + // Out of order claims works. + assert_ok!(Staking::payout_stakers_by_page(RuntimeOrigin::signed(1337), 11, test_era, 2)); + assert_eq!(Staking::claimed_rewards(test_era, &11), vec![2]); + + assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, test_era)); + assert_eq!(Staking::claimed_rewards(test_era, &11), vec![0, 2]); + + // cannot claim page 2 again + assert_noop!( + Staking::payout_stakers_by_page(RuntimeOrigin::signed(1337), 11, test_era, 2), + Error::::AlreadyClaimed.with_weight(err_weight) + ); + + assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, test_era)); + assert_eq!(Staking::claimed_rewards(test_era, &11), vec![0, 1, 2]); + + assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, test_era)); + assert_eq!(Staking::claimed_rewards(test_era, &11), vec![0, 1, 2, 3]); + }); +} + #[test] fn payout_stakers_handles_basic_errors() { // Here we will test payouts handle all errors. From 0f76c591cc2eb58c7686093b78c31be0e72ab5c1 Mon Sep 17 00:00:00 2001 From: Ankan Date: Tue, 7 Feb 2023 18:25:27 +0100 Subject: [PATCH 107/162] remove todo --- frame/staking/src/pallet/mod.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index b813136e12864..b7a4f1a972a44 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -708,7 +708,6 @@ pub mod pallet { } /// Returns the next page that can be claimed or `None` if nothing to claim. - // TODO(ank4n): Test and refactor pub(crate) fn get_next_claimable_page( era: EraIndex, validator: &T::AccountId, From 37d46b6826e47a7d77e871c303b842e1dffb498d Mon Sep 17 00:00:00 2001 From: Ankan Date: Wed, 8 Feb 2023 00:11:51 +0100 Subject: [PATCH 108/162] benchmark against implicit page payout stakers since thats worst case --- 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 86559861db3ae..8ff3ba8ad21c2 100644 --- a/frame/staking/src/benchmarking.rs +++ b/frame/staking/src/benchmarking.rs @@ -598,7 +598,7 @@ benchmarks! { let balance = T::Currency::free_balance(stash); nominator_balances_before.push(balance); } - }: payout_stakers_by_page(RawOrigin::Signed(caller), validator.clone(), current_era, 0) + }: payout_stakers(RawOrigin::Signed(caller), validator.clone(), current_era) verify { let balance_after = T::Currency::free_balance(&validator); ensure!( From 406d3b82a0e0175a4729c0ed3219129a9af9cffb Mon Sep 17 00:00:00 2001 From: Ankan Date: Wed, 8 Feb 2023 20:32:15 +0100 Subject: [PATCH 109/162] add a working draft of changelog --- frame/staking/CHANGELOG.md | 35 +++++++++++++++++++++++++++++++++ frame/staking/src/pallet/mod.rs | 1 + 2 files changed, 36 insertions(+) create mode 100644 frame/staking/CHANGELOG.md diff --git a/frame/staking/CHANGELOG.md b/frame/staking/CHANGELOG.md new file mode 100644 index 0000000000000..01630c1270be4 --- /dev/null +++ b/frame/staking/CHANGELOG.md @@ -0,0 +1,35 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +The semantic versioning guarantees cover the interface to the substrate runtime which +includes this pallet as a dependency. This module will also add storage migrations whenever +changes require it. Stability with regard to offchain tooling is explicitly excluded from +this guarantee: For example adding a new field to an in-storage data structure will require +changes to frontends to properly display it. However, those changes will still be regarded +as a minor version bump. + +## [5.0.0] - UNRELEASED + +### Added + +- Unlimited number of nominators can be rewarded. +- New storage item `ExposurePageSize` to limit the number of nominators rewarded for a single call for reward payout. +- New storage item `ErasStakersPaged` that keeps upto `ExposurePageSize` individual nominator exposures by era, validator and page. +- New storage item `ErasStakersOverview` which complements `ErasStakersPaged` and keeps track of validator's own stake and total backing stake for each era. +- New call `payout_stakers_by_page` that allows to payout rewards for a single validator by passing the page explicitly. +- New storage item `ClaimedRewards` that keeps track of claimed reward history of a validator by era and page. + +### Changed +- `payout_stakers` can be called multiple times for the same era if the validator has more than `ExposurePageSize` nominators backing them. +- `MaxNominatorRewardedPerValidator` is renamed to `MaxExposurePageSize`. + +### Deprecated +- `ErasStakersClipped` is deprecated in favor of `ErasStakersPaged`. In 84 eras, `ErasStakersClipped` will be removed. +- `StakingLedger.claimed_rewards` is renamed to `StakingLedger.legacy_claimed_rewards` and is deprecated. + +### PRs +[#13059](https://github.com/paritytech/substrate/pull/13059) diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index b7a4f1a972a44..7fb6fbffa5453 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -216,6 +216,7 @@ pub mod pallet { /// exposures. In future we should rename this to something like `ExposurePageSize` when we /// are ready to get rid of `ErasStakersClipped`. /// Refer issue: #13034 + /// TODO(ank4n): rename this to `MaxExposurePageSize`. #[pallet::constant] type MaxNominatorRewardedPerValidator: Get; From bfdd1430606d47c7bdd5502a613a26106d096d90 Mon Sep 17 00:00:00 2001 From: Ankan Date: Wed, 8 Feb 2023 20:50:18 +0100 Subject: [PATCH 110/162] small doc update --- frame/staking/src/lib.rs | 3 +++ frame/staking/src/pallet/mod.rs | 6 ++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index 563cd06ca8626..9bb3223c741b0 100644 --- a/frame/staking/src/lib.rs +++ b/frame/staking/src/lib.rs @@ -818,6 +818,9 @@ impl Default for ExposureOverview { } /// Extended view of Exposure comprising of `ExposureOverview` and a single page of `ExposurePage`. +/// +/// This is useful where we need to take into account the validator's own stake and total exposure +/// in consideration in addition to the individual nominators backing them. #[derive(Encode, Decode, RuntimeDebug, TypeInfo, PartialEq, Eq)] struct ExposureExt { exposure_overview: ExposureOverview, diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index 7fb6fbffa5453..92ec691bbcfc6 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -642,10 +642,8 @@ pub mod pallet { pub type CurrentPlannedSession = StorageValue<_, SessionIndex, ValueQuery>; /// Wrapper struct for Era related information. It is not a pure encapsulation as these storage - /// items can be accessed directly but nevertheless, its recommended to use `EraInfo` for - /// accessing the following: (1) `ErasStakers`, (2) `ClaimedRewards`, (3) `ErasStakersClipped`, - /// (4) `ErasStakersPaged`, (5) `ErasTotalStake`. - // TODO(Ank4n): add all era related storage items in this struct + /// items can be accessed directly but nevertheless, its recommended to use `EraInfo` where we + /// can and add more functions to it as needed. pub(crate) struct EraInfo(sp_std::marker::PhantomData); impl EraInfo { /// Temporary function which looks at both (1) passed param `T::StakingLedger` for legacy From f2fd8d4192bad191fd5da5b70c430fac6724417d Mon Sep 17 00:00:00 2001 From: Arkadiy Paronyan Date: Tue, 7 Feb 2023 19:15:01 +0100 Subject: [PATCH 111/162] Fix block pruning (#13323) --- client/db/src/lib.rs | 84 +++++++++++++++++++++++++++++++++----------- 1 file changed, 64 insertions(+), 20 deletions(-) diff --git a/client/db/src/lib.rs b/client/db/src/lib.rs index f217eb6480abc..f54f1bdb131c7 100644 --- a/client/db/src/lib.rs +++ b/client/db/src/lib.rs @@ -1806,7 +1806,13 @@ impl Backend { } let new_displaced = self.blockchain.leaves.write().finalize_height(f_num); - self.prune_blocks(transaction, f_num, &new_displaced, current_transaction_justifications)?; + self.prune_blocks( + transaction, + f_num, + f_hash, + &new_displaced, + current_transaction_justifications, + )?; Ok(()) } @@ -1815,6 +1821,7 @@ impl Backend { &self, transaction: &mut Transaction, finalized_number: NumberFor, + finalized_hash: Block::Hash, displaced: &FinalizationOutcome>, current_transaction_justifications: &mut HashMap, ) -> ClientResult<()> { @@ -1843,10 +1850,10 @@ impl Backend { self.prune_block(transaction, BlockId::::number(number))?; } - self.prune_displaced_branches(transaction, finalized_number, displaced)?; + self.prune_displaced_branches(transaction, finalized_hash, displaced)?; }, BlocksPruning::KeepFinalized => { - self.prune_displaced_branches(transaction, finalized_number, displaced)?; + self.prune_displaced_branches(transaction, finalized_hash, displaced)?; }, } Ok(()) @@ -1855,28 +1862,21 @@ impl Backend { fn prune_displaced_branches( &self, transaction: &mut Transaction, - finalized: NumberFor, + finalized: Block::Hash, displaced: &FinalizationOutcome>, ) -> ClientResult<()> { // Discard all blocks from displaced branches for h in displaced.leaves() { - let mut number = finalized; - let mut hash = *h; - // Follow displaced chains back until we reach a finalized block. - // Since leaves are discarded due to finality, they can't have parents - // that are canonical, but not yet finalized. So we stop deleting as soon as - // we reach canonical chain. - while self.blockchain.hash(number)? != Some(hash) { - match self.blockchain.header(hash)? { - Some(header) => { - self.blockchain.insert_persisted_body_if_pinned(hash)?; - - self.prune_block(transaction, BlockId::::hash(hash))?; - number = header.number().saturating_sub(One::one()); - hash = *header.parent_hash(); + match sp_blockchain::tree_route(&self.blockchain, *h, finalized) { + Ok(tree_route) => + for r in tree_route.retracted() { + self.blockchain.insert_persisted_body_if_pinned(r.hash)?; + self.prune_block(transaction, BlockId::::hash(r.hash))?; }, - None => break, - } + Err(sp_blockchain::Error::UnknownBlock(_)) => { + // Sometimes routes can't be calculated. E.g. after warp sync. + }, + Err(e) => Err(e)?, } } Ok(()) @@ -3569,6 +3569,50 @@ pub(crate) mod tests { assert_eq!(Some(vec![4.into()]), bc.body(blocks[4]).unwrap()); } + #[test] + fn prune_blocks_on_finalize_and_reorg() { + // 0 - 1b + // \ - 1a - 2a - 3a + // \ - 2b + + let backend = Backend::::new_test_with_tx_storage(BlocksPruning::Some(10), 10); + + let make_block = |index, parent, val: u64| { + insert_block(&backend, index, parent, None, H256::random(), vec![val.into()], None) + .unwrap() + }; + + let block_0 = make_block(0, Default::default(), 0x00); + let block_1a = make_block(1, block_0, 0x1a); + let block_1b = make_block(1, block_0, 0x1b); + let block_2a = make_block(2, block_1a, 0x2a); + let block_2b = make_block(2, block_1a, 0x2b); + let block_3a = make_block(3, block_2a, 0x3a); + + // Make sure 1b is head + let mut op = backend.begin_operation().unwrap(); + backend.begin_state_operation(&mut op, block_0).unwrap(); + op.mark_head(block_1b).unwrap(); + backend.commit_operation(op).unwrap(); + + // Finalize 3a + let mut op = backend.begin_operation().unwrap(); + backend.begin_state_operation(&mut op, block_0).unwrap(); + op.mark_head(block_3a).unwrap(); + op.mark_finalized(block_1a, None).unwrap(); + op.mark_finalized(block_2a, None).unwrap(); + op.mark_finalized(block_3a, None).unwrap(); + backend.commit_operation(op).unwrap(); + + let bc = backend.blockchain(); + assert_eq!(None, bc.body(block_1b).unwrap()); + assert_eq!(None, bc.body(block_2b).unwrap()); + assert_eq!(Some(vec![0x00.into()]), bc.body(block_0).unwrap()); + assert_eq!(Some(vec![0x1a.into()]), bc.body(block_1a).unwrap()); + assert_eq!(Some(vec![0x2a.into()]), bc.body(block_2a).unwrap()); + assert_eq!(Some(vec![0x3a.into()]), bc.body(block_3a).unwrap()); + } + #[test] fn indexed_data_block_body() { let backend = Backend::::new_test_with_tx_storage(BlocksPruning::Some(1), 10); From 58eef2c360572f82deaf4b71ea7f33bbc24b25bb Mon Sep 17 00:00:00 2001 From: Muharem Ismailov Date: Wed, 8 Feb 2023 09:33:34 +0100 Subject: [PATCH 112/162] Referendum proposal's metadata (#12568) * referenda metadata * todo comment * remove TODO, update rustdocs * referenda clear_metadata origin signed or root * referenda metadata unit tests * drop schema type for referenda metadata * remove metadata type * referenda metadata benches * note different preimages * metadata for democracy pallet * metadata democracy pallet tests and benches * fix cargo clippy * update docs * ".git/.scripts/bench-bot.sh" pallet dev pallet_democracy * ".git/.scripts/bench-bot.sh" pallet dev pallet_referenda * Update the doc frame/democracy/src/lib.rs Co-authored-by: Roman Useinov * Update the doc frame/democracy/src/lib.rs Co-authored-by: Anthony Alaribe * reference instead clone for take Co-authored-by: Anthony Alaribe * error rename BadMetadata to PreimageNotExist * clear metadata within internal_cancel_referendum fn * remove redundant clone * collapse metadata api into one set_metadata method * fmt * review fixes * not request preimage on set_metadata * rename events and update docs * ".git/.scripts/commands/bench/bench.sh" pallet dev pallet_democracy * ".git/.scripts/commands/bench/bench.sh" pallet dev pallet_referenda * rename reset_metadata to transfer_metadata --------- Co-authored-by: command-bot <> Co-authored-by: Roman Useinov Co-authored-by: Anthony Alaribe --- frame/democracy/src/benchmarking.rs | 203 +++++- frame/democracy/src/lib.rs | 176 +++++- frame/democracy/src/tests.rs | 15 +- frame/democracy/src/tests/fast_tracking.rs | 11 + frame/democracy/src/tests/metadata.rs | 209 +++++++ frame/democracy/src/tests/public_proposals.rs | 14 +- frame/democracy/src/types.rs | 17 + frame/democracy/src/weights.rs | 581 ++++++++++++------ frame/referenda/src/benchmarking.rs | 26 +- frame/referenda/src/lib.rs | 72 ++- frame/referenda/src/mock.rs | 14 +- frame/referenda/src/tests.rs | 72 +++ frame/referenda/src/weights.rs | 307 +++++---- 13 files changed, 1367 insertions(+), 350 deletions(-) create mode 100644 frame/democracy/src/tests/metadata.rs diff --git a/frame/democracy/src/benchmarking.rs b/frame/democracy/src/benchmarking.rs index f2d45b719f678..f376b733aba6b 100644 --- a/frame/democracy/src/benchmarking.rs +++ b/frame/democracy/src/benchmarking.rs @@ -54,19 +54,20 @@ fn add_proposal(n: u32) -> Result { Ok(proposal.hash()) } -fn add_referendum(n: u32) -> (ReferendumIndex, H256) { +// add a referendum with a metadata. +fn add_referendum(n: u32) -> (ReferendumIndex, H256, PreimageHash) { let vote_threshold = VoteThreshold::SimpleMajority; let proposal = make_proposal::(n); let hash = proposal.hash(); - ( - Democracy::::inject_referendum( - T::LaunchPeriod::get(), - proposal, - vote_threshold, - 0u32.into(), - ), - hash, - ) + let index = Democracy::::inject_referendum( + T::LaunchPeriod::get(), + proposal, + vote_threshold, + 0u32.into(), + ); + let preimage_hash = note_preimage::(); + MetadataOf::::insert(crate::MetadataOwner::Referendum(index), preimage_hash.clone()); + (index, hash, preimage_hash) } fn account_vote(b: BalanceOf) -> AccountVote> { @@ -75,6 +76,25 @@ fn account_vote(b: BalanceOf) -> AccountVote> { AccountVote::Standard { vote: v, balance: b } } +fn assert_last_event(generic_event: ::RuntimeEvent) { + frame_system::Pallet::::assert_last_event(generic_event.into()); +} + +fn assert_has_event(generic_event: ::RuntimeEvent) { + frame_system::Pallet::::assert_has_event(generic_event.into()); +} + +// note a new preimage. +fn note_preimage() -> PreimageHash { + use core::sync::atomic::{AtomicU8, Ordering}; + use sp_std::borrow::Cow; + // note a new preimage on every function invoke. + static COUNTER: AtomicU8 = AtomicU8::new(0); + let data = Cow::from(vec![COUNTER.fetch_add(1, Ordering::Relaxed)]); + let hash = ::Preimages::note(data).unwrap(); + hash +} + benchmarks! { propose { let p = T::MaxProposals::get(); @@ -179,7 +199,7 @@ benchmarks! { emergency_cancel { let origin = T::CancellationOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; - let ref_index = add_referendum::(0).0; + let (ref_index, _, preimage_hash) = add_referendum::(0); assert_ok!(Democracy::::referendum_status(ref_index)); }: _(origin, ref_index) verify { @@ -188,6 +208,10 @@ benchmarks! { Democracy::::referendum_status(ref_index), Error::::ReferendumInvalid, ); + assert_last_event::(crate::Event::MetadataCleared { + owner: MetadataOwner::Referendum(ref_index), + hash: preimage_hash, + }.into()); } blacklist { @@ -198,7 +222,7 @@ benchmarks! { // We should really add a lot of seconds here, but we're not doing it elsewhere. // Add a referendum of our proposal. - let (ref_index, hash) = add_referendum::(0); + let (ref_index, hash, preimage_hash) = add_referendum::(0); assert_ok!(Democracy::::referendum_status(ref_index)); // Place our proposal in the external queue, too. assert_ok!(Democracy::::external_propose( @@ -215,6 +239,10 @@ benchmarks! { Democracy::::referendum_status(ref_index), Error::::ReferendumInvalid ); + assert_has_event::(crate::Event::MetadataCleared { + owner: MetadataOwner::Referendum(ref_index), + hash: preimage_hash, + }.into()); } // Worst case scenario, we external propose a previously blacklisted proposal @@ -262,8 +290,13 @@ benchmarks! { .expect("ExternalDefaultOrigin has no successful origin required for the benchmark"); let proposal = make_proposal::(0); let proposal_hash = proposal.hash(); - Democracy::::external_propose_default(origin_propose, proposal)?; - + Democracy::::external_propose_default(origin_propose.clone(), proposal)?; + // Set metadata to the external proposal. + let preimage_hash = note_preimage::(); + assert_ok!(Democracy::::set_metadata( + origin_propose, + MetadataOwner::External, + Some(preimage_hash))); // NOTE: Instant origin may invoke a little bit more logic, but may not always succeed. let origin_fast_track = T::FastTrackOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; @@ -271,7 +304,12 @@ benchmarks! { let delay = 0u32; }: _(origin_fast_track, proposal_hash, voting_period, delay.into()) verify { - assert_eq!(Democracy::::referendum_count(), 1, "referendum not created") + assert_eq!(Democracy::::referendum_count(), 1, "referendum not created"); + assert_last_event::(crate::Event::MetadataTransferred { + prev_owner: MetadataOwner::External, + owner: MetadataOwner::Referendum(0), + hash: preimage_hash, + }.into()); } veto_external { @@ -280,7 +318,14 @@ benchmarks! { let origin_propose = T::ExternalDefaultOrigin::try_successful_origin() .expect("ExternalDefaultOrigin has no successful origin required for the benchmark"); - Democracy::::external_propose_default(origin_propose, proposal)?; + Democracy::::external_propose_default(origin_propose.clone(), proposal)?; + + let preimage_hash = note_preimage::(); + assert_ok!(Democracy::::set_metadata( + origin_propose, + MetadataOwner::External, + Some(preimage_hash)) + ); let mut vetoers: BoundedVec = Default::default(); for i in 0 .. (T::MaxBlacklisted::get() - 1) { @@ -303,13 +348,32 @@ benchmarks! { for i in 0 .. T::MaxProposals::get() { add_proposal::(i)?; } + // Add metadata to the first proposal. + let proposer = funded_account::("proposer", 0); + let preimage_hash = note_preimage::(); + assert_ok!(Democracy::::set_metadata( + RawOrigin::Signed(proposer).into(), + MetadataOwner::Proposal(0), + Some(preimage_hash))); let cancel_origin = T::CancelProposalOrigin::try_successful_origin() .map_err(|_| BenchmarkError::Weightless)?; }: _(cancel_origin, 0) + verify { + assert_last_event::(crate::Event::MetadataCleared { + owner: MetadataOwner::Proposal(0), + hash: preimage_hash, + }.into()); + } cancel_referendum { - let ref_index = add_referendum::(0).0; + let (ref_index, _, preimage_hash) = add_referendum::(0); }: _(RawOrigin::Root, ref_index) + verify { + assert_last_event::(crate::Event::MetadataCleared { + owner: MetadataOwner::Referendum(0), + hash: preimage_hash, + }.into()); + } #[extra] on_initialize_external { @@ -678,6 +742,111 @@ benchmarks! { assert_eq!(votes.len(), (r - 1) as usize, "Vote was not removed"); } + set_external_metadata { + let origin = T::ExternalOrigin::try_successful_origin() + .expect("ExternalOrigin has no successful origin required for the benchmark"); + assert_ok!( + Democracy::::external_propose(origin.clone(), make_proposal::(0)) + ); + let owner = MetadataOwner::External; + let hash = note_preimage::(); + }: set_metadata(origin, owner.clone(), Some(hash)) + verify { + assert_last_event::(crate::Event::MetadataSet { + owner, + hash, + }.into()); + } + + clear_external_metadata { + let origin = T::ExternalOrigin::try_successful_origin() + .expect("ExternalOrigin has no successful origin required for the benchmark"); + assert_ok!( + Democracy::::external_propose(origin.clone(), make_proposal::(0)) + ); + let owner = MetadataOwner::External; + let proposer = funded_account::("proposer", 0); + let hash = note_preimage::(); + assert_ok!(Democracy::::set_metadata(origin.clone(), owner.clone(), Some(hash))); + }: set_metadata(origin, owner.clone(), None) + verify { + assert_last_event::(crate::Event::MetadataCleared { + owner, + hash, + }.into()); + } + + set_proposal_metadata { + // Place our proposal at the end to make sure it's worst case. + for i in 0 .. T::MaxProposals::get() { + add_proposal::(i)?; + } + let owner = MetadataOwner::Proposal(0); + let proposer = funded_account::("proposer", 0); + let hash = note_preimage::(); + }: set_metadata(RawOrigin::Signed(proposer).into(), owner.clone(), Some(hash)) + verify { + assert_last_event::(crate::Event::MetadataSet { + owner, + hash, + }.into()); + } + + clear_proposal_metadata { + // Place our proposal at the end to make sure it's worst case. + for i in 0 .. T::MaxProposals::get() { + add_proposal::(i)?; + } + let proposer = funded_account::("proposer", 0); + let owner = MetadataOwner::Proposal(0); + let hash = note_preimage::(); + assert_ok!(Democracy::::set_metadata( + RawOrigin::Signed(proposer.clone()).into(), + owner.clone(), + Some(hash))); + }: set_metadata(RawOrigin::Signed(proposer).into(), owner.clone(), None) + verify { + assert_last_event::(crate::Event::MetadataCleared { + owner, + hash, + }.into()); + } + + set_referendum_metadata { + // create not ongoing referendum. + ReferendumInfoOf::::insert( + 0, + ReferendumInfo::Finished { end: T::BlockNumber::zero(), approved: true }, + ); + let owner = MetadataOwner::Referendum(0); + let caller = funded_account::("caller", 0); + let hash = note_preimage::(); + }: set_metadata(RawOrigin::Root.into(), owner.clone(), Some(hash)) + verify { + assert_last_event::(crate::Event::MetadataSet { + owner, + hash, + }.into()); + } + + clear_referendum_metadata { + // create not ongoing referendum. + ReferendumInfoOf::::insert( + 0, + ReferendumInfo::Finished { end: T::BlockNumber::zero(), approved: true }, + ); + let owner = MetadataOwner::Referendum(0); + let hash = note_preimage::(); + MetadataOf::::insert(owner.clone(), hash); + let caller = funded_account::("caller", 0); + }: set_metadata(RawOrigin::Signed(caller).into(), owner.clone(), None) + verify { + assert_last_event::(crate::Event::MetadataCleared { + owner, + hash, + }.into()); + } + impl_benchmark_test_suite!( Democracy, crate::tests::new_test_ext(), diff --git a/frame/democracy/src/lib.rs b/frame/democracy/src/lib.rs index 2c65e5d94bc46..3aa8bc0015d38 100644 --- a/frame/democracy/src/lib.rs +++ b/frame/democracy/src/lib.rs @@ -155,14 +155,17 @@ use codec::{Decode, Encode}; use frame_support::{ ensure, + error::BadOrigin, traits::{ defensive_prelude::*, schedule::{v3::Named as ScheduleNamed, DispatchTime}, - Bounded, Currency, Get, LockIdentifier, LockableCurrency, OnUnbalanced, QueryPreimage, - ReservableCurrency, StorePreimage, WithdrawReasons, + Bounded, Currency, EnsureOrigin, Get, Hash as PreimageHash, LockIdentifier, + LockableCurrency, OnUnbalanced, QueryPreimage, ReservableCurrency, StorePreimage, + WithdrawReasons, }, weights::Weight, }; +use frame_system::pallet_prelude::OriginFor; use sp_runtime::{ traits::{Bounded as ArithBounded, One, Saturating, StaticLookup, Zero}, ArithmeticError, DispatchError, DispatchResult, @@ -176,7 +179,10 @@ mod vote_threshold; pub mod weights; pub use conviction::Conviction; pub use pallet::*; -pub use types::{Delegations, ReferendumInfo, ReferendumStatus, Tally, UnvoteScope}; +pub use types::{ + Delegations, MetadataOwner, PropIndex, ReferendumIndex, ReferendumInfo, ReferendumStatus, + Tally, UnvoteScope, +}; pub use vote::{AccountVote, Vote, Voting}; pub use vote_threshold::{Approved, VoteThreshold}; pub use weights::WeightInfo; @@ -191,12 +197,6 @@ pub mod migrations; const DEMOCRACY_ID: LockIdentifier = *b"democrac"; -/// A proposal index. -pub type PropIndex = u32; - -/// A referendum index. -pub type ReferendumIndex = u32; - type BalanceOf = <::Currency as Currency<::AccountId>>::Balance; type NegativeImbalanceOf = <::Currency as Currency< @@ -425,6 +425,15 @@ pub mod pallet { #[pallet::storage] pub type Cancellations = StorageMap<_, Identity, H256, bool, ValueQuery>; + /// General information concerning any proposal or referendum. + /// The `PreimageHash` refers to the preimage of the `Preimages` provider which can be a JSON + /// dump or IPFS hash of a JSON file. + /// + /// Consider a garbage collection for a metadata of finished referendums to `unrequest` (remove) + /// large preimages. + #[pallet::storage] + pub type MetadataOf = StorageMap<_, Blake2_128Concat, MetadataOwner, PreimageHash>; + #[pallet::genesis_config] pub struct GenesisConfig { _phantom: sp_std::marker::PhantomData, @@ -477,6 +486,29 @@ pub mod pallet { Seconded { seconder: T::AccountId, prop_index: PropIndex }, /// A proposal got canceled. ProposalCanceled { prop_index: PropIndex }, + /// Metadata for a proposal or a referendum has been set. + MetadataSet { + /// Metadata owner. + owner: MetadataOwner, + /// Preimage hash. + hash: PreimageHash, + }, + /// Metadata for a proposal or a referendum has been cleared. + MetadataCleared { + /// Metadata owner. + owner: MetadataOwner, + /// Preimage hash. + hash: PreimageHash, + }, + /// Metadata has been transferred to new owner. + MetadataTransferred { + /// Previous metadata owner. + prev_owner: MetadataOwner, + /// New metadata owner. + owner: MetadataOwner, + /// Preimage hash. + hash: PreimageHash, + }, } #[pallet::error] @@ -528,6 +560,8 @@ pub mod pallet { TooMany, /// Voting period too low VotingPeriodLow, + /// The preimage does not exist. + PreimageNotExist, } #[pallet::hooks] @@ -773,12 +807,13 @@ pub mod pallet { >::kill(); let now = >::block_number(); - Self::inject_referendum( + let ref_index = Self::inject_referendum( now.saturating_add(voting_period), ext_proposal, threshold, delay, ); + Self::transfer_metadata(MetadataOwner::External, MetadataOwner::Referendum(ref_index)); Ok(()) } @@ -816,6 +851,7 @@ pub mod pallet { Self::deposit_event(Event::::Vetoed { who, proposal_hash, until }); >::kill(); + Self::clear_metadata(MetadataOwner::External); Ok(()) } @@ -1025,12 +1061,14 @@ pub mod pallet { T::Slash::on_unbalanced(T::Currency::slash_reserved(&who, amount).0); } } + Self::clear_metadata(MetadataOwner::Proposal(prop_index)); } }); // Remove the external queued referendum, if it's there. if matches!(NextExternal::::get(), Some((p, ..)) if p.hash() == proposal_hash) { NextExternal::::kill(); + Self::clear_metadata(MetadataOwner::External); } // Remove the referendum, if it's there. @@ -1067,8 +1105,68 @@ pub mod pallet { T::Slash::on_unbalanced(T::Currency::slash_reserved(&who, amount).0); } } - Self::deposit_event(Event::::ProposalCanceled { prop_index }); + Self::clear_metadata(MetadataOwner::Proposal(prop_index)); + Ok(()) + } + + /// Set or clear a metadata of a proposal or a referendum. + /// + /// Parameters: + /// - `origin`: Must correspond to the `MetadataOwner`. + /// - `ExternalOrigin` for an external proposal with the `SuperMajorityApprove` + /// threshold. + /// - `ExternalDefaultOrigin` for an external proposal with the `SuperMajorityAgainst` + /// threshold. + /// - `ExternalMajorityOrigin` for an external proposal with the `SimpleMajority` + /// threshold. + /// - `Signed` by a creator for a public proposal. + /// - `Signed` to clear a metadata for a finished referendum. + /// - `Root` to set a metadata for an ongoing referendum. + /// - `owner`: an identifier of a metadata owner. + /// - `maybe_hash`: The hash of an on-chain stored preimage. `None` to clear a metadata. + #[pallet::call_index(18)] + #[pallet::weight( + match (owner, maybe_hash) { + (MetadataOwner::External, Some(_)) => T::WeightInfo::set_external_metadata(), + (MetadataOwner::External, None) => T::WeightInfo::clear_external_metadata(), + (MetadataOwner::Proposal(_), Some(_)) => T::WeightInfo::set_proposal_metadata(), + (MetadataOwner::Proposal(_), None) => T::WeightInfo::clear_proposal_metadata(), + (MetadataOwner::Referendum(_), Some(_)) => T::WeightInfo::set_referendum_metadata(), + (MetadataOwner::Referendum(_), None) => T::WeightInfo::clear_referendum_metadata(), + } + )] + pub fn set_metadata( + origin: OriginFor, + owner: MetadataOwner, + maybe_hash: Option, + ) -> DispatchResult { + match owner { + MetadataOwner::External => { + let (_, threshold) = >::get().ok_or(Error::::NoProposal)?; + Self::ensure_external_origin(threshold, origin)?; + }, + MetadataOwner::Proposal(index) => { + let who = ensure_signed(origin)?; + let (_, _, proposer) = Self::proposal(index)?; + ensure!(proposer == who, Error::::NoPermission); + }, + MetadataOwner::Referendum(index) => { + let is_root = ensure_signed_or_root(origin)?.is_none(); + ensure!(is_root || maybe_hash.is_none(), Error::::NoPermission); + ensure!( + is_root || Self::referendum_status(index).is_err(), + Error::::NoPermission + ); + }, + } + if let Some(hash) = maybe_hash { + ensure!(T::Preimages::len(&hash).is_some(), Error::::PreimageNotExist); + MetadataOf::::insert(owner.clone(), hash); + Self::deposit_event(Event::::MetadataSet { owner, hash }); + } else { + Self::clear_metadata(owner); + } Ok(()) } } @@ -1146,6 +1244,7 @@ impl Pallet { pub fn internal_cancel_referendum(ref_index: ReferendumIndex) { Self::deposit_event(Event::::Cancelled { ref_index }); ReferendumInfoOf::::remove(ref_index); + Self::clear_metadata(MetadataOwner::Referendum(ref_index)); } // private. @@ -1432,12 +1531,13 @@ impl Pallet { if let Some((proposal, threshold)) = >::take() { LastTabledWasExternal::::put(true); Self::deposit_event(Event::::ExternalTabled); - Self::inject_referendum( + let ref_index = Self::inject_referendum( now.saturating_add(T::VotingPeriod::get()), proposal, threshold, T::EnactmentPeriod::get(), ); + Self::transfer_metadata(MetadataOwner::External, MetadataOwner::Referendum(ref_index)); Ok(()) } else { return Err(Error::::NoneWaiting.into()) @@ -1460,12 +1560,16 @@ impl Pallet { T::Currency::unreserve(d, deposit); } Self::deposit_event(Event::::Tabled { proposal_index: prop_index, deposit }); - Self::inject_referendum( + let ref_index = Self::inject_referendum( now.saturating_add(T::VotingPeriod::get()), proposal, VoteThreshold::SuperMajorityApprove, T::EnactmentPeriod::get(), ); + Self::transfer_metadata( + MetadataOwner::Proposal(prop_index), + MetadataOwner::Referendum(ref_index), + ) } Ok(()) } else { @@ -1578,6 +1682,52 @@ impl Pallet { // `Compact`. decode_compact_u32_at(&>::hashed_key_for(proposal)) } + + /// Return a proposal of an index. + fn proposal(index: PropIndex) -> Result<(PropIndex, BoundedCallOf, T::AccountId), Error> { + PublicProps::::get() + .into_iter() + .find(|(prop_index, _, _)| prop_index == &index) + .ok_or(Error::::ProposalMissing) + } + + /// Clear metadata if exist for a given owner. + fn clear_metadata(owner: MetadataOwner) { + if let Some(hash) = MetadataOf::::take(&owner) { + Self::deposit_event(Event::::MetadataCleared { owner, hash }); + } + } + + /// Transfer the metadata of an `owner` to a `new_owner`. + fn transfer_metadata(owner: MetadataOwner, new_owner: MetadataOwner) { + if let Some(hash) = MetadataOf::::take(&owner) { + MetadataOf::::insert(&new_owner, hash); + Self::deposit_event(Event::::MetadataTransferred { + prev_owner: owner, + owner: new_owner, + hash, + }); + } + } + + /// Ensure external origin for corresponding vote threshold. + fn ensure_external_origin( + threshold: VoteThreshold, + origin: OriginFor, + ) -> Result<(), BadOrigin> { + match threshold { + VoteThreshold::SuperMajorityApprove => { + let _ = T::ExternalOrigin::ensure_origin(origin)?; + }, + VoteThreshold::SuperMajorityAgainst => { + let _ = T::ExternalDefaultOrigin::ensure_origin(origin)?; + }, + VoteThreshold::SimpleMajority => { + let _ = T::ExternalMajorityOrigin::ensure_origin(origin)?; + }, + }; + Ok(()) + } } /// Decode `Compact` from the trie at given key. diff --git a/frame/democracy/src/tests.rs b/frame/democracy/src/tests.rs index 41b279035028e..9c7ec2906c677 100644 --- a/frame/democracy/src/tests.rs +++ b/frame/democracy/src/tests.rs @@ -32,7 +32,7 @@ use pallet_balances::{BalanceLock, Error as BalancesError}; use sp_core::H256; use sp_runtime::{ testing::Header, - traits::{BadOrigin, BlakeTwo256, IdentityLookup}, + traits::{BadOrigin, BlakeTwo256, Hash, IdentityLookup}, Perbill, }; mod cancellation; @@ -41,6 +41,7 @@ mod delegation; mod external_proposing; mod fast_tracking; mod lock_voting; +mod metadata; mod public_proposals; mod scheduling; mod voting; @@ -276,3 +277,15 @@ fn big_nay(who: u64) -> AccountVote { fn tally(r: ReferendumIndex) -> Tally { Democracy::referendum_status(r).unwrap().tally } + +/// note a new preimage without registering. +fn note_preimage(who: u64) -> PreimageHash { + use std::sync::atomic::{AtomicU8, Ordering}; + // note a new preimage on every function invoke. + static COUNTER: AtomicU8 = AtomicU8::new(0); + let data = vec![COUNTER.fetch_add(1, Ordering::Relaxed)]; + assert_ok!(Preimage::note_preimage(RuntimeOrigin::signed(who), data.clone())); + let hash = BlakeTwo256::hash(&data); + assert!(!Preimage::is_requested(&hash)); + hash +} diff --git a/frame/democracy/src/tests/fast_tracking.rs b/frame/democracy/src/tests/fast_tracking.rs index 97bb7a63908ab..09af3dbf3b5dd 100644 --- a/frame/democracy/src/tests/fast_tracking.rs +++ b/frame/democracy/src/tests/fast_tracking.rs @@ -32,6 +32,14 @@ fn fast_track_referendum_works() { RuntimeOrigin::signed(3), set_balance_proposal(2) )); + let hash = note_preimage(1); + assert!(>::get(MetadataOwner::External).is_none()); + assert_ok!(Democracy::set_metadata( + RuntimeOrigin::signed(3), + MetadataOwner::External, + Some(hash), + ),); + assert!(>::get(MetadataOwner::External).is_some()); assert_noop!(Democracy::fast_track(RuntimeOrigin::signed(1), h, 3, 2), BadOrigin); assert_ok!(Democracy::fast_track(RuntimeOrigin::signed(5), h, 2, 0)); assert_eq!( @@ -44,6 +52,9 @@ fn fast_track_referendum_works() { tally: Tally { ayes: 0, nays: 0, turnout: 0 }, }) ); + // metadata reset from the external proposal to the referendum. + assert!(>::get(MetadataOwner::External).is_none()); + assert!(>::get(MetadataOwner::Referendum(0)).is_some()); }); } diff --git a/frame/democracy/src/tests/metadata.rs b/frame/democracy/src/tests/metadata.rs new file mode 100644 index 0000000000000..95b617e37b199 --- /dev/null +++ b/frame/democracy/src/tests/metadata.rs @@ -0,0 +1,209 @@ +// This file is part of Substrate. + +// Copyright (C) 2017-2022 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. + +//! The tests for functionality concerning the metadata. + +use super::*; + +#[test] +fn set_external_metadata_works() { + new_test_ext().execute_with(|| { + use frame_support::traits::Hash as PreimageHash; + // invalid preimage hash. + let invalid_hash: PreimageHash = [1u8; 32].into(); + // metadata owner is an external proposal. + let owner = MetadataOwner::External; + // fails to set metadata if an external proposal does not exist. + assert_noop!( + Democracy::set_metadata(RuntimeOrigin::signed(2), owner.clone(), Some(invalid_hash)), + Error::::NoProposal, + ); + // create an external proposal. + assert_ok!(Democracy::external_propose(RuntimeOrigin::signed(2), set_balance_proposal(2),)); + assert!(>::exists()); + // fails to set metadata with non external origin. + assert_noop!( + Democracy::set_metadata(RuntimeOrigin::signed(1), owner.clone(), Some(invalid_hash)), + BadOrigin, + ); + // fails to set non-existing preimage. + assert_noop!( + Democracy::set_metadata(RuntimeOrigin::signed(2), owner.clone(), Some(invalid_hash)), + Error::::PreimageNotExist, + ); + // set metadata successful. + let hash = note_preimage(1); + assert_ok!(Democracy::set_metadata(RuntimeOrigin::signed(2), owner.clone(), Some(hash),),); + System::assert_last_event(RuntimeEvent::Democracy(crate::Event::MetadataSet { + owner, + hash, + })); + }); +} + +#[test] +fn clear_metadata_works() { + new_test_ext().execute_with(|| { + // metadata owner is an external proposal. + let owner = MetadataOwner::External; + // create an external proposal. + assert_ok!(Democracy::external_propose(RuntimeOrigin::signed(2), set_balance_proposal(2),)); + assert!(>::exists()); + // set metadata. + let hash = note_preimage(1); + assert_ok!(Democracy::set_metadata(RuntimeOrigin::signed(2), owner.clone(), Some(hash),)); + // fails to clear metadata with a wrong origin. + assert_noop!( + Democracy::set_metadata(RuntimeOrigin::signed(1), owner.clone(), None), + BadOrigin, + ); + // clear metadata successful. + assert_ok!(Democracy::set_metadata(RuntimeOrigin::signed(2), owner.clone(), None)); + System::assert_last_event(RuntimeEvent::Democracy(crate::Event::MetadataCleared { + owner, + hash, + })); + }); +} + +#[test] +fn set_proposal_metadata_works() { + new_test_ext().execute_with(|| { + use frame_support::traits::Hash as PreimageHash; + // invalid preimage hash. + let invalid_hash: PreimageHash = [1u8; 32].into(); + // create an external proposal. + assert_ok!(propose_set_balance(1, 2, 5)); + // metadata owner is a public proposal. + let owner = MetadataOwner::Proposal(Democracy::public_prop_count() - 1); + // fails to set non-existing preimage. + assert_noop!( + Democracy::set_metadata(RuntimeOrigin::signed(1), owner.clone(), Some(invalid_hash),), + Error::::PreimageNotExist, + ); + // note preimage. + let hash = note_preimage(1); + // fails to set a preimage if an origin is not a proposer. + assert_noop!( + Democracy::set_metadata(RuntimeOrigin::signed(3), owner.clone(), Some(hash),), + Error::::NoPermission, + ); + // set metadata successful. + assert_ok!(Democracy::set_metadata(RuntimeOrigin::signed(1), owner.clone(), Some(hash),),); + System::assert_last_event(RuntimeEvent::Democracy(crate::Event::MetadataSet { + owner, + hash, + })); + }); +} + +#[test] +fn clear_proposal_metadata_works() { + new_test_ext().execute_with(|| { + // create an external proposal. + assert_ok!(propose_set_balance(1, 2, 5)); + // metadata owner is a public proposal. + let owner = MetadataOwner::Proposal(Democracy::public_prop_count() - 1); + // set metadata. + let hash = note_preimage(1); + assert_ok!(Democracy::set_metadata(RuntimeOrigin::signed(1), owner.clone(), Some(hash),)); + // fails to clear metadata with a wrong origin. + assert_noop!( + Democracy::set_metadata(RuntimeOrigin::signed(3), owner.clone(), None), + Error::::NoPermission, + ); + // clear metadata successful. + assert_ok!(Democracy::set_metadata(RuntimeOrigin::signed(1), owner.clone(), None)); + System::assert_last_event(RuntimeEvent::Democracy(crate::Event::MetadataCleared { + owner, + hash, + })); + }); +} + +#[test] +fn set_referendum_metadata_by_root() { + new_test_ext().execute_with(|| { + let index = Democracy::inject_referendum( + 2, + set_balance_proposal(2), + VoteThreshold::SuperMajorityApprove, + 0, + ); + // metadata owner is a referendum. + let owner = MetadataOwner::Referendum(index); + // note preimage. + let hash = note_preimage(1); + // fails to set if not a root. + assert_noop!( + Democracy::set_metadata(RuntimeOrigin::signed(3), owner.clone(), Some(hash),), + Error::::NoPermission, + ); + // fails to clear if not a root. + assert_noop!( + Democracy::set_metadata(RuntimeOrigin::signed(3), owner.clone(), None,), + Error::::NoPermission, + ); + // succeed to set metadata by a root for an ongoing referendum. + assert_ok!(Democracy::set_metadata(RuntimeOrigin::root(), owner.clone(), Some(hash),)); + System::assert_last_event(RuntimeEvent::Democracy(crate::Event::MetadataSet { + owner: owner.clone(), + hash, + })); + // succeed to clear metadata by a root for an ongoing referendum. + assert_ok!(Democracy::set_metadata(RuntimeOrigin::root(), owner.clone(), None)); + System::assert_last_event(RuntimeEvent::Democracy(crate::Event::MetadataCleared { + owner, + hash, + })); + }); +} + +#[test] +fn clear_referendum_metadata_works() { + new_test_ext().execute_with(|| { + // create a referendum. + let index = Democracy::inject_referendum( + 2, + set_balance_proposal(2), + VoteThreshold::SuperMajorityApprove, + 0, + ); + // metadata owner is a referendum. + let owner = MetadataOwner::Referendum(index); + // set metadata. + let hash = note_preimage(1); + // referendum finished. + MetadataOf::::insert(owner.clone(), hash); + // no permission to clear metadata of an ongoing referendum. + assert_noop!( + Democracy::set_metadata(RuntimeOrigin::signed(1), owner.clone(), None), + Error::::NoPermission, + ); + // referendum finished. + ReferendumInfoOf::::insert( + index, + ReferendumInfo::Finished { end: 1, approved: true }, + ); + // clear metadata successful. + assert_ok!(Democracy::set_metadata(RuntimeOrigin::signed(1), owner.clone(), None)); + System::assert_last_event(RuntimeEvent::Democracy(crate::Event::MetadataCleared { + owner, + hash, + })); + }); +} diff --git a/frame/democracy/src/tests/public_proposals.rs b/frame/democracy/src/tests/public_proposals.rs index f48824dc95c5d..f9471442c6336 100644 --- a/frame/democracy/src/tests/public_proposals.rs +++ b/frame/democracy/src/tests/public_proposals.rs @@ -91,8 +91,20 @@ fn cancel_proposal_should_work() { assert_ok!(propose_set_balance(1, 2, 2)); assert_ok!(propose_set_balance(1, 4, 4)); assert_noop!(Democracy::cancel_proposal(RuntimeOrigin::signed(1), 0), BadOrigin); + let hash = note_preimage(1); + assert_ok!(Democracy::set_metadata( + RuntimeOrigin::signed(1), + MetadataOwner::Proposal(0), + Some(hash) + )); + assert!(>::get(MetadataOwner::Proposal(0)).is_some()); assert_ok!(Democracy::cancel_proposal(RuntimeOrigin::root(), 0)); - System::assert_last_event(crate::Event::ProposalCanceled { prop_index: 0 }.into()); + // metadata cleared, preimage unrequested. + assert!(>::get(MetadataOwner::Proposal(0)).is_none()); + System::assert_has_event(crate::Event::ProposalCanceled { prop_index: 0 }.into()); + System::assert_last_event( + crate::Event::MetadataCleared { owner: MetadataOwner::Proposal(0), hash }.into(), + ); assert_eq!(Democracy::backing_for(0), None); assert_eq!(Democracy::backing_for(1), Some(4)); }); diff --git a/frame/democracy/src/types.rs b/frame/democracy/src/types.rs index 4b7f1a0fac45c..25954e05498a6 100644 --- a/frame/democracy/src/types.rs +++ b/frame/democracy/src/types.rs @@ -25,6 +25,12 @@ use sp_runtime::{ RuntimeDebug, }; +/// A proposal index. +pub type PropIndex = u32; + +/// A referendum index. +pub type ReferendumIndex = u32; + /// Info regarding an ongoing referendum. #[derive(Encode, MaxEncodedLen, Decode, Default, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo)] pub struct Tally { @@ -206,3 +212,14 @@ pub enum UnvoteScope { /// Permitted to do only the changes that do not need the owner's permission. OnlyExpired, } + +/// Identifies an owner of a metadata. +#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo, MaxEncodedLen)] +pub enum MetadataOwner { + /// External proposal. + External, + /// Public proposal of the index. + Proposal(PropIndex), + /// Referendum of the index. + Referendum(ReferendumIndex), +} diff --git a/frame/democracy/src/weights.rs b/frame/democracy/src/weights.rs index 985fe8fbde781..10d0744eac029 100644 --- a/frame/democracy/src/weights.rs +++ b/frame/democracy/src/weights.rs @@ -18,25 +18,26 @@ //! Autogenerated weights for pallet_democracy //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-01-24, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-01-27, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `runner-b3zmxxc-project-145-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// ./target/production/substrate +// target/production/substrate // benchmark // pallet -// --chain=dev // --steps=50 // --repeat=20 -// --pallet=pallet_democracy // --extrinsic=* // --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=./frame/democracy/src/weights.rs +// --json-file=/builds/parity/mirrors/substrate/.git/.artifacts/bench.json +// --pallet=pallet_democracy +// --chain=dev // --header=./HEADER-APACHE2 +// --output=./frame/democracy/src/weights.rs // --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] @@ -70,6 +71,12 @@ pub trait WeightInfo { fn unlock_set(r: u32, ) -> Weight; fn remove_vote(r: u32, ) -> Weight; fn remove_other_vote(r: u32, ) -> Weight; + fn set_external_metadata() -> Weight; + fn clear_external_metadata() -> Weight; + fn set_proposal_metadata() -> Weight; + fn clear_proposal_metadata() -> Weight; + fn set_referendum_metadata() -> Weight; + fn clear_referendum_metadata() -> Weight; } /// Weights for pallet_democracy using the Substrate node and recommended hardware. @@ -87,8 +94,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `4864` // Estimated: `23409` - // Minimum execution time: 34_509 nanoseconds. - Weight::from_parts(34_781_000, 23409) + // Minimum execution time: 42_939 nanoseconds. + Weight::from_parts(43_543_000, 23409) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -98,8 +105,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `3620` // Estimated: `5705` - // Minimum execution time: 31_151 nanoseconds. - Weight::from_parts(31_566_000, 5705) + // Minimum execution time: 36_475 nanoseconds. + Weight::from_parts(37_863_000, 5705) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -111,10 +118,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) fn vote_new() -> Weight { // Proof Size summary in bytes: - // Measured: `3555` + // Measured: `3565` // Estimated: `12720` - // Minimum execution time: 42_618 nanoseconds. - Weight::from_parts(43_231_000, 12720) + // Minimum execution time: 56_372 nanoseconds. + Weight::from_parts(57_483_000, 12720) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -126,10 +133,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) fn vote_existing() -> Weight { // Proof Size summary in bytes: - // Measured: `3577` + // Measured: `3587` // Estimated: `12720` - // Minimum execution time: 42_875 nanoseconds. - Weight::from_parts(43_338_000, 12720) + // Minimum execution time: 56_789 nanoseconds. + Weight::from_parts(57_737_000, 12720) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -137,14 +144,16 @@ impl WeightInfo for SubstrateWeight { /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) /// Storage: Democracy Cancellations (r:1 w:1) /// Proof: Democracy Cancellations (max_values: None, max_size: Some(33), added: 2508, mode: MaxEncodedLen) + /// Storage: Democracy MetadataOf (r:1 w:1) + /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) fn emergency_cancel() -> Weight { // Proof Size summary in bytes: - // Measured: `320` - // Estimated: `5184` - // Minimum execution time: 16_543 nanoseconds. - Weight::from_parts(16_762_000, 5184) - .saturating_add(T::DbWeight::get().reads(2_u64)) - .saturating_add(T::DbWeight::get().writes(2_u64)) + // Measured: `398` + // Estimated: `7712` + // Minimum execution time: 24_379 nanoseconds. + Weight::from_parts(25_302_000, 7712) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) } /// Storage: Democracy PublicProps (r:1 w:1) /// Proof: Democracy PublicProps (max_values: Some(1), max_size: Some(16702), added: 17197, mode: MaxEncodedLen) @@ -152,6 +161,8 @@ impl WeightInfo for SubstrateWeight { /// Proof: Democracy DepositOf (max_values: None, max_size: Some(3230), added: 5705, mode: MaxEncodedLen) /// Storage: System Account (r:1 w:1) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Democracy MetadataOf (r:3 w:1) + /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) /// Storage: Democracy NextExternal (r:1 w:1) /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) /// Storage: Democracy ReferendumInfoOf (r:1 w:1) @@ -160,12 +171,12 @@ impl WeightInfo for SubstrateWeight { /// Proof: Democracy Blacklist (max_values: None, max_size: Some(3238), added: 5713, mode: MaxEncodedLen) fn blacklist() -> Weight { // Proof Size summary in bytes: - // Measured: `5958` - // Estimated: `28808` - // Minimum execution time: 70_135 nanoseconds. - Weight::from_parts(70_616_000, 28808) - .saturating_add(T::DbWeight::get().reads(5_u64)) - .saturating_add(T::DbWeight::get().writes(6_u64)) + // Measured: `6036` + // Estimated: `36392` + // Minimum execution time: 100_345 nanoseconds. + Weight::from_parts(102_233_000, 36392) + .saturating_add(T::DbWeight::get().reads(8_u64)) + .saturating_add(T::DbWeight::get().writes(7_u64)) } /// Storage: Democracy NextExternal (r:1 w:1) /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) @@ -175,8 +186,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `3448` // Estimated: `6340` - // Minimum execution time: 12_580 nanoseconds. - Weight::from_parts(12_987_000, 6340) + // Minimum execution time: 13_155 nanoseconds. + Weight::from_parts(14_158_000, 6340) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -186,8 +197,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_320 nanoseconds. - Weight::from_ref_time(3_513_000) + // Minimum execution time: 2_961 nanoseconds. + Weight::from_ref_time(3_139_000) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: Democracy NextExternal (r:0 w:1) @@ -196,37 +207,41 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_407 nanoseconds. - Weight::from_ref_time(3_565_000) + // Minimum execution time: 3_040 nanoseconds. + Weight::from_ref_time(3_261_000) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: Democracy NextExternal (r:1 w:1) /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) /// Storage: Democracy ReferendumCount (r:1 w:1) /// Proof: Democracy ReferendumCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Democracy MetadataOf (r:1 w:2) + /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) /// Storage: Democracy ReferendumInfoOf (r:0 w:1) /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) fn fast_track() -> Weight { // Proof Size summary in bytes: - // Measured: `212` - // Estimated: `1126` - // Minimum execution time: 16_831 nanoseconds. - Weight::from_parts(17_155_000, 1126) - .saturating_add(T::DbWeight::get().reads(2_u64)) - .saturating_add(T::DbWeight::get().writes(3_u64)) + // Measured: `286` + // Estimated: `3654` + // Minimum execution time: 26_666 nanoseconds. + Weight::from_parts(28_014_000, 3654) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(5_u64)) } /// Storage: Democracy NextExternal (r:1 w:1) /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) /// Storage: Democracy Blacklist (r:1 w:1) /// Proof: Democracy Blacklist (max_values: None, max_size: Some(3238), added: 5713, mode: MaxEncodedLen) + /// Storage: Democracy MetadataOf (r:1 w:1) + /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) fn veto_external() -> Weight { // Proof Size summary in bytes: - // Measured: `3477` - // Estimated: `6340` - // Minimum execution time: 22_072 nanoseconds. - Weight::from_parts(22_517_000, 6340) - .saturating_add(T::DbWeight::get().reads(2_u64)) - .saturating_add(T::DbWeight::get().writes(2_u64)) + // Measured: `3551` + // Estimated: `8868` + // Minimum execution time: 30_180 nanoseconds. + Weight::from_parts(31_593_000, 8868) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) } /// Storage: Democracy PublicProps (r:1 w:1) /// Proof: Democracy PublicProps (max_values: Some(1), max_size: Some(16702), added: 17197, mode: MaxEncodedLen) @@ -234,24 +249,29 @@ impl WeightInfo for SubstrateWeight { /// Proof: Democracy DepositOf (max_values: None, max_size: Some(3230), added: 5705, mode: MaxEncodedLen) /// Storage: System Account (r:1 w:1) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Democracy MetadataOf (r:1 w:1) + /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) fn cancel_proposal() -> Weight { // Proof Size summary in bytes: - // Measured: `5837` - // Estimated: `25505` - // Minimum execution time: 56_925 nanoseconds. - Weight::from_parts(57_253_000, 25505) - .saturating_add(T::DbWeight::get().reads(3_u64)) - .saturating_add(T::DbWeight::get().writes(3_u64)) + // Measured: `5915` + // Estimated: `28033` + // Minimum execution time: 80_780 nanoseconds. + Weight::from_parts(82_070_000, 28033) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().writes(4_u64)) } + /// Storage: Democracy MetadataOf (r:1 w:1) + /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) /// Storage: Democracy ReferendumInfoOf (r:0 w:1) /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) fn cancel_referendum() -> Weight { // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 8_582 nanoseconds. - Weight::from_ref_time(8_754_000) - .saturating_add(T::DbWeight::get().writes(1_u64)) + // Measured: `271` + // Estimated: `2528` + // Minimum execution time: 18_117 nanoseconds. + Weight::from_parts(19_027_000, 2528) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) } /// Storage: Democracy LowestUnbaked (r:1 w:1) /// Proof: Democracy LowestUnbaked (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) @@ -262,12 +282,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 99]`. fn on_initialize_base(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `207 + r * (117 ±0)` + // Measured: `244 + r * (117 ±0)` // Estimated: `998 + r * (2676 ±0)` - // Minimum execution time: 6_665 nanoseconds. - Weight::from_parts(9_219_932, 998) - // Standard Error: 4_236 - .saturating_add(Weight::from_ref_time(2_194_623).saturating_mul(r.into())) + // Minimum execution time: 7_093 nanoseconds. + Weight::from_parts(8_792_955, 998) + // Standard Error: 6_630 + .saturating_add(Weight::from_ref_time(3_091_565).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(1_u64)) @@ -288,12 +308,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 99]`. fn on_initialize_base_with_launch_period(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `207 + r * (117 ±0)` + // Measured: `244 + r * (117 ±0)` // Estimated: `19318 + r * (2676 ±0)` - // Minimum execution time: 9_842 nanoseconds. - Weight::from_parts(11_932_535, 19318) - // Standard Error: 4_413 - .saturating_add(Weight::from_ref_time(2_199_644).saturating_mul(r.into())) + // Minimum execution time: 10_372 nanoseconds. + Weight::from_parts(10_961_165, 19318) + // Standard Error: 7_284 + .saturating_add(Weight::from_ref_time(3_112_573).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(1_u64)) @@ -308,12 +328,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 99]`. fn delegate(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `948 + r * (139 ±0)` + // Measured: `958 + r * (139 ±0)` // Estimated: `22584 + r * (2676 ±0)` - // Minimum execution time: 34_740 nanoseconds. - Weight::from_parts(38_366_374, 22584) - // Standard Error: 4_868 - .saturating_add(Weight::from_ref_time(3_286_516).saturating_mul(r.into())) + // Minimum execution time: 36_618 nanoseconds. + Weight::from_parts(42_803_184, 22584) + // Standard Error: 7_268 + .saturating_add(Weight::from_ref_time(4_537_902).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(4_u64)) @@ -327,12 +347,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 99]`. fn undelegate(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `547 + r * (139 ±0)` + // Measured: `557 + r * (139 ±0)` // Estimated: `12540 + r * (2676 ±0)` - // Minimum execution time: 19_516 nanoseconds. - Weight::from_parts(21_629_605, 12540) - // Standard Error: 4_401 - .saturating_add(Weight::from_ref_time(3_238_187).saturating_mul(r.into())) + // Minimum execution time: 19_758 nanoseconds. + Weight::from_parts(21_641_793, 12540) + // Standard Error: 6_889 + .saturating_add(Weight::from_ref_time(4_478_884).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(2_u64)) @@ -345,8 +365,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_291 nanoseconds. - Weight::from_ref_time(3_485_000) + // Minimum execution time: 2_844 nanoseconds. + Weight::from_ref_time(3_017_000) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: Democracy VotingOf (r:1 w:1) @@ -358,12 +378,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 99]`. fn unlock_remove(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `617` + // Measured: `627` // Estimated: `12647` - // Minimum execution time: 19_357 nanoseconds. - Weight::from_parts(24_014_517, 12647) - // Standard Error: 994 - .saturating_add(Weight::from_ref_time(17_096).saturating_mul(r.into())) + // Minimum execution time: 20_380 nanoseconds. + Weight::from_parts(28_295_875, 12647) + // Standard Error: 2_331 + .saturating_add(Weight::from_ref_time(67_348).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -376,12 +396,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[0, 99]`. fn unlock_set(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `618 + r * (22 ±0)` + // Measured: `628 + r * (22 ±0)` // Estimated: `12647` - // Minimum execution time: 22_340 nanoseconds. - Weight::from_parts(23_355_734, 12647) - // Standard Error: 548 - .saturating_add(Weight::from_ref_time(64_308).saturating_mul(r.into())) + // Minimum execution time: 24_475 nanoseconds. + Weight::from_parts(27_102_576, 12647) + // Standard Error: 1_464 + .saturating_add(Weight::from_ref_time(128_921).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -392,12 +412,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[1, 100]`. fn remove_vote(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `781 + r * (26 ±0)` + // Measured: `791 + r * (26 ±0)` // Estimated: `8946` - // Minimum execution time: 14_542 nanoseconds. - Weight::from_parts(16_411_916, 8946) - // Standard Error: 839 - .saturating_add(Weight::from_ref_time(73_268).saturating_mul(r.into())) + // Minimum execution time: 15_039 nanoseconds. + Weight::from_parts(19_252_498, 8946) + // Standard Error: 1_798 + .saturating_add(Weight::from_ref_time(131_855).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -408,15 +428,97 @@ impl WeightInfo for SubstrateWeight { /// The range of component `r` is `[1, 100]`. fn remove_other_vote(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `781 + r * (26 ±0)` + // Measured: `791 + r * (26 ±0)` // Estimated: `8946` - // Minimum execution time: 14_463 nanoseconds. - Weight::from_parts(16_302_901, 8946) - // Standard Error: 809 - .saturating_add(Weight::from_ref_time(73_692).saturating_mul(r.into())) + // Minimum execution time: 14_837 nanoseconds. + Weight::from_parts(19_144_929, 8946) + // Standard Error: 1_875 + .saturating_add(Weight::from_ref_time(136_819).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } + /// Storage: Democracy NextExternal (r:1 w:0) + /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) + /// Storage: Preimage StatusFor (r:1 w:0) + /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) + /// Storage: Democracy MetadataOf (r:0 w:1) + /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) + fn set_external_metadata() -> Weight { + // Proof Size summary in bytes: + // Measured: `356` + // Estimated: `3193` + // Minimum execution time: 17_338 nanoseconds. + Weight::from_parts(17_946_000, 3193) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: Democracy NextExternal (r:1 w:0) + /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) + /// Storage: Democracy MetadataOf (r:1 w:1) + /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) + fn clear_external_metadata() -> Weight { + // Proof Size summary in bytes: + // Measured: `286` + // Estimated: `3155` + // Minimum execution time: 15_364 nanoseconds. + Weight::from_parts(15_990_000, 3155) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: Democracy PublicProps (r:1 w:0) + /// Proof: Democracy PublicProps (max_values: Some(1), max_size: Some(16702), added: 17197, mode: MaxEncodedLen) + /// Storage: Preimage StatusFor (r:1 w:0) + /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) + /// Storage: Democracy MetadataOf (r:0 w:1) + /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) + fn set_proposal_metadata() -> Weight { + // Proof Size summary in bytes: + // Measured: `4919` + // Estimated: `19763` + // Minimum execution time: 37_147 nanoseconds. + Weight::from_parts(37_778_000, 19763) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: Democracy PublicProps (r:1 w:0) + /// Proof: Democracy PublicProps (max_values: Some(1), max_size: Some(16702), added: 17197, mode: MaxEncodedLen) + /// Storage: Democracy MetadataOf (r:1 w:1) + /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) + fn clear_proposal_metadata() -> Weight { + // Proof Size summary in bytes: + // Measured: `4853` + // Estimated: `19725` + // Minimum execution time: 34_118 nanoseconds. + Weight::from_parts(34_737_000, 19725) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: Preimage StatusFor (r:1 w:0) + /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) + /// Storage: Democracy MetadataOf (r:0 w:1) + /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) + fn set_referendum_metadata() -> Weight { + // Proof Size summary in bytes: + // Measured: `144` + // Estimated: `2566` + // Minimum execution time: 12_787 nanoseconds. + Weight::from_parts(13_463_000, 2566) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: Democracy ReferendumInfoOf (r:1 w:0) + /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) + /// Storage: Democracy MetadataOf (r:1 w:1) + /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) + fn clear_referendum_metadata() -> Weight { + // Proof Size summary in bytes: + // Measured: `302` + // Estimated: `5204` + // Minimum execution time: 17_636 nanoseconds. + Weight::from_parts(18_399_000, 5204) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } } // For backwards compatibility and tests @@ -433,8 +535,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `4864` // Estimated: `23409` - // Minimum execution time: 34_509 nanoseconds. - Weight::from_parts(34_781_000, 23409) + // Minimum execution time: 42_939 nanoseconds. + Weight::from_parts(43_543_000, 23409) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -444,8 +546,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `3620` // Estimated: `5705` - // Minimum execution time: 31_151 nanoseconds. - Weight::from_parts(31_566_000, 5705) + // Minimum execution time: 36_475 nanoseconds. + Weight::from_parts(37_863_000, 5705) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -457,10 +559,10 @@ impl WeightInfo for () { /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) fn vote_new() -> Weight { // Proof Size summary in bytes: - // Measured: `3555` + // Measured: `3565` // Estimated: `12720` - // Minimum execution time: 42_618 nanoseconds. - Weight::from_parts(43_231_000, 12720) + // Minimum execution time: 56_372 nanoseconds. + Weight::from_parts(57_483_000, 12720) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -472,10 +574,10 @@ impl WeightInfo for () { /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) fn vote_existing() -> Weight { // Proof Size summary in bytes: - // Measured: `3577` + // Measured: `3587` // Estimated: `12720` - // Minimum execution time: 42_875 nanoseconds. - Weight::from_parts(43_338_000, 12720) + // Minimum execution time: 56_789 nanoseconds. + Weight::from_parts(57_737_000, 12720) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -483,14 +585,16 @@ impl WeightInfo for () { /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) /// Storage: Democracy Cancellations (r:1 w:1) /// Proof: Democracy Cancellations (max_values: None, max_size: Some(33), added: 2508, mode: MaxEncodedLen) + /// Storage: Democracy MetadataOf (r:1 w:1) + /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) fn emergency_cancel() -> Weight { // Proof Size summary in bytes: - // Measured: `320` - // Estimated: `5184` - // Minimum execution time: 16_543 nanoseconds. - Weight::from_parts(16_762_000, 5184) - .saturating_add(RocksDbWeight::get().reads(2_u64)) - .saturating_add(RocksDbWeight::get().writes(2_u64)) + // Measured: `398` + // Estimated: `7712` + // Minimum execution time: 24_379 nanoseconds. + Weight::from_parts(25_302_000, 7712) + .saturating_add(RocksDbWeight::get().reads(3_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) } /// Storage: Democracy PublicProps (r:1 w:1) /// Proof: Democracy PublicProps (max_values: Some(1), max_size: Some(16702), added: 17197, mode: MaxEncodedLen) @@ -498,6 +602,8 @@ impl WeightInfo for () { /// Proof: Democracy DepositOf (max_values: None, max_size: Some(3230), added: 5705, mode: MaxEncodedLen) /// Storage: System Account (r:1 w:1) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Democracy MetadataOf (r:3 w:1) + /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) /// Storage: Democracy NextExternal (r:1 w:1) /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) /// Storage: Democracy ReferendumInfoOf (r:1 w:1) @@ -506,12 +612,12 @@ impl WeightInfo for () { /// Proof: Democracy Blacklist (max_values: None, max_size: Some(3238), added: 5713, mode: MaxEncodedLen) fn blacklist() -> Weight { // Proof Size summary in bytes: - // Measured: `5958` - // Estimated: `28808` - // Minimum execution time: 70_135 nanoseconds. - Weight::from_parts(70_616_000, 28808) - .saturating_add(RocksDbWeight::get().reads(5_u64)) - .saturating_add(RocksDbWeight::get().writes(6_u64)) + // Measured: `6036` + // Estimated: `36392` + // Minimum execution time: 100_345 nanoseconds. + Weight::from_parts(102_233_000, 36392) + .saturating_add(RocksDbWeight::get().reads(8_u64)) + .saturating_add(RocksDbWeight::get().writes(7_u64)) } /// Storage: Democracy NextExternal (r:1 w:1) /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) @@ -521,8 +627,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `3448` // Estimated: `6340` - // Minimum execution time: 12_580 nanoseconds. - Weight::from_parts(12_987_000, 6340) + // Minimum execution time: 13_155 nanoseconds. + Weight::from_parts(14_158_000, 6340) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -532,8 +638,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_320 nanoseconds. - Weight::from_ref_time(3_513_000) + // Minimum execution time: 2_961 nanoseconds. + Weight::from_ref_time(3_139_000) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: Democracy NextExternal (r:0 w:1) @@ -542,37 +648,41 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_407 nanoseconds. - Weight::from_ref_time(3_565_000) + // Minimum execution time: 3_040 nanoseconds. + Weight::from_ref_time(3_261_000) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: Democracy NextExternal (r:1 w:1) /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) /// Storage: Democracy ReferendumCount (r:1 w:1) /// Proof: Democracy ReferendumCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Democracy MetadataOf (r:1 w:2) + /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) /// Storage: Democracy ReferendumInfoOf (r:0 w:1) /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) fn fast_track() -> Weight { // Proof Size summary in bytes: - // Measured: `212` - // Estimated: `1126` - // Minimum execution time: 16_831 nanoseconds. - Weight::from_parts(17_155_000, 1126) - .saturating_add(RocksDbWeight::get().reads(2_u64)) - .saturating_add(RocksDbWeight::get().writes(3_u64)) + // Measured: `286` + // Estimated: `3654` + // Minimum execution time: 26_666 nanoseconds. + Weight::from_parts(28_014_000, 3654) + .saturating_add(RocksDbWeight::get().reads(3_u64)) + .saturating_add(RocksDbWeight::get().writes(5_u64)) } /// Storage: Democracy NextExternal (r:1 w:1) /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) /// Storage: Democracy Blacklist (r:1 w:1) /// Proof: Democracy Blacklist (max_values: None, max_size: Some(3238), added: 5713, mode: MaxEncodedLen) + /// Storage: Democracy MetadataOf (r:1 w:1) + /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) fn veto_external() -> Weight { // Proof Size summary in bytes: - // Measured: `3477` - // Estimated: `6340` - // Minimum execution time: 22_072 nanoseconds. - Weight::from_parts(22_517_000, 6340) - .saturating_add(RocksDbWeight::get().reads(2_u64)) - .saturating_add(RocksDbWeight::get().writes(2_u64)) + // Measured: `3551` + // Estimated: `8868` + // Minimum execution time: 30_180 nanoseconds. + Weight::from_parts(31_593_000, 8868) + .saturating_add(RocksDbWeight::get().reads(3_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) } /// Storage: Democracy PublicProps (r:1 w:1) /// Proof: Democracy PublicProps (max_values: Some(1), max_size: Some(16702), added: 17197, mode: MaxEncodedLen) @@ -580,24 +690,29 @@ impl WeightInfo for () { /// Proof: Democracy DepositOf (max_values: None, max_size: Some(3230), added: 5705, mode: MaxEncodedLen) /// Storage: System Account (r:1 w:1) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Democracy MetadataOf (r:1 w:1) + /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) fn cancel_proposal() -> Weight { // Proof Size summary in bytes: - // Measured: `5837` - // Estimated: `25505` - // Minimum execution time: 56_925 nanoseconds. - Weight::from_parts(57_253_000, 25505) - .saturating_add(RocksDbWeight::get().reads(3_u64)) - .saturating_add(RocksDbWeight::get().writes(3_u64)) + // Measured: `5915` + // Estimated: `28033` + // Minimum execution time: 80_780 nanoseconds. + Weight::from_parts(82_070_000, 28033) + .saturating_add(RocksDbWeight::get().reads(4_u64)) + .saturating_add(RocksDbWeight::get().writes(4_u64)) } + /// Storage: Democracy MetadataOf (r:1 w:1) + /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) /// Storage: Democracy ReferendumInfoOf (r:0 w:1) /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) fn cancel_referendum() -> Weight { // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 8_582 nanoseconds. - Weight::from_ref_time(8_754_000) - .saturating_add(RocksDbWeight::get().writes(1_u64)) + // Measured: `271` + // Estimated: `2528` + // Minimum execution time: 18_117 nanoseconds. + Weight::from_parts(19_027_000, 2528) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) } /// Storage: Democracy LowestUnbaked (r:1 w:1) /// Proof: Democracy LowestUnbaked (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) @@ -608,12 +723,12 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 99]`. fn on_initialize_base(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `207 + r * (117 ±0)` + // Measured: `244 + r * (117 ±0)` // Estimated: `998 + r * (2676 ±0)` - // Minimum execution time: 6_665 nanoseconds. - Weight::from_parts(9_219_932, 998) - // Standard Error: 4_236 - .saturating_add(Weight::from_ref_time(2_194_623).saturating_mul(r.into())) + // Minimum execution time: 7_093 nanoseconds. + Weight::from_parts(8_792_955, 998) + // Standard Error: 6_630 + .saturating_add(Weight::from_ref_time(3_091_565).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(1_u64)) @@ -634,12 +749,12 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 99]`. fn on_initialize_base_with_launch_period(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `207 + r * (117 ±0)` + // Measured: `244 + r * (117 ±0)` // Estimated: `19318 + r * (2676 ±0)` - // Minimum execution time: 9_842 nanoseconds. - Weight::from_parts(11_932_535, 19318) - // Standard Error: 4_413 - .saturating_add(Weight::from_ref_time(2_199_644).saturating_mul(r.into())) + // Minimum execution time: 10_372 nanoseconds. + Weight::from_parts(10_961_165, 19318) + // Standard Error: 7_284 + .saturating_add(Weight::from_ref_time(3_112_573).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(1_u64)) @@ -654,12 +769,12 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 99]`. fn delegate(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `948 + r * (139 ±0)` + // Measured: `958 + r * (139 ±0)` // Estimated: `22584 + r * (2676 ±0)` - // Minimum execution time: 34_740 nanoseconds. - Weight::from_parts(38_366_374, 22584) - // Standard Error: 4_868 - .saturating_add(Weight::from_ref_time(3_286_516).saturating_mul(r.into())) + // Minimum execution time: 36_618 nanoseconds. + Weight::from_parts(42_803_184, 22584) + // Standard Error: 7_268 + .saturating_add(Weight::from_ref_time(4_537_902).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(4_u64)) @@ -673,12 +788,12 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 99]`. fn undelegate(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `547 + r * (139 ±0)` + // Measured: `557 + r * (139 ±0)` // Estimated: `12540 + r * (2676 ±0)` - // Minimum execution time: 19_516 nanoseconds. - Weight::from_parts(21_629_605, 12540) - // Standard Error: 4_401 - .saturating_add(Weight::from_ref_time(3_238_187).saturating_mul(r.into())) + // Minimum execution time: 19_758 nanoseconds. + Weight::from_parts(21_641_793, 12540) + // Standard Error: 6_889 + .saturating_add(Weight::from_ref_time(4_478_884).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r.into()))) .saturating_add(RocksDbWeight::get().writes(2_u64)) @@ -691,8 +806,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_291 nanoseconds. - Weight::from_ref_time(3_485_000) + // Minimum execution time: 2_844 nanoseconds. + Weight::from_ref_time(3_017_000) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: Democracy VotingOf (r:1 w:1) @@ -704,12 +819,12 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 99]`. fn unlock_remove(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `617` + // Measured: `627` // Estimated: `12647` - // Minimum execution time: 19_357 nanoseconds. - Weight::from_parts(24_014_517, 12647) - // Standard Error: 994 - .saturating_add(Weight::from_ref_time(17_096).saturating_mul(r.into())) + // Minimum execution time: 20_380 nanoseconds. + Weight::from_parts(28_295_875, 12647) + // Standard Error: 2_331 + .saturating_add(Weight::from_ref_time(67_348).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -722,12 +837,12 @@ impl WeightInfo for () { /// The range of component `r` is `[0, 99]`. fn unlock_set(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `618 + r * (22 ±0)` + // Measured: `628 + r * (22 ±0)` // Estimated: `12647` - // Minimum execution time: 22_340 nanoseconds. - Weight::from_parts(23_355_734, 12647) - // Standard Error: 548 - .saturating_add(Weight::from_ref_time(64_308).saturating_mul(r.into())) + // Minimum execution time: 24_475 nanoseconds. + Weight::from_parts(27_102_576, 12647) + // Standard Error: 1_464 + .saturating_add(Weight::from_ref_time(128_921).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -738,12 +853,12 @@ impl WeightInfo for () { /// The range of component `r` is `[1, 100]`. fn remove_vote(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `781 + r * (26 ±0)` + // Measured: `791 + r * (26 ±0)` // Estimated: `8946` - // Minimum execution time: 14_542 nanoseconds. - Weight::from_parts(16_411_916, 8946) - // Standard Error: 839 - .saturating_add(Weight::from_ref_time(73_268).saturating_mul(r.into())) + // Minimum execution time: 15_039 nanoseconds. + Weight::from_parts(19_252_498, 8946) + // Standard Error: 1_798 + .saturating_add(Weight::from_ref_time(131_855).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -754,13 +869,95 @@ impl WeightInfo for () { /// The range of component `r` is `[1, 100]`. fn remove_other_vote(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `781 + r * (26 ±0)` + // Measured: `791 + r * (26 ±0)` // Estimated: `8946` - // Minimum execution time: 14_463 nanoseconds. - Weight::from_parts(16_302_901, 8946) - // Standard Error: 809 - .saturating_add(Weight::from_ref_time(73_692).saturating_mul(r.into())) + // Minimum execution time: 14_837 nanoseconds. + Weight::from_parts(19_144_929, 8946) + // Standard Error: 1_875 + .saturating_add(Weight::from_ref_time(136_819).saturating_mul(r.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } + /// Storage: Democracy NextExternal (r:1 w:0) + /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) + /// Storage: Preimage StatusFor (r:1 w:0) + /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) + /// Storage: Democracy MetadataOf (r:0 w:1) + /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) + fn set_external_metadata() -> Weight { + // Proof Size summary in bytes: + // Measured: `356` + // Estimated: `3193` + // Minimum execution time: 17_338 nanoseconds. + Weight::from_parts(17_946_000, 3193) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: Democracy NextExternal (r:1 w:0) + /// Proof: Democracy NextExternal (max_values: Some(1), max_size: Some(132), added: 627, mode: MaxEncodedLen) + /// Storage: Democracy MetadataOf (r:1 w:1) + /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) + fn clear_external_metadata() -> Weight { + // Proof Size summary in bytes: + // Measured: `286` + // Estimated: `3155` + // Minimum execution time: 15_364 nanoseconds. + Weight::from_parts(15_990_000, 3155) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: Democracy PublicProps (r:1 w:0) + /// Proof: Democracy PublicProps (max_values: Some(1), max_size: Some(16702), added: 17197, mode: MaxEncodedLen) + /// Storage: Preimage StatusFor (r:1 w:0) + /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) + /// Storage: Democracy MetadataOf (r:0 w:1) + /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) + fn set_proposal_metadata() -> Weight { + // Proof Size summary in bytes: + // Measured: `4919` + // Estimated: `19763` + // Minimum execution time: 37_147 nanoseconds. + Weight::from_parts(37_778_000, 19763) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: Democracy PublicProps (r:1 w:0) + /// Proof: Democracy PublicProps (max_values: Some(1), max_size: Some(16702), added: 17197, mode: MaxEncodedLen) + /// Storage: Democracy MetadataOf (r:1 w:1) + /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) + fn clear_proposal_metadata() -> Weight { + // Proof Size summary in bytes: + // Measured: `4853` + // Estimated: `19725` + // Minimum execution time: 34_118 nanoseconds. + Weight::from_parts(34_737_000, 19725) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: Preimage StatusFor (r:1 w:0) + /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) + /// Storage: Democracy MetadataOf (r:0 w:1) + /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) + fn set_referendum_metadata() -> Weight { + // Proof Size summary in bytes: + // Measured: `144` + // Estimated: `2566` + // Minimum execution time: 12_787 nanoseconds. + Weight::from_parts(13_463_000, 2566) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: Democracy ReferendumInfoOf (r:1 w:0) + /// Proof: Democracy ReferendumInfoOf (max_values: None, max_size: Some(201), added: 2676, mode: MaxEncodedLen) + /// Storage: Democracy MetadataOf (r:1 w:1) + /// Proof: Democracy MetadataOf (max_values: None, max_size: Some(53), added: 2528, mode: MaxEncodedLen) + fn clear_referendum_metadata() -> Weight { + // Proof Size summary in bytes: + // Measured: `302` + // Estimated: `5204` + // Minimum execution time: 17_636 nanoseconds. + Weight::from_parts(18_399_000, 5204) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } } diff --git a/frame/referenda/src/benchmarking.rs b/frame/referenda/src/benchmarking.rs index 62b37857f2567..ea44beeb3994f 100644 --- a/frame/referenda/src/benchmarking.rs +++ b/frame/referenda/src/benchmarking.rs @@ -33,7 +33,6 @@ use sp_runtime::traits::Bounded as ArithBounded; const SEED: u32 = 0; -#[allow(dead_code)] fn assert_last_event, I: 'static>(generic_event: >::RuntimeEvent) { frame_system::Pallet::::assert_last_event(generic_event.into()); } @@ -631,6 +630,31 @@ benchmarks_instance_pallet! { assert_matches!(info, ReferendumInfo::Rejected(..)); } + set_some_metadata { + use sp_std::borrow::Cow; + let origin = T::SubmitOrigin::try_successful_origin() + .expect("SubmitOrigin has no successful origin required for the benchmark"); + let index = create_referendum::(origin.clone()); + let hash = T::Preimages::note(Cow::from(vec![5, 6])).unwrap(); + }: set_metadata(origin, index, Some(hash)) + verify { + assert_last_event::(Event::MetadataSet { index, hash }.into()); + } + + clear_metadata { + use sp_std::borrow::Cow; + let origin = T::SubmitOrigin::try_successful_origin() + .expect("SubmitOrigin has no successful origin required for the benchmark"); + let index = create_referendum::(origin.clone()); + let hash = T::Preimages::note(Cow::from(vec![6, 7, 8])).unwrap(); + assert_ok!( + Referenda::::set_metadata(origin.clone(), index, Some(hash)) + ); + }: set_metadata(origin, index, None) + verify { + assert_last_event::(Event::MetadataCleared { index, hash }.into()); + } + impl_benchmark_test_suite!( Referenda, crate::mock::new_test_ext(), diff --git a/frame/referenda/src/lib.rs b/frame/referenda/src/lib.rs index 0b846faf88558..4491c1b40d197 100644 --- a/frame/referenda/src/lib.rs +++ b/frame/referenda/src/lib.rs @@ -72,8 +72,8 @@ use frame_support::{ v3::{Anon as ScheduleAnon, Named as ScheduleNamed}, DispatchTime, }, - Currency, LockIdentifier, OnUnbalanced, OriginTrait, PollStatus, Polling, QueryPreimage, - ReservableCurrency, StorePreimage, VoteTally, + Currency, Hash as PreimageHash, LockIdentifier, OnUnbalanced, OriginTrait, PollStatus, + Polling, QueryPreimage, ReservableCurrency, StorePreimage, VoteTally, }, BoundedVec, }; @@ -251,6 +251,16 @@ pub mod pallet { pub type DecidingCount, I: 'static = ()> = StorageMap<_, Twox64Concat, TrackIdOf, u32, ValueQuery>; + /// The metadata is a general information concerning the referendum. + /// The `PreimageHash` refers to the preimage of the `Preimages` provider which can be a JSON + /// dump or IPFS hash of a JSON file. + /// + /// Consider a garbage collection for a metadata of finished referendums to `unrequest` (remove) + /// large preimages. + #[pallet::storage] + pub type MetadataOf, I: 'static = ()> = + StorageMap<_, Blake2_128Concat, ReferendumIndex, PreimageHash>; + #[pallet::event] #[pallet::generate_deposit(pub(super) fn deposit_event)] pub enum Event, I: 'static = ()> { @@ -356,6 +366,20 @@ pub mod pallet { /// The amount placed by the account. amount: BalanceOf, }, + /// Metadata for a referendum has been set. + MetadataSet { + /// Index of the referendum. + index: ReferendumIndex, + /// Preimage hash. + hash: PreimageHash, + }, + /// Metadata for a referendum has been cleared. + MetadataCleared { + /// Index of the referendum. + index: ReferendumIndex, + /// Preimage hash. + hash: PreimageHash, + }, } #[pallet::error] @@ -384,6 +408,8 @@ pub mod pallet { NoDeposit, /// The referendum status is invalid for this operation. BadStatus, + /// The preimage does not exist. + PreimageNotExist, } #[pallet::call] @@ -540,6 +566,7 @@ pub mod pallet { Self::deposit_event(Event::::Killed { index, tally: status.tally }); Self::slash_deposit(Some(status.submission_deposit.clone())); Self::slash_deposit(status.decision_deposit.clone()); + Self::do_clear_metadata(index); let info = ReferendumInfo::Killed(frame_system::Pallet::::block_number()); ReferendumInfoFor::::insert(index, info); Ok(()) @@ -633,6 +660,40 @@ pub mod pallet { Self::deposit_event(e); Ok(()) } + + /// Set or clear metadata of a referendum. + /// + /// Parameters: + /// - `origin`: Must be `Signed` by a creator of a referendum or by anyone to clear a + /// metadata of a finished referendum. + /// - `index`: The index of a referendum to set or clear metadata for. + /// - `maybe_hash`: The hash of an on-chain stored preimage. `None` to clear a metadata. + #[pallet::call_index(8)] + #[pallet::weight( + maybe_hash.map_or( + T::WeightInfo::clear_metadata(), |_| T::WeightInfo::set_some_metadata()) + )] + pub fn set_metadata( + origin: OriginFor, + index: ReferendumIndex, + maybe_hash: Option, + ) -> DispatchResult { + let who = ensure_signed(origin)?; + if let Some(hash) = maybe_hash { + let status = Self::ensure_ongoing(index)?; + ensure!(status.submission_deposit.who == who, Error::::NoPermission); + ensure!(T::Preimages::len(&hash).is_some(), Error::::PreimageNotExist); + MetadataOf::::insert(index, hash); + Self::deposit_event(Event::::MetadataSet { index, hash }); + Ok(()) + } else { + if let Some(status) = Self::ensure_ongoing(index).ok() { + ensure!(status.submission_deposit.who == who, Error::::NoPermission); + } + Self::do_clear_metadata(index); + Ok(()) + } + } } } @@ -1204,4 +1265,11 @@ impl, I: 'static> Pallet { support_needed.passing(x, tally.support(id)) && approval_needed.passing(x, tally.approval(id)) } + + /// Clear metadata if exist for a given referendum index. + fn do_clear_metadata(index: ReferendumIndex) { + if let Some(hash) = MetadataOf::::take(index) { + Self::deposit_event(Event::::MetadataCleared { index, hash }); + } + } } diff --git a/frame/referenda/src/mock.rs b/frame/referenda/src/mock.rs index 82ae508d52b6f..f6e19d06ed5f3 100644 --- a/frame/referenda/src/mock.rs +++ b/frame/referenda/src/mock.rs @@ -32,7 +32,7 @@ use frame_system::{EnsureRoot, EnsureSignedBy}; use sp_core::H256; use sp_runtime::{ testing::Header, - traits::{BlakeTwo256, IdentityLookup}, + traits::{BlakeTwo256, Hash, IdentityLookup}, DispatchResult, Perbill, }; @@ -470,3 +470,15 @@ impl RefState { index } } + +/// note a new preimage without registering. +pub fn note_preimage(who: u64) -> PreimageHash { + use std::sync::atomic::{AtomicU8, Ordering}; + // note a new preimage on every function invoke. + static COUNTER: AtomicU8 = AtomicU8::new(0); + let data = vec![COUNTER.fetch_add(1, Ordering::Relaxed)]; + assert_ok!(Preimage::note_preimage(RuntimeOrigin::signed(who), data.clone())); + let hash = BlakeTwo256::hash(&data); + assert!(!Preimage::is_requested(&hash)); + hash +} diff --git a/frame/referenda/src/tests.rs b/frame/referenda/src/tests.rs index c109fafe332e2..034454cfcc265 100644 --- a/frame/referenda/src/tests.rs +++ b/frame/referenda/src/tests.rs @@ -578,3 +578,75 @@ fn curve_handles_all_inputs() { let threshold = test_curve.threshold(Perbill::one()); assert_eq!(threshold, Perbill::zero()); } + +#[test] +fn set_metadata_works() { + new_test_ext().execute_with(|| { + use frame_support::traits::Hash as PreimageHash; + // invalid preimage hash. + let invalid_hash: PreimageHash = [1u8; 32].into(); + // fails to set metadata for a finished referendum. + assert_ok!(Referenda::submit( + RuntimeOrigin::signed(1), + Box::new(RawOrigin::Root.into()), + set_balance_proposal_bounded(1), + DispatchTime::At(1), + )); + let index = ReferendumCount::::get() - 1; + assert_ok!(Referenda::kill(RuntimeOrigin::root(), index)); + assert_noop!( + Referenda::set_metadata(RuntimeOrigin::signed(1), index, Some(invalid_hash)), + Error::::NotOngoing, + ); + // no permission to set metadata. + assert_ok!(Referenda::submit( + RuntimeOrigin::signed(1), + Box::new(RawOrigin::Root.into()), + set_balance_proposal_bounded(1), + DispatchTime::At(1), + )); + let index = ReferendumCount::::get() - 1; + assert_noop!( + Referenda::set_metadata(RuntimeOrigin::signed(2), index, Some(invalid_hash)), + Error::::NoPermission, + ); + // preimage does not exist. + let index = ReferendumCount::::get() - 1; + assert_noop!( + Referenda::set_metadata(RuntimeOrigin::signed(1), index, Some(invalid_hash)), + Error::::PreimageNotExist, + ); + // metadata set. + let index = ReferendumCount::::get() - 1; + let hash = note_preimage(1); + assert_ok!(Referenda::set_metadata(RuntimeOrigin::signed(1), index, Some(hash))); + System::assert_last_event(RuntimeEvent::Referenda(crate::Event::MetadataSet { + index, + hash, + })); + }); +} + +#[test] +fn clear_metadata_works() { + new_test_ext().execute_with(|| { + let hash = note_preimage(1); + assert_ok!(Referenda::submit( + RuntimeOrigin::signed(1), + Box::new(RawOrigin::Root.into()), + set_balance_proposal_bounded(1), + DispatchTime::At(1), + )); + let index = ReferendumCount::::get() - 1; + assert_ok!(Referenda::set_metadata(RuntimeOrigin::signed(1), index, Some(hash))); + assert_noop!( + Referenda::set_metadata(RuntimeOrigin::signed(2), index, None), + Error::::NoPermission, + ); + assert_ok!(Referenda::set_metadata(RuntimeOrigin::signed(1), index, None),); + System::assert_last_event(RuntimeEvent::Referenda(crate::Event::MetadataCleared { + index, + hash, + })); + }); +} diff --git a/frame/referenda/src/weights.rs b/frame/referenda/src/weights.rs index 68b44e8beff90..ab49759516bd9 100644 --- a/frame/referenda/src/weights.rs +++ b/frame/referenda/src/weights.rs @@ -18,25 +18,26 @@ //! Autogenerated weights for pallet_referenda //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-01-24, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-01-27, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `runner-b3zmxxc-project-145-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// ./target/production/substrate +// target/production/substrate // benchmark // pallet -// --chain=dev // --steps=50 // --repeat=20 -// --pallet=pallet_referenda // --extrinsic=* // --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=./frame/referenda/src/weights.rs +// --json-file=/builds/parity/mirrors/substrate/.git/.artifacts/bench.json +// --pallet=pallet_referenda +// --chain=dev // --header=./HEADER-APACHE2 +// --output=./frame/referenda/src/weights.rs // --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] @@ -76,6 +77,8 @@ pub trait WeightInfo { fn nudge_referendum_continue_confirming() -> Weight; fn nudge_referendum_approved() -> Weight; fn nudge_referendum_rejected() -> Weight; + fn set_some_metadata() -> Weight; + fn clear_metadata() -> Weight; } /// Weights for pallet_referenda using the Substrate node and recommended hardware. @@ -91,8 +94,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `251` // Estimated: `109996` - // Minimum execution time: 32_207 nanoseconds. - Weight::from_parts(32_639_000, 109996) + // Minimum execution time: 34_540 nanoseconds. + Weight::from_parts(36_144_000, 109996) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -104,8 +107,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `536` // Estimated: `221835` - // Minimum execution time: 43_766 nanoseconds. - Weight::from_parts(44_494_000, 221835) + // Minimum execution time: 46_963 nanoseconds. + Weight::from_parts(48_459_000, 221835) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -119,8 +122,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `3203` // Estimated: `9817` - // Minimum execution time: 41_561 nanoseconds. - Weight::from_parts(42_180_000, 9817) + // Minimum execution time: 55_798 nanoseconds. + Weight::from_parts(58_260_000, 9817) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -134,8 +137,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `3223` // Estimated: `9817` - // Minimum execution time: 41_039 nanoseconds. - Weight::from_parts(41_673_000, 9817) + // Minimum execution time: 53_888 nanoseconds. + Weight::from_parts(57_919_000, 9817) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -149,8 +152,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `536` // Estimated: `224324` - // Minimum execution time: 52_922 nanoseconds. - Weight::from_parts(53_395_000, 224324) + // Minimum execution time: 56_121 nanoseconds. + Weight::from_parts(58_301_000, 224324) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -164,8 +167,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `536` // Estimated: `224324` - // Minimum execution time: 51_050 nanoseconds. - Weight::from_parts(51_736_000, 224324) + // Minimum execution time: 54_237 nanoseconds. + Weight::from_parts(55_681_000, 224324) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -175,8 +178,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `415` // Estimated: `2841` - // Minimum execution time: 24_102 nanoseconds. - Weight::from_parts(24_372_000, 2841) + // Minimum execution time: 25_734 nanoseconds. + Weight::from_parts(26_429_000, 2841) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -186,8 +189,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `405` // Estimated: `2841` - // Minimum execution time: 24_162 nanoseconds. - Weight::from_parts(24_547_000, 2841) + // Minimum execution time: 26_000 nanoseconds. + Weight::from_parts(26_786_000, 2841) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -199,8 +202,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `412` // Estimated: `221835` - // Minimum execution time: 32_247 nanoseconds. - Weight::from_parts(32_731_000, 221835) + // Minimum execution time: 34_567 nanoseconds. + Weight::from_parts(35_939_000, 221835) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -208,13 +211,15 @@ impl WeightInfo for SubstrateWeight { /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) /// Storage: Scheduler Agenda (r:2 w:2) /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) + /// Storage: Referenda MetadataOf (r:1 w:0) + /// Proof: Referenda MetadataOf (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) fn kill() -> Weight { // Proof Size summary in bytes: // Measured: `717` - // Estimated: `221835` - // Minimum execution time: 59_900 nanoseconds. - Weight::from_parts(60_659_000, 221835) - .saturating_add(T::DbWeight::get().reads(3_u64)) + // Estimated: `224362` + // Minimum execution time: 67_744 nanoseconds. + Weight::from_parts(70_047_000, 224362) + .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } /// Storage: Referenda TrackQueue (r:1 w:0) @@ -225,8 +230,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `174` // Estimated: `6976` - // Minimum execution time: 9_322 nanoseconds. - Weight::from_parts(9_638_000, 6976) + // Minimum execution time: 9_886 nanoseconds. + Weight::from_parts(10_406_000, 6976) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -240,8 +245,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `4661` // Estimated: `226322` - // Minimum execution time: 76_976 nanoseconds. - Weight::from_parts(77_597_000, 226322) + // Minimum execution time: 100_449 nanoseconds. + Weight::from_parts(101_812_000, 226322) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -255,8 +260,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `4661` // Estimated: `226322` - // Minimum execution time: 78_405 nanoseconds. - Weight::from_parts(78_972_000, 226322) + // Minimum execution time: 101_430 nanoseconds. + Weight::from_parts(103_704_000, 226322) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -270,8 +275,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `4682` // Estimated: `116825` - // Minimum execution time: 51_360 nanoseconds. - Weight::from_parts(51_737_000, 116825) + // Minimum execution time: 67_224 nanoseconds. + Weight::from_parts(70_596_000, 116825) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -285,8 +290,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `4668` // Estimated: `116825` - // Minimum execution time: 50_485 nanoseconds. - Weight::from_parts(51_601_000, 116825) + // Minimum execution time: 65_461 nanoseconds. + Weight::from_parts(69_624_000, 116825) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -302,8 +307,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `4642` // Estimated: `119314` - // Minimum execution time: 53_075 nanoseconds. - Weight::from_parts(54_014_000, 119314) + // Minimum execution time: 69_848 nanoseconds. + Weight::from_parts(74_480_000, 119314) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -319,8 +324,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `4676` // Estimated: `119314` - // Minimum execution time: 52_916 nanoseconds. - Weight::from_parts(53_716_000, 119314) + // Minimum execution time: 70_042 nanoseconds. + Weight::from_parts(72_912_000, 119314) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -332,8 +337,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `364` // Estimated: `112338` - // Minimum execution time: 21_920 nanoseconds. - Weight::from_parts(22_172_000, 112338) + // Minimum execution time: 23_008 nanoseconds. + Weight::from_parts(23_767_000, 112338) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -345,8 +350,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `412` // Estimated: `112338` - // Minimum execution time: 22_094 nanoseconds. - Weight::from_parts(22_314_000, 112338) + // Minimum execution time: 23_550 nanoseconds. + Weight::from_parts(24_081_000, 112338) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -356,8 +361,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `310` // Estimated: `2841` - // Minimum execution time: 15_696 nanoseconds. - Weight::from_parts(15_964_000, 2841) + // Minimum execution time: 15_850 nanoseconds. + Weight::from_parts(16_773_000, 2841) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -371,8 +376,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `412` // Estimated: `114827` - // Minimum execution time: 30_604 nanoseconds. - Weight::from_parts(31_126_000, 114827) + // Minimum execution time: 32_126 nanoseconds. + Weight::from_parts(33_313_000, 114827) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -386,8 +391,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `412` // Estimated: `114827` - // Minimum execution time: 32_961 nanoseconds. - Weight::from_parts(33_295_000, 114827) + // Minimum execution time: 34_698 nanoseconds. + Weight::from_parts(35_802_000, 114827) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -399,8 +404,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `465` // Estimated: `112338` - // Minimum execution time: 27_072 nanoseconds. - Weight::from_parts(27_405_000, 112338) + // Minimum execution time: 28_710 nanoseconds. + Weight::from_parts(29_574_000, 112338) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -412,8 +417,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `448` // Estimated: `112338` - // Minimum execution time: 27_056 nanoseconds. - Weight::from_parts(27_768_000, 112338) + // Minimum execution time: 29_030 nanoseconds. + Weight::from_parts(30_308_000, 112338) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -425,8 +430,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `465` // Estimated: `112338` - // Minimum execution time: 24_599 nanoseconds. - Weight::from_parts(25_170_000, 112338) + // Minimum execution time: 26_382 nanoseconds. + Weight::from_parts(27_219_000, 112338) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -438,8 +443,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `469` // Estimated: `112338` - // Minimum execution time: 23_737 nanoseconds. - Weight::from_parts(24_184_000, 112338) + // Minimum execution time: 25_445 nanoseconds. + Weight::from_parts(26_010_000, 112338) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -453,8 +458,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `469` // Estimated: `224358` - // Minimum execution time: 37_880 nanoseconds. - Weight::from_parts(38_537_000, 224358) + // Minimum execution time: 41_064 nanoseconds. + Weight::from_parts(42_895_000, 224358) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -466,11 +471,39 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `465` // Estimated: `112338` - // Minimum execution time: 26_898 nanoseconds. - Weight::from_parts(27_496_000, 112338) + // Minimum execution time: 29_472 nanoseconds. + Weight::from_parts(30_011_000, 112338) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } + /// Storage: Referenda ReferendumInfoFor (r:1 w:0) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: Preimage StatusFor (r:1 w:0) + /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) + /// Storage: Referenda MetadataOf (r:0 w:1) + /// Proof: Referenda MetadataOf (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + fn set_some_metadata() -> Weight { + // Proof Size summary in bytes: + // Measured: `454` + // Estimated: `5407` + // Minimum execution time: 19_389 nanoseconds. + Weight::from_parts(20_490_000, 5407) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: Referenda ReferendumInfoFor (r:1 w:0) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: Referenda MetadataOf (r:1 w:1) + /// Proof: Referenda MetadataOf (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + fn clear_metadata() -> Weight { + // Proof Size summary in bytes: + // Measured: `387` + // Estimated: `5368` + // Minimum execution time: 18_195 nanoseconds. + Weight::from_parts(19_917_000, 5368) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } } // For backwards compatibility and tests @@ -485,8 +518,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `251` // Estimated: `109996` - // Minimum execution time: 32_207 nanoseconds. - Weight::from_parts(32_639_000, 109996) + // Minimum execution time: 34_540 nanoseconds. + Weight::from_parts(36_144_000, 109996) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -498,8 +531,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `536` // Estimated: `221835` - // Minimum execution time: 43_766 nanoseconds. - Weight::from_parts(44_494_000, 221835) + // Minimum execution time: 46_963 nanoseconds. + Weight::from_parts(48_459_000, 221835) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -513,8 +546,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `3203` // Estimated: `9817` - // Minimum execution time: 41_561 nanoseconds. - Weight::from_parts(42_180_000, 9817) + // Minimum execution time: 55_798 nanoseconds. + Weight::from_parts(58_260_000, 9817) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -528,8 +561,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `3223` // Estimated: `9817` - // Minimum execution time: 41_039 nanoseconds. - Weight::from_parts(41_673_000, 9817) + // Minimum execution time: 53_888 nanoseconds. + Weight::from_parts(57_919_000, 9817) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -543,8 +576,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `536` // Estimated: `224324` - // Minimum execution time: 52_922 nanoseconds. - Weight::from_parts(53_395_000, 224324) + // Minimum execution time: 56_121 nanoseconds. + Weight::from_parts(58_301_000, 224324) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -558,8 +591,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `536` // Estimated: `224324` - // Minimum execution time: 51_050 nanoseconds. - Weight::from_parts(51_736_000, 224324) + // Minimum execution time: 54_237 nanoseconds. + Weight::from_parts(55_681_000, 224324) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -569,8 +602,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `415` // Estimated: `2841` - // Minimum execution time: 24_102 nanoseconds. - Weight::from_parts(24_372_000, 2841) + // Minimum execution time: 25_734 nanoseconds. + Weight::from_parts(26_429_000, 2841) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -580,8 +613,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `405` // Estimated: `2841` - // Minimum execution time: 24_162 nanoseconds. - Weight::from_parts(24_547_000, 2841) + // Minimum execution time: 26_000 nanoseconds. + Weight::from_parts(26_786_000, 2841) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -593,8 +626,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `412` // Estimated: `221835` - // Minimum execution time: 32_247 nanoseconds. - Weight::from_parts(32_731_000, 221835) + // Minimum execution time: 34_567 nanoseconds. + Weight::from_parts(35_939_000, 221835) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -602,13 +635,15 @@ impl WeightInfo for () { /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) /// Storage: Scheduler Agenda (r:2 w:2) /// Proof: Scheduler Agenda (max_values: None, max_size: Some(107022), added: 109497, mode: MaxEncodedLen) + /// Storage: Referenda MetadataOf (r:1 w:0) + /// Proof: Referenda MetadataOf (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) fn kill() -> Weight { // Proof Size summary in bytes: // Measured: `717` - // Estimated: `221835` - // Minimum execution time: 59_900 nanoseconds. - Weight::from_parts(60_659_000, 221835) - .saturating_add(RocksDbWeight::get().reads(3_u64)) + // Estimated: `224362` + // Minimum execution time: 67_744 nanoseconds. + Weight::from_parts(70_047_000, 224362) + .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } /// Storage: Referenda TrackQueue (r:1 w:0) @@ -619,8 +654,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `174` // Estimated: `6976` - // Minimum execution time: 9_322 nanoseconds. - Weight::from_parts(9_638_000, 6976) + // Minimum execution time: 9_886 nanoseconds. + Weight::from_parts(10_406_000, 6976) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -634,8 +669,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `4661` // Estimated: `226322` - // Minimum execution time: 76_976 nanoseconds. - Weight::from_parts(77_597_000, 226322) + // Minimum execution time: 100_449 nanoseconds. + Weight::from_parts(101_812_000, 226322) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -649,8 +684,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `4661` // Estimated: `226322` - // Minimum execution time: 78_405 nanoseconds. - Weight::from_parts(78_972_000, 226322) + // Minimum execution time: 101_430 nanoseconds. + Weight::from_parts(103_704_000, 226322) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -664,8 +699,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `4682` // Estimated: `116825` - // Minimum execution time: 51_360 nanoseconds. - Weight::from_parts(51_737_000, 116825) + // Minimum execution time: 67_224 nanoseconds. + Weight::from_parts(70_596_000, 116825) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -679,8 +714,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `4668` // Estimated: `116825` - // Minimum execution time: 50_485 nanoseconds. - Weight::from_parts(51_601_000, 116825) + // Minimum execution time: 65_461 nanoseconds. + Weight::from_parts(69_624_000, 116825) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -696,8 +731,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `4642` // Estimated: `119314` - // Minimum execution time: 53_075 nanoseconds. - Weight::from_parts(54_014_000, 119314) + // Minimum execution time: 69_848 nanoseconds. + Weight::from_parts(74_480_000, 119314) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -713,8 +748,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `4676` // Estimated: `119314` - // Minimum execution time: 52_916 nanoseconds. - Weight::from_parts(53_716_000, 119314) + // Minimum execution time: 70_042 nanoseconds. + Weight::from_parts(72_912_000, 119314) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -726,8 +761,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `364` // Estimated: `112338` - // Minimum execution time: 21_920 nanoseconds. - Weight::from_parts(22_172_000, 112338) + // Minimum execution time: 23_008 nanoseconds. + Weight::from_parts(23_767_000, 112338) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -739,8 +774,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `412` // Estimated: `112338` - // Minimum execution time: 22_094 nanoseconds. - Weight::from_parts(22_314_000, 112338) + // Minimum execution time: 23_550 nanoseconds. + Weight::from_parts(24_081_000, 112338) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -750,8 +785,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `310` // Estimated: `2841` - // Minimum execution time: 15_696 nanoseconds. - Weight::from_parts(15_964_000, 2841) + // Minimum execution time: 15_850 nanoseconds. + Weight::from_parts(16_773_000, 2841) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -765,8 +800,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `412` // Estimated: `114827` - // Minimum execution time: 30_604 nanoseconds. - Weight::from_parts(31_126_000, 114827) + // Minimum execution time: 32_126 nanoseconds. + Weight::from_parts(33_313_000, 114827) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -780,8 +815,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `412` // Estimated: `114827` - // Minimum execution time: 32_961 nanoseconds. - Weight::from_parts(33_295_000, 114827) + // Minimum execution time: 34_698 nanoseconds. + Weight::from_parts(35_802_000, 114827) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -793,8 +828,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `465` // Estimated: `112338` - // Minimum execution time: 27_072 nanoseconds. - Weight::from_parts(27_405_000, 112338) + // Minimum execution time: 28_710 nanoseconds. + Weight::from_parts(29_574_000, 112338) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -806,8 +841,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `448` // Estimated: `112338` - // Minimum execution time: 27_056 nanoseconds. - Weight::from_parts(27_768_000, 112338) + // Minimum execution time: 29_030 nanoseconds. + Weight::from_parts(30_308_000, 112338) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -819,8 +854,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `465` // Estimated: `112338` - // Minimum execution time: 24_599 nanoseconds. - Weight::from_parts(25_170_000, 112338) + // Minimum execution time: 26_382 nanoseconds. + Weight::from_parts(27_219_000, 112338) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -832,8 +867,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `469` // Estimated: `112338` - // Minimum execution time: 23_737 nanoseconds. - Weight::from_parts(24_184_000, 112338) + // Minimum execution time: 25_445 nanoseconds. + Weight::from_parts(26_010_000, 112338) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -847,8 +882,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `469` // Estimated: `224358` - // Minimum execution time: 37_880 nanoseconds. - Weight::from_parts(38_537_000, 224358) + // Minimum execution time: 41_064 nanoseconds. + Weight::from_parts(42_895_000, 224358) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -860,9 +895,37 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `465` // Estimated: `112338` - // Minimum execution time: 26_898 nanoseconds. - Weight::from_parts(27_496_000, 112338) + // Minimum execution time: 29_472 nanoseconds. + Weight::from_parts(30_011_000, 112338) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } + /// Storage: Referenda ReferendumInfoFor (r:1 w:0) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: Preimage StatusFor (r:1 w:0) + /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) + /// Storage: Referenda MetadataOf (r:0 w:1) + /// Proof: Referenda MetadataOf (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + fn set_some_metadata() -> Weight { + // Proof Size summary in bytes: + // Measured: `454` + // Estimated: `5407` + // Minimum execution time: 19_389 nanoseconds. + Weight::from_parts(20_490_000, 5407) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: Referenda ReferendumInfoFor (r:1 w:0) + /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(366), added: 2841, mode: MaxEncodedLen) + /// Storage: Referenda MetadataOf (r:1 w:1) + /// Proof: Referenda MetadataOf (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) + fn clear_metadata() -> Weight { + // Proof Size summary in bytes: + // Measured: `387` + // Estimated: `5368` + // Minimum execution time: 18_195 nanoseconds. + Weight::from_parts(19_917_000, 5368) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } } From b10767478a156c9a6ceb4afdd948525923467c97 Mon Sep 17 00:00:00 2001 From: Aaro Altonen <48052676+altonen@users.noreply.github.com> Date: Wed, 8 Feb 2023 11:04:02 +0200 Subject: [PATCH 113/162] Improve test coverage of the `Notifications` protocol (#13033) * Add handler and upgrade tests * Add tests for `behaviour.rs` * Apply review comments * Update dependencies * Apply suggestions from code review Co-authored-by: Dmitry Markin * Apply review comments * Fix clippy * Update mockall * Apply review comment --------- Co-authored-by: Dmitry Markin --- Cargo.lock | 702 +++-- client/consensus/common/Cargo.toml | 2 +- client/network/Cargo.toml | 4 + .../src/protocol/notifications/behaviour.rs | 2417 +++++++++++++++++ .../src/protocol/notifications/handler.rs | 1015 ++++++- .../src/protocol/notifications/upgrade.rs | 4 +- .../protocol/notifications/upgrade/collec.rs | 80 +- .../notifications/upgrade/notifications.rs | 18 +- client/network/sync/Cargo.toml | 2 +- 9 files changed, 3773 insertions(+), 471 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c870fb0a930ac..3e5ab65c0ce20 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -27,7 +27,7 @@ version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a76fd60b23679b7d19bd066031410fb7e458ccc5e958eb5c325888ce4baedc97" dependencies = [ - "gimli 0.27.0", + "gimli 0.27.1", ] [[package]] @@ -139,9 +139,9 @@ dependencies = [ [[package]] name = "ahash" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf6ccdb167abbf410dcb915cabd428929d7f6a04980b54a11f26a39f1c7f7107" +checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f" dependencies = [ "cfg-if", "getrandom 0.2.8", @@ -184,9 +184,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.68" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2cb2f989d18dd141ab8ae82f64d1a8cdd37e0840f73a406896cf5e99502fab61" +checksum = "224afbd727c3d6e4b90103ece64b8d1b67fbb1973b1046c2281eed3f3803f800" [[package]] name = "approx" @@ -199,9 +199,9 @@ dependencies = [ [[package]] name = "arbitrary" -version = "1.2.0" +version = "1.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29d47fbf90d5149a107494b15a7dc8d69b351be2db3bb9691740e88ec17fd880" +checksum = "3e90af4de65aa7b293ef2d09daff88501eb254f58edde2e1ac02c82d873eadad" [[package]] name = "arc-swap" @@ -308,11 +308,11 @@ checksum = "e22d1f4b888c298a027c99dc9048015fac177587de20fc30232a057dfbe24a21" [[package]] name = "assert_cmd" -version = "2.0.7" +version = "2.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa3d466004a8b4cb1bc34044240a2fd29d17607e2e3bd613eb44fd48e8100da3" +checksum = "9834fcc22e0874394a010230586367d4a3e9f11b560f469262678547e1d2575e" dependencies = [ - "bstr 1.1.0", + "bstr", "doc-comment", "predicates", "predicates-core", @@ -379,9 +379,9 @@ dependencies = [ [[package]] name = "async-trait" -version = "0.1.60" +version = "0.1.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d1d8ab452a3936018a687b20e6f7cf5363d713b732b8884001317b0e48aa3" +checksum = "1cd7fce9ba8c3c042128ce72d8b2ddbf3a05747efb67ea0313c635e10bda47a2" dependencies = [ "proc-macro2", "quote", @@ -403,9 +403,9 @@ dependencies = [ [[package]] name = "atomic-waker" -version = "1.0.0" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "065374052e7df7ee4047b1160cca5e1467a12351a40b3da123c870ba0b8eda2a" +checksum = "debc29dde2e69f9e47506b525f639ed42300fc014a3e007832592448fa8e4599" [[package]] name = "atty" @@ -435,7 +435,7 @@ dependencies = [ "cfg-if", "libc", "miniz_oxide", - "object 0.30.0", + "object 0.30.3", "rustc-demangle", ] @@ -463,12 +463,27 @@ version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" +[[package]] +name = "base64" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4a4ddaa51a5bc52a6948f74c06d20aaaddb71924eab79b8c97a8c556e942d6a" + [[package]] name = "base64ct" version = "1.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b645a089122eccb6111b4f81cbc1a49f5900ac4666bb93ac027feaecf15607bf" +[[package]] +name = "basic-toml" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e819b667739967cd44d308b8c7b71305d8bb0729ac44a248aa08f33d01950b4" +dependencies = [ + "serde", +] + [[package]] name = "beef" version = "0.5.2" @@ -546,7 +561,7 @@ name = "binary-merkle-tree" version = "4.0.0-dev" dependencies = [ "array-bytes", - "env_logger", + "env_logger 0.9.3", "hash-db", "log", "sp-core", @@ -718,18 +733,9 @@ checksum = "771fe0050b883fcc3ea2359b1a96bcfbc090b7116eae7c3c512c7a083fdf23d3" [[package]] name = "bstr" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223" -dependencies = [ - "memchr", -] - -[[package]] -name = "bstr" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b45ea9b00a7b3f2988e9a65ad3917e62123c38dba709b666506207be96d1790b" +checksum = "b7f0778972c64420fdedc63f09919c8a88bda7b25135357fd25a5d9f3257e832" dependencies = [ "memchr", "once_cell", @@ -748,9 +754,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.11.1" +version = "3.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "572f695136211188308f16ad2ca5c851a712c464060ae6974944458eb83880ba" +checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535" [[package]] name = "byte-slice-cast" @@ -778,9 +784,9 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" [[package]] name = "bytes" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfb24e866b15a1af2a1b663f10c6b6b8f397a84aadb828f12e5b289ec23a3a3c" +checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" [[package]] name = "bzip2-sys" @@ -795,9 +801,9 @@ dependencies = [ [[package]] name = "camino" -version = "1.1.1" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88ad0e1e3e88dd237a156ab9f571021b8a158caa0ae44b1968a241efb5144c1e" +checksum = "c77df041dc383319cc661b428b6961a005db4d6808d5e12536931b1ca9556055" dependencies = [ "serde", ] @@ -813,9 +819,9 @@ dependencies = [ [[package]] name = "cargo_metadata" -version = "0.15.2" +version = "0.15.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "982a0cf6a99c350d7246035613882e376d58cebe571785abc5da4f648d53ac0a" +checksum = "08a1ec454bc3eead8719cb56e15dbbfecdbc14e4b3a3ae4936cc6e31f5fc0d07" dependencies = [ "camino", "cargo-platform", @@ -833,9 +839,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cc" -version = "1.0.78" +version = "1.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a20104e2335ce8a659d6dd92a51a767a0c062599c73b343fd152cb401e828c3d" +checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" dependencies = [ "jobserver", ] @@ -911,7 +917,7 @@ name = "chain-spec-builder" version = "2.0.0" dependencies = [ "ansi_term", - "clap 4.0.32", + "clap 4.1.4", "node-cli", "rand 0.8.5", "sc-chain-spec", @@ -1027,13 +1033,13 @@ dependencies = [ [[package]] name = "clap" -version = "4.0.32" +version = "4.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7db700bc935f9e43e88d00b0850dae18a63773cfbec6d8e070fccf7fef89a39" +checksum = "f13b9c79b5d1dd500d20ef541215a6423c75829ef43117e1b4d17fd8af0b5d76" dependencies = [ "bitflags", "clap_derive", - "clap_lex 0.3.0", + "clap_lex 0.3.1", "is-terminal", "once_cell", "strsim", @@ -1042,18 +1048,18 @@ dependencies = [ [[package]] name = "clap_complete" -version = "4.0.7" +version = "4.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10861370d2ba66b0f5989f83ebf35db6421713fd92351790e7fdd6c36774c56b" +checksum = "3d6540eedc41f8a5a76cf3d8d458057dcdf817be4158a55b5f861f7a5483de75" dependencies = [ - "clap 4.0.32", + "clap 4.1.4", ] [[package]] name = "clap_derive" -version = "4.0.21" +version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0177313f9f02afc995627906bbd8967e2be069f5261954222dac78290c2b9014" +checksum = "684a277d672e91966334af371f1a7b5833f9aa00b07c84e92fbce95e00208ce8" dependencies = [ "heck", "proc-macro-error", @@ -1073,9 +1079,9 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d4198f73e42b4936b35b5bb248d81d2b595ecb170da0bac7655c54eedfa8da8" +checksum = "783fe232adfca04f90f56201b26d79682d4cd2625e0bc7290b95123afe558ade" dependencies = [ "os_str_bytes", ] @@ -1103,9 +1109,9 @@ dependencies = [ [[package]] name = "concurrent-queue" -version = "2.0.0" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd7bef69dc86e3c610e4e7aed41035e2a7ed12e72dd7530f61327a6579a4390b" +checksum = "c278839b831783b70278b14df4d45e1beb1aad306c07bb796637de9a0e323e8e" dependencies = [ "crossbeam-utils", ] @@ -1278,18 +1284,18 @@ dependencies = [ [[package]] name = "crc" -version = "3.0.0" +version = "3.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53757d12b596c16c78b83458d732a5d1a17ab3f53f2f7412f6fb57cc8a140ab3" +checksum = "86ec7a15cbe22e59248fc7eadb1907dab5ba09372595da4d73dd805ed4417dfe" dependencies = [ "crc-catalog", ] [[package]] name = "crc-catalog" -version = "2.1.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d0165d2900ae6778e36e80bbc4da3b5eefccee9ba939761f9c2882a5d9af3ff" +checksum = "9cace84e55f07e7301bae1c519df89cdad8cc3cd868413d3fdbdeca9ff3db484" [[package]] name = "crc32fast" @@ -1495,9 +1501,9 @@ dependencies = [ [[package]] name = "curve25519-dalek" -version = "4.0.0-pre.5" +version = "4.0.0-rc.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67bc65846be335cb20f4e52d49a437b773a2c1fdb42b19fc84e79e6f6771536f" +checksum = "8da00a7a9a4eb92a0a0f8e75660926d48f0d0f3c537e455c457bcdaa1e16b1ac" dependencies = [ "cfg-if", "fiat-crypto", @@ -1509,9 +1515,9 @@ dependencies = [ [[package]] name = "cxx" -version = "1.0.85" +version = "1.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5add3fc1717409d029b20c5b6903fc0c0b02fa6741d820054f4a2efa5e5816fd" +checksum = "bc831ee6a32dd495436e317595e639a587aa9907bef96fe6e6abc290ab6204e9" dependencies = [ "cc", "cxxbridge-flags", @@ -1521,9 +1527,9 @@ dependencies = [ [[package]] name = "cxx-build" -version = "1.0.85" +version = "1.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4c87959ba14bc6fbc61df77c3fcfe180fc32b93538c4f1031dd802ccb5f2ff0" +checksum = "94331d54f1b1a8895cd81049f7eaaaef9d05a7dcb4d1fd08bf3ff0806246789d" dependencies = [ "cc", "codespan-reporting", @@ -1536,15 +1542,15 @@ dependencies = [ [[package]] name = "cxxbridge-flags" -version = "1.0.85" +version = "1.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69a3e162fde4e594ed2b07d0f83c6c67b745e7f28ce58c6df5e6b6bef99dfb59" +checksum = "48dcd35ba14ca9b40d6e4b4b39961f23d835dbb8eed74565ded361d93e1feb8a" [[package]] name = "cxxbridge-macro" -version = "1.0.85" +version = "1.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e7e2adeb6a0d4a282e581096b06e1791532b7d576dcde5ccd9382acf55db8e6" +checksum = "81bbeb29798b407ccd82a3324ade1a7286e0d29851475990b612670f6f5124d2" dependencies = [ "proc-macro2", "quote", @@ -1553,9 +1559,9 @@ dependencies = [ [[package]] name = "darling" -version = "0.14.2" +version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0dd3cd20dc6b5a876612a6e5accfe7f3dd883db6d07acfbf14c128f61550dfa" +checksum = "c0808e1bd8671fb44a113a14e13497557533369847788fa2ae912b6ebfce9fa8" dependencies = [ "darling_core", "darling_macro", @@ -1563,9 +1569,9 @@ dependencies = [ [[package]] name = "darling_core" -version = "0.14.2" +version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a784d2ccaf7c98501746bf0be29b2022ba41fd62a2e622af997a03e9f972859f" +checksum = "001d80444f28e193f30c2f293455da62dcf9a6b29918a4253152ae2b1de592cb" dependencies = [ "fnv", "ident_case", @@ -1577,9 +1583,9 @@ dependencies = [ [[package]] name = "darling_macro" -version = "0.14.2" +version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7618812407e9402654622dd402b0a89dff9ba93badd6540781526117b92aab7e" +checksum = "b36230598a2d5de7ec1c6f51f72d8a99a9208daff41de2084d06e3fd3ea56685" dependencies = [ "darling_core", "quote", @@ -1799,9 +1805,9 @@ dependencies = [ [[package]] name = "dissimilar" -version = "1.0.5" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd5f0c7e4bd266b8ab2550e6238d2e74977c23c15536ac7be45e9c95e2e3fbbb" +checksum = "210ec60ae7d710bed8683e333e9d2855a8a56a3e9892b38bad3bb0d4d29b0d5e" [[package]] name = "doc-comment" @@ -1868,9 +1874,9 @@ dependencies = [ [[package]] name = "ed25519" -version = "1.5.2" +version = "1.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e9c280362032ea4203659fc489832d0204ef09f247a0506f170dafcac08c369" +checksum = "91cff35c70bba8a626e3185d8cd48cc11b5437e1a5bcd15b9b5fa3c64b6dfee7" dependencies = [ "signature", ] @@ -1905,9 +1911,9 @@ dependencies = [ [[package]] name = "either" -version = "1.8.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797" +checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" [[package]] name = "elliptic-curve" @@ -1976,6 +1982,19 @@ dependencies = [ "termcolor", ] +[[package]] +name = "env_logger" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85cdab6a89accf66733ad5a1693a4dcced6aeff64602b634530dd73c1f3ee9f0" +dependencies = [ + "humantime", + "is-terminal", + "log", + "regex", + "termcolor", +] + [[package]] name = "environmental" version = "1.1.4" @@ -2066,11 +2085,11 @@ checksum = "a214f5bb88731d436478f3ae1f8a277b62124089ba9fb67f4f93fb100ef73c90" [[package]] name = "file-per-thread-logger" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21e16290574b39ee41c71aeb90ae960c504ebaf1e2a1c87bd52aa56ed6e1a02f" +checksum = "84f2e425d9790201ba4af4630191feac6dcc98765b118d4d18e91d23c2353866" dependencies = [ - "env_logger", + "env_logger 0.10.0", "log", ] @@ -2203,7 +2222,7 @@ dependencies = [ "Inflector", "array-bytes", "chrono", - "clap 4.0.32", + "clap 4.1.4", "comfy-table", "frame-benchmarking", "frame-support", @@ -2294,7 +2313,7 @@ dependencies = [ name = "frame-election-solution-type-fuzzer" version = "2.0.0-alpha.5" dependencies = [ - "clap 4.0.32", + "clap 4.1.4", "frame-election-provider-solution-type", "frame-election-provider-support", "frame-support", @@ -2539,9 +2558,9 @@ dependencies = [ [[package]] name = "fs_extra" -version = "1.2.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2022715d62ab30faffd124d40b76f4134a550a87792276512b18d63272333394" +checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" [[package]] name = "funty" @@ -2551,9 +2570,9 @@ checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" [[package]] name = "futures" -version = "0.3.25" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38390104763dc37a5145a53c29c63c1290b5d316d6086ec32c293f6736051bb0" +checksum = "13e2792b0ff0340399d58445b88fd9770e3489eff258a4cbc1523418f12abf84" dependencies = [ "futures-channel", "futures-core", @@ -2566,9 +2585,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.25" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52ba265a92256105f45b719605a571ffe2d1f0fea3807304b522c1d778f79eed" +checksum = "2e5317663a9089767a1ec00a487df42e0ca174b61b4483213ac24448e4664df5" dependencies = [ "futures-core", "futures-sink", @@ -2576,15 +2595,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.25" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04909a7a7e4633ae6c4a9ab280aeb86da1236243a77b694a49eacd659a4bd3ac" +checksum = "ec90ff4d0fe1f57d600049061dc6bb68ed03c7d2fbd697274c41805dcb3f8608" [[package]] name = "futures-executor" -version = "0.3.25" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7acc85df6714c176ab5edf386123fafe217be88c0840ec11f199441134a074e2" +checksum = "e8de0a35a6ab97ec8869e32a2473f4b1324459e14c29275d14b10cb1fd19b50e" dependencies = [ "futures-core", "futures-task", @@ -2594,9 +2613,9 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.25" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00f5fb52a06bdcadeb54e8d3671f8888a39697dcb0b81b23b55174030427f4eb" +checksum = "bfb8371b6fb2aeb2d280374607aeabfc99d95c72edfe51692e42d3d7f0d08531" [[package]] name = "futures-lite" @@ -2615,9 +2634,9 @@ dependencies = [ [[package]] name = "futures-macro" -version = "0.3.25" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdfb8ce053d86b91919aad980c220b1fb8401a9394410e1c289ed7e66b61835d" +checksum = "95a73af87da33b5acf53acfebdc339fe592ecf5357ac7c0a7734ab9d8c876a70" dependencies = [ "proc-macro2", "quote", @@ -2631,21 +2650,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2411eed028cdf8c8034eaf21f9915f956b6c3abec4d4c7949ee67f0721127bd" dependencies = [ "futures-io", - "rustls 0.20.7", + "rustls 0.20.8", "webpki 0.22.0", ] [[package]] name = "futures-sink" -version = "0.3.25" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39c15cf1a4aa79df40f1bb462fb39676d0ad9e366c2a33b590d7c66f4f81fcf9" +checksum = "f310820bb3e8cfd46c80db4d7fb8353e15dfff853a127158425f31e0be6c8364" [[package]] name = "futures-task" -version = "0.3.25" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ffb393ac5d9a6eaa9d3fdf37ae2776656b706e200c8e16b1bdb227f5198e6ea" +checksum = "dcf79a1bf610b10f42aea489289c5a2c478a786509693b80cd39c44ccd936366" [[package]] name = "futures-timer" @@ -2655,9 +2674,9 @@ checksum = "e64b03909df88034c26dc1547e8970b91f98bdb65165d6a4e9110d94263dbb2c" [[package]] name = "futures-util" -version = "0.3.25" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "197676987abd2f9cadff84926f410af1c183608d36641465df73ae8211dc65d6" +checksum = "9c1d6de3acfef38d2be4b1f543f553131788603495be83da675e180c8d6b7bd1" dependencies = [ "futures-channel", "futures-core", @@ -2777,15 +2796,15 @@ dependencies = [ [[package]] name = "gimli" -version = "0.27.0" +version = "0.27.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dec7af912d60cdbd3677c1af9352ebae6fb8394d165568a2234df0fa00f87793" +checksum = "221996f774192f0f718773def8201c4ae31f02616a54ccfc2d358bb0e5cefdec" [[package]] name = "git2" -version = "0.16.0" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be36bc9e0546df253c0cc41fd0af34f5e92845ad8509462ec76672fac6997f5b" +checksum = "ccf7f68c2995f392c49fffb4f95ae2c873297830eb25c6bc4c114ce8f4562acc" dependencies = [ "bitflags", "libc", @@ -2796,18 +2815,18 @@ dependencies = [ [[package]] name = "glob" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" [[package]] name = "globset" -version = "0.4.9" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a1e17342619edbc21a964c2afbeb6c820c6a2560032872f397bb97ea127bd0a" +checksum = "029d74589adefde59de1a0c4f4732695c32805624aec7b68d91503d4dba79afc" dependencies = [ "aho-corasick", - "bstr 0.2.17", + "bstr", "fnv", "log", "regex", @@ -2895,9 +2914,9 @@ checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" [[package]] name = "heck" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" [[package]] name = "hermit-abi" @@ -2917,6 +2936,12 @@ dependencies = [ "libc", ] +[[package]] +name = "hermit-abi" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "856b5cb0902c2b6d65d5fd97dfa30f9b70c7538e770b98eab5ed52d8db923e01" + [[package]] name = "hex" version = "0.4.3" @@ -3053,9 +3078,9 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "hyper" -version = "0.14.23" +version = "0.14.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "034711faac9d2166cb1baf1a2fb0b60b1f277f8492fd72176c17f3515e1abd3c" +checksum = "5e011372fa0b68db8350aa7a248930ecc7839bf46d8485577d69f117a75f164c" dependencies = [ "bytes", "futures-channel", @@ -3084,7 +3109,7 @@ dependencies = [ "http", "hyper", "log", - "rustls 0.20.7", + "rustls 0.20.8", "rustls-native-certs", "tokio", "tokio-rustls", @@ -3255,12 +3280,12 @@ dependencies = [ [[package]] name = "io-lifetimes" -version = "1.0.3" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46112a93252b123d31a119a8d1a1ac19deac4fac6e0e8b0df58f0d4e5870e63c" +checksum = "1abeb7a0dd0f8181267ff8adc397075586500b81b28a73e8a0208b00fc170fb3" dependencies = [ "libc", - "windows-sys 0.42.0", + "windows-sys 0.45.0", ] [[package]] @@ -3283,20 +3308,20 @@ dependencies = [ [[package]] name = "ipnet" -version = "2.7.0" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11b0d96e660696543b251e58030cf9787df56da39dab19ad60eae7353040917e" +checksum = "30e22bd8629359895450b59ea7a776c850561b96a3b1d31321c1949d9e6c9146" [[package]] name = "is-terminal" -version = "0.4.2" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28dfb6c8100ccc63462345b67d1bbc3679177c75ee4bf59bf29c8b1d110b8189" +checksum = "22e18b0a45d56fe973d6db23972bf5bc46f988a4a2385deac9cc29572f09daef" dependencies = [ - "hermit-abi 0.2.6", + "hermit-abi 0.3.0", "io-lifetimes", "rustix", - "windows-sys 0.42.0", + "windows-sys 0.45.0", ] [[package]] @@ -3325,9 +3350,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.60" +version = "0.3.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49409df3e3bf0856b916e2ceaca09ee28e6871cf7d9ce97a692cacfdb2a25a47" +checksum = "445dde2150c55e483f3d8416706b97ec8e8237c307e5b7b4b8dd15e6af2a0730" dependencies = [ "wasm-bindgen", ] @@ -3643,9 +3668,9 @@ checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79" [[package]] name = "libgit2-sys" -version = "0.14.1+1.5.0" +version = "0.14.2+1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a07fb2692bc3593bda59de45a502bb3071659f2c515e28c71e728306b038e17" +checksum = "7f3d95f6b51075fe9810a7ae22c7095f12b98005ab364d8544797a825ce946a4" dependencies = [ "cc", "libc", @@ -3913,7 +3938,7 @@ dependencies = [ "parking_lot 0.12.1", "quinn-proto", "rand 0.8.5", - "rustls 0.20.7", + "rustls 0.20.8", "thiserror", "tokio", ] @@ -3996,7 +4021,7 @@ dependencies = [ "libp2p-core", "rcgen 0.10.0", "ring", - "rustls 0.20.7", + "rustls 0.20.8", "thiserror", "webpki 0.22.0", "x509-parser 0.14.0", @@ -4103,7 +4128,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95b09eff1b35ed3b33b877ced3a691fc7a481919c7e29c53c906226fcf55e2a1" dependencies = [ "arrayref", - "base64", + "base64 0.13.1", "digest 0.9.0", "hmac-drbg", "libsecp256k1-core", @@ -4305,9 +4330,9 @@ dependencies = [ [[package]] name = "matches" -version = "0.1.9" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" +checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5" [[package]] name = "matrixmultiply" @@ -4538,9 +4563,9 @@ dependencies = [ [[package]] name = "multihash-derive" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc076939022111618a5026d3be019fd8b366e76314538ff9a1b59ffbcbf98bcd" +checksum = "1d6d4752e6230d8ef7adf7bd5d8c4b1f6561c1014c5ba9a37445ccefe18aa1db" dependencies = [ "proc-macro-crate", "proc-macro-error", @@ -4634,9 +4659,9 @@ dependencies = [ [[package]] name = "netlink-packet-utils" -version = "0.5.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25af9cf0dc55498b7bd94a1508af7a78706aa0ab715a73c5169273e03c84845e" +checksum = "0ede8a08c71ad5a95cdd0e4e52facd37190977039a4704eb82a283f713747d34" dependencies = [ "anyhow", "byteorder", @@ -4661,9 +4686,9 @@ dependencies = [ [[package]] name = "netlink-sys" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92b654097027250401127914afb37cb1f311df6610a9891ff07a757e94199027" +checksum = "260e21fbb6f3d253a14df90eb0000a6066780a15dd901a7519ce02d77a94985b" dependencies = [ "bytes", "futures", @@ -4686,9 +4711,9 @@ dependencies = [ [[package]] name = "nix" -version = "0.26.1" +version = "0.26.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46a58d1d356c6597d08cde02c2f09d785b09e28711837b1ed667dc652c08a694" +checksum = "bfdda3d196821d6af13126e40375cdf7da646a96114af134d5f417a9a1dc8e1a" dependencies = [ "bitflags", "cfg-if", @@ -4703,7 +4728,7 @@ name = "node-bench" version = "0.9.0-dev" dependencies = [ "array-bytes", - "clap 4.0.32", + "clap 4.1.4", "derive_more", "fs_extra", "futures", @@ -4740,7 +4765,7 @@ version = "3.0.0-dev" dependencies = [ "array-bytes", "assert_cmd", - "clap 4.0.32", + "clap 4.1.4", "clap_complete", "criterion", "frame-benchmarking-cli", @@ -4750,7 +4775,7 @@ dependencies = [ "jsonrpsee", "kitchensink-runtime", "log", - "nix 0.26.1", + "nix 0.26.2", "node-executor", "node-inspect", "node-primitives", @@ -4859,7 +4884,7 @@ dependencies = [ name = "node-inspect" version = "0.9.0-dev" dependencies = [ - "clap 4.0.32", + "clap 4.1.4", "parity-scale-codec", "sc-cli", "sc-client-api", @@ -4918,7 +4943,7 @@ dependencies = [ name = "node-runtime-generate-bags" version = "3.0.0" dependencies = [ - "clap 4.0.32", + "clap 4.1.4", "generate-bags", "kitchensink-runtime", ] @@ -4927,7 +4952,7 @@ dependencies = [ name = "node-template" version = "4.0.0-dev" dependencies = [ - "clap 4.0.32", + "clap 4.1.4", "frame-benchmarking", "frame-benchmarking-cli", "frame-system", @@ -5046,9 +5071,9 @@ checksum = "2bf50223579dc7cdcfb3bfcacf7069ff68243f8c363f62ffa99cf000a6b9c451" [[package]] name = "nom" -version = "7.1.2" +version = "7.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5507769c4919c998e69e49c839d9dc6e693ede4cc4290d6ad8b41d4f09c548c" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" dependencies = [ "memchr", "minimal-lexical", @@ -5083,9 +5108,9 @@ dependencies = [ [[package]] name = "num-complex" -version = "0.4.2" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ae39348c8bc5fbd7f40c727a9925f03517afd2ab27d46702108b6a7e5414c19" +checksum = "02e0d21255c828d6f128a1e41534206671e8c3ea0c62f32291e808dc82cff17d" dependencies = [ "num-traits", ] @@ -5156,9 +5181,9 @@ dependencies = [ [[package]] name = "object" -version = "0.30.0" +version = "0.30.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "239da7f290cfa979f43f85a8efeee9a8a76d0827c356d37f9d3d7254d6b537fb" +checksum = "ea86265d3d3dcb6a27fc51bd29a4bf387fae9d2986b823079d4986af253eb439" dependencies = [ "memchr", ] @@ -5582,7 +5607,7 @@ dependencies = [ "array-bytes", "assert_matches", "bitflags", - "env_logger", + "env_logger 0.9.3", "frame-benchmarking", "frame-support", "frame-system", @@ -5947,7 +5972,7 @@ name = "pallet-mmr" version = "4.0.0-dev" dependencies = [ "array-bytes", - "env_logger", + "env_logger 0.9.3", "frame-benchmarking", "frame-support", "frame-system", @@ -6787,7 +6812,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" dependencies = [ "lock_api", - "parking_lot_core 0.9.5", + "parking_lot_core 0.9.7", ] [[package]] @@ -6806,15 +6831,15 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.5" +version = "0.9.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ff9f3fef3968a3ec5945535ed654cb38ff72d7495a25619e2247fb15a2ed9ba" +checksum = "9069cbb9f99e3a5083476ccb29ceb1de18b9118cafa53e90c9551235de2b9521" dependencies = [ "cfg-if", "libc", "redox_syscall", "smallvec", - "windows-sys 0.42.0", + "windows-sys 0.45.0", ] [[package]] @@ -6849,11 +6874,11 @@ checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" [[package]] name = "pem" -version = "1.1.0" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03c64931a1a212348ec4f3b4362585eca7159d0d09cbdf4a7f74f02173596fd4" +checksum = "a8835c273a76a90455d7344889b0964598e3316e2a79ede8e36f16bdcf2228b8" dependencies = [ - "base64", + "base64 0.13.1", ] [[package]] @@ -6873,9 +6898,9 @@ checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" [[package]] name = "pest" -version = "2.5.2" +version = "2.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f6e86fb9e7026527a0d46bc308b841d73170ef8f443e1807f6ef88526a816d4" +checksum = "4ab62d2fa33726dbe6321cc97ef96d8cde531e3eeaf858a058de53a8a6d40d8f" dependencies = [ "thiserror", "ucd-trie", @@ -6883,9 +6908,9 @@ dependencies = [ [[package]] name = "pest_derive" -version = "2.5.2" +version = "2.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96504449aa860c8dcde14f9fba5c58dc6658688ca1fe363589d6327b8662c603" +checksum = "8bf026e2d0581559db66d837fe5242320f525d85c76283c61f4d51a1238d65ea" dependencies = [ "pest", "pest_generator", @@ -6893,9 +6918,9 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.5.2" +version = "2.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "798e0220d1111ae63d66cb66a5dcb3fc2d986d520b98e49e1852bfdb11d7c5e7" +checksum = "2b27bd18aa01d91c8ed2b61ea23406a676b42d82609c6e2581fba42f0c15f17f" dependencies = [ "pest", "pest_meta", @@ -6906,20 +6931,20 @@ dependencies = [ [[package]] name = "pest_meta" -version = "2.5.2" +version = "2.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "984298b75898e30a843e278a9f2452c31e349a073a0ce6fd950a12a74464e065" +checksum = "9f02b677c1859756359fc9983c2e56a0237f18624a3789528804406b7e915e5d" dependencies = [ "once_cell", "pest", - "sha1", + "sha2 0.10.6", ] [[package]] name = "petgraph" -version = "0.6.2" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6d5014253a1331579ce62aa67443b4a658c5e7dd03d4bc6d302b94474888143" +checksum = "4dd7d28ee937e54fe3080c91faa1c3a46c06de6252988a7f4592ba2310ef22a4" dependencies = [ "fixedbitset", "indexmap", @@ -7117,9 +7142,9 @@ dependencies = [ [[package]] name = "prettyplease" -version = "0.1.22" +version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c8992a85d8e93a28bdf76137db888d3874e3b230dee5ed8bebac4c9f7617773" +checksum = "e97e3215779627f01ee256d2fad52f3d95e8e1c11e9fc6fd08f7cd455d5d5c78" dependencies = [ "proc-macro2", "syn", @@ -7140,11 +7165,10 @@ dependencies = [ [[package]] name = "proc-macro-crate" -version = "1.2.1" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eda0fc3b0fb7c975631757e14d9049da17374063edb6ebbcbc54d880d4fe94e9" +checksum = "e17d47ce914bf4de440332250b0edd23ce48c005f59fab39d3335866b114f11a" dependencies = [ - "once_cell", "thiserror", "toml", ] @@ -7175,9 +7199,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.50" +version = "1.0.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ef7d57beacfaf2d8aee5937dab7b7f28de3cb8b1828479bb5de2a7106f2bae2" +checksum = "5d727cae5b39d21da60fa540906919ad737832fe0b1c165da3a34d6548c849d6" dependencies = [ "unicode-ident", ] @@ -7221,9 +7245,9 @@ dependencies = [ [[package]] name = "prost" -version = "0.11.5" +version = "0.11.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c01db6702aa05baa3f57dec92b8eeeeb4cb19e894e73996b32a4093289e54592" +checksum = "21dc42e00223fc37204bd4aa177e69420c604ca4a183209a8f9de30c6d934698" dependencies = [ "bytes", "prost-derive", @@ -7231,9 +7255,9 @@ dependencies = [ [[package]] name = "prost-build" -version = "0.11.5" +version = "0.11.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb5320c680de74ba083512704acb90fe00f28f79207286a848e730c45dd73ed6" +checksum = "a3f8ad728fb08fe212df3c05169e940fbb6d9d16a877ddde14644a983ba2012e" dependencies = [ "bytes", "heck", @@ -7266,9 +7290,9 @@ dependencies = [ [[package]] name = "prost-derive" -version = "0.11.5" +version = "0.11.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8842bad1a5419bca14eac663ba798f6bc19c413c2fdceb5f3ba3b0932d96720" +checksum = "8bda8c0881ea9f722eb9629376db3d0b903b462477c1aafcb0566610ac28ac5d" dependencies = [ "anyhow", "itertools", @@ -7279,9 +7303,9 @@ dependencies = [ [[package]] name = "prost-types" -version = "0.11.5" +version = "0.11.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "017f79637768cde62820bc2d4fe0e45daaa027755c323ad077767c6c5f173091" +checksum = "a5e0526209433e96d83d750dd81a99118edbc55739e7e61a46764fd2ad537788" dependencies = [ "bytes", "prost", @@ -7332,7 +7356,7 @@ dependencies = [ "rand 0.8.5", "ring", "rustc-hash", - "rustls 0.20.7", + "rustls 0.20.8", "slab", "thiserror", "tinyvec", @@ -7463,9 +7487,9 @@ dependencies = [ [[package]] name = "rayon-core" -version = "1.10.1" +version = "1.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cac410af5d00ab6884528b4ab69d1e8e146e8d471201800fa1b4524126de6ad3" +checksum = "356a0625f1954f730c0201cdab48611198dc6ce21f4acff55089b5a78e6e835b" dependencies = [ "crossbeam-channel", "crossbeam-deque", @@ -7552,9 +7576,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.7.0" +version = "1.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e076559ef8e241f2ae3479e36f97bd5741c0330689e217ad51ce2c76808b868a" +checksum = "48aaa5748ba571fb95cd2c85c09f629215d3a6ece942baa100950af03a34f733" dependencies = [ "aho-corasick", "memchr", @@ -7739,16 +7763,16 @@ dependencies = [ [[package]] name = "rustix" -version = "0.36.6" +version = "0.36.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4feacf7db682c6c329c4ede12649cd36ecab0f3be5b7d74e6a20304725db4549" +checksum = "f43abb88211988493c1abb44a70efa56ff0ce98f233b7b276146f1f3f7ba9644" dependencies = [ "bitflags", "errno", "io-lifetimes", "libc", "linux-raw-sys", - "windows-sys 0.42.0", + "windows-sys 0.45.0", ] [[package]] @@ -7757,7 +7781,7 @@ version = "0.19.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "35edb675feee39aec9c99fa5ff985081995a06d594114ae14cbe797ad7b7a6d7" dependencies = [ - "base64", + "base64 0.13.1", "log", "ring", "sct 0.6.1", @@ -7766,9 +7790,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.20.7" +version = "0.20.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "539a2bfe908f471bfa933876bd1eb6a19cf2176d375f82ef7f99530a40e48c2c" +checksum = "fff78fc74d175294f4e83b28343315ffcfb114b156f0185e9741cb5570f50e2f" dependencies = [ "log", "ring", @@ -7790,11 +7814,11 @@ dependencies = [ [[package]] name = "rustls-pemfile" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0864aeff53f8c05aa08d86e5ef839d3dfcf07aeba2db32f12db0ef716e87bd55" +checksum = "d194b56d58803a43635bdc398cd17e383d6f71f9182b9a192c127ca42494a59b" dependencies = [ - "base64", + "base64 0.21.0", ] [[package]] @@ -7968,7 +7992,7 @@ version = "0.10.0-dev" dependencies = [ "array-bytes", "chrono", - "clap 4.0.32", + "clap 4.1.4", "fdlimit", "futures", "futures-timer", @@ -8305,7 +8329,7 @@ dependencies = [ "array-bytes", "assert_matches", "criterion", - "env_logger", + "env_logger 0.9.3", "lru", "num_cpus", "parity-scale-codec", @@ -8389,7 +8413,7 @@ dependencies = [ name = "sc-finality-grandpa" version = "0.10.0-dev" dependencies = [ - "ahash 0.8.2", + "ahash 0.8.3", "array-bytes", "assert_matches", "async-trait", @@ -8502,6 +8526,8 @@ dependencies = [ "libp2p", "log", "lru", + "mockall", + "multistream-select", "parity-scale-codec", "parking_lot 0.12.1", "pin-project", @@ -8530,6 +8556,7 @@ dependencies = [ "tempfile", "thiserror", "tokio", + "tokio-test", "tokio-util", "unsigned-varint", "zeroize", @@ -8589,7 +8616,7 @@ dependencies = [ name = "sc-network-gossip" version = "0.10.0-dev" dependencies = [ - "ahash 0.8.2", + "ahash 0.8.3", "futures", "futures-timer", "libp2p", @@ -8774,7 +8801,7 @@ name = "sc-rpc" version = "4.0.0-dev" dependencies = [ "assert_matches", - "env_logger", + "env_logger 0.9.3", "futures", "jsonrpsee", "log", @@ -8999,10 +9026,10 @@ dependencies = [ name = "sc-storage-monitor" version = "0.1.0" dependencies = [ - "clap 4.0.32", + "clap 4.1.4", "futures", "log", - "nix 0.26.1", + "nix 0.26.2", "sc-client-db", "sc-utils", "sp-core", @@ -9196,12 +9223,11 @@ dependencies = [ [[package]] name = "schannel" -version = "0.1.20" +version = "0.1.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88d6731146462ea25d9244b2ed5fd1d716d25c52e4d54aa4fb0f3c4e9854dbe2" +checksum = "713cfb06c7059f3588fb8044c0fad1d09e3c01d225e25b9220dbfdcf16dbb1b3" dependencies = [ - "lazy_static", - "windows-sys 0.36.1", + "windows-sys 0.42.0", ] [[package]] @@ -9210,7 +9236,7 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "772575a524feeb803e5b0fcbc6dd9f367e579488197c94c6e4023aad2305774d" dependencies = [ - "ahash 0.8.2", + "ahash 0.8.3", "cfg-if", "hashbrown 0.13.2", ] @@ -9293,9 +9319,9 @@ dependencies = [ [[package]] name = "secp256k1" -version = "0.24.2" +version = "0.24.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9512ffd81e3a3503ed401f79c33168b9148c75038956039166cd750eaa037c3" +checksum = "6b1629c9c557ef9b293568b338dddfc8208c98a18c59d722a9d53f859d9c9b62" dependencies = [ "secp256k1-sys", ] @@ -9320,9 +9346,9 @@ dependencies = [ [[package]] name = "security-framework" -version = "2.7.0" +version = "2.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bc1bb97804af6631813c55739f771071e0f2ed33ee20b68c86ec505d906356c" +checksum = "a332be01508d814fed64bf28f798a146d73792121129962fdf335bb3c49a4254" dependencies = [ "bitflags", "core-foundation", @@ -9333,9 +9359,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.6.1" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0160a13a177a45bfb43ce71c01580998474f556ad854dcbca936dd2841a5c556" +checksum = "31c9bb296072e961fcbd8853511dd39c2d8be2deb1e17c6860b1d30732b323b4" dependencies = [ "core-foundation-sys", "libc", @@ -9396,9 +9422,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.91" +version = "1.0.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "877c235533714907a8c2464236f5c4b2a17262ef1bd71f38f35ea592c8da6883" +checksum = "7434af0dc1cbd59268aa98b4c22c131c0584d2232f6fb166efb993e2832e896a" dependencies = [ "itoa", "ryu", @@ -9418,17 +9444,6 @@ dependencies = [ "opaque-debug 0.3.0", ] -[[package]] -name = "sha1" -version = "0.10.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f04293dc80c3993519f2d7f6f511707ee7094fe0c6d3406feb330cdb3540eba3" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest 0.10.6", -] - [[package]] name = "sha2" version = "0.8.2" @@ -9551,14 +9566,14 @@ checksum = "5e9f0ab6ef7eb7353d9119c170a436d1bf248eea575ac42d19d12f4e34130831" [[package]] name = "snow" -version = "0.9.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "774d05a3edae07ce6d68ea6984f3c05e9bba8927e3dd591e3b479e5b03213d0d" +checksum = "12ba5f4d4ff12bdb6a169ed51b7c48c0e0ac4b0b4b31012b2571e97d78d3201d" dependencies = [ "aes-gcm 0.9.4", "blake2", "chacha20poly1305", - "curve25519-dalek 4.0.0-pre.5", + "curve25519-dalek 4.0.0-rc.0", "rand_core 0.6.4", "ring", "rustc_version 0.4.0", @@ -9582,7 +9597,7 @@ version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "41d1c5305e39e09653383c2c7244f2f78b3bcae37cf50c64cb4789c9f5096ec2" dependencies = [ - "base64", + "base64 0.13.1", "bytes", "flate2", "futures", @@ -10070,7 +10085,7 @@ dependencies = [ name = "sp-npos-elections-fuzzer" version = "2.0.0-alpha.5" dependencies = [ - "clap 4.0.32", + "clap 4.1.4", "honggfuzz", "parity-scale-codec", "rand 0.8.5", @@ -10342,7 +10357,7 @@ dependencies = [ name = "sp-trie" version = "7.0.0" dependencies = [ - "ahash 0.8.2", + "ahash 0.8.3", "array-bytes", "criterion", "hash-db", @@ -10443,9 +10458,9 @@ dependencies = [ [[package]] name = "ss58-registry" -version = "1.36.0" +version = "1.38.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23d92659e7d18d82b803824a9ba5a6022cff101c3491d027c1c1d8d30e749284" +checksum = "e40c020d72bc0a9c5660bb71e4a6fdef081493583062c474740a7d59f55f0e7b" dependencies = [ "Inflector", "num-format", @@ -10530,7 +10545,7 @@ version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7e94b1ec00bad60e6410e058b52f1c66de3dc5fe4d62d09b3e52bb7d3b73e25" dependencies = [ - "base64", + "base64 0.13.1", "crc", "lazy_static", "md-5", @@ -10547,7 +10562,7 @@ dependencies = [ name = "subkey" version = "2.0.2" dependencies = [ - "clap 4.0.32", + "clap 4.1.4", "sc-cli", ] @@ -10575,7 +10590,7 @@ dependencies = [ name = "substrate-frame-cli" version = "4.0.0-dev" dependencies = [ - "clap 4.0.32", + "clap 4.1.4", "frame-support", "frame-system", "sc-cli", @@ -10905,9 +10920,9 @@ dependencies = [ [[package]] name = "termcolor" -version = "1.1.3" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755" +checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" dependencies = [ "winapi-util", ] @@ -10970,12 +10985,11 @@ dependencies = [ [[package]] name = "tikv-jemalloc-sys" -version = "0.5.2+5.3.0-patched" +version = "0.5.3+5.3.0-patched" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec45c14da997d0925c7835883e4d5c181f196fa142f8c19d7643d1e9af2592c3" +checksum = "a678df20055b43e57ef8cddde41cdfda9a3c1a060b67f4c5836dfb1d78543ba8" dependencies = [ "cc", - "fs_extra", "libc", ] @@ -11066,15 +11080,15 @@ dependencies = [ [[package]] name = "tinyvec_macros" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.23.0" +version = "1.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eab6d665857cc6ca78d6e80303a02cea7a7851e85dfbd77cbdc09bd129f1ef46" +checksum = "c8e00990ebabbe4c14c08aca901caed183ecd5c09562a12c824bb53d3c3fd3af" dependencies = [ "autocfg", "bytes", @@ -11107,7 +11121,7 @@ version = "0.23.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c43ee83903113e03984cb9e5cebe6c04a5116269e900e3ddba8f068a62adda59" dependencies = [ - "rustls 0.20.7", + "rustls 0.20.8", "tokio", "webpki 0.22.0", ] @@ -11154,9 +11168,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.5.10" +version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1333c76748e868a4d9d1017b5ab53171dfd095f70c712fdb4653a406547f598f" +checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" dependencies = [ "serde", ] @@ -11404,15 +11418,15 @@ dependencies = [ [[package]] name = "try-lock" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" +checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" [[package]] name = "try-runtime-cli" version = "0.10.0-dev" dependencies = [ - "clap 4.0.32", + "clap 4.1.4", "frame-remote-externalities", "frame-try-runtime", "hex", @@ -11441,10 +11455,11 @@ dependencies = [ [[package]] name = "trybuild" -version = "1.0.74" +version = "1.0.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "654bfc024d30963fce210f22f98956407fe8c8365eb85a1fa530f6f8844137ed" +checksum = "a44da5a6f2164c8e14d3bbc0657d69c5966af9f5f6930d4f600b1f5c4a673413" dependencies = [ + "basic-toml", "dissimilar", "glob", "once_cell", @@ -11452,7 +11467,6 @@ dependencies = [ "serde_derive", "serde_json", "termcolor", - "toml", ] [[package]] @@ -11468,7 +11482,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4712ee30d123ec7ae26d1e1b218395a16c87cdbaf4b3925d170d684af62ea5e8" dependencies = [ "async-trait", - "base64", + "base64 0.13.1", "futures", "log", "md-5", @@ -11518,9 +11532,9 @@ dependencies = [ [[package]] name = "unicode-bidi" -version = "0.3.8" +version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992" +checksum = "d54675592c1dbefd78cbd98db9bacd89886e1ca50692a0692baefffdeb92dd58" [[package]] name = "unicode-ident" @@ -11590,9 +11604,9 @@ dependencies = [ [[package]] name = "uuid" -version = "1.2.2" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "422ee0de9031b5b948b97a8fc04e3aa35230001a722ddd27943e0be31564ce4c" +checksum = "1674845326ee10d37ca60470760d4288a6f80f304007d92e5c53bab78c9cfd79" dependencies = [ "getrandom 0.2.8", ] @@ -11686,9 +11700,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.83" +version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eaf9f5aceeec8be17c128b2e93e031fb8a4d469bb9c4ae2d7dc1888b26887268" +checksum = "31f8dcbc21f30d9b8f2ea926ecb58f6b91192c17e9d33594b3df58b2007ca53b" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -11696,9 +11710,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.83" +version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c8ffb332579b0557b52d268b91feab8df3615f265d5270fec2a8c95b17c1142" +checksum = "95ce90fd5bcc06af55a641a86428ee4229e44e07033963a2290a8e241607ccb9" dependencies = [ "bumpalo", "log", @@ -11711,9 +11725,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.33" +version = "0.4.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23639446165ca5a5de86ae1d8896b737ae80319560fbaa4c2887b7da6e7ebd7d" +checksum = "f219e0d211ba40266969f6dbdd90636da12f75bee4fc9d6c23d1260dadb51454" dependencies = [ "cfg-if", "js-sys", @@ -11723,9 +11737,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.83" +version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "052be0f94026e6cbc75cdefc9bae13fd6052cdcaf532fa6c45e7ae33a1e6c810" +checksum = "4c21f77c0bedc37fd5dc21f897894a5ca01e7bb159884559461862ae90c0b4c5" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -11733,9 +11747,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.83" +version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c" +checksum = "2aff81306fcac3c7515ad4e177f521b5c9a15f2b08f4e32d823066102f35a5f6" dependencies = [ "proc-macro2", "quote", @@ -11746,15 +11760,15 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.83" +version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c38c045535d93ec4f0b4defec448e4291638ee608530863b1e2ba115d4fff7f" +checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d" [[package]] name = "wasm-encoder" -version = "0.20.0" +version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05632e0a66a6ed8cca593c24223aabd6262f256c3693ad9822c315285f010614" +checksum = "9a584273ccc2d9311f1dd19dc3fb26054661fa3e373d53ede5d1144ba07a9acd" dependencies = [ "leb128", ] @@ -11958,7 +11972,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "830570847f905b8f6d2ca635c33cf42ce701dd8e4abd7d1806c631f8f06e9e4b" dependencies = [ "anyhow", - "base64", + "base64 0.13.1", "bincode", "directories-next", "file-per-thread-logger", @@ -12095,9 +12109,9 @@ dependencies = [ [[package]] name = "wast" -version = "50.0.0" +version = "52.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2cbb59d4ac799842791fe7e806fa5dbbf6b5554d538e51cc8e176db6ff0ae34" +checksum = "15942180f265280eede7bc38b239e9770031d1821c02d905284216c645316430" dependencies = [ "leb128", "memchr", @@ -12107,18 +12121,18 @@ dependencies = [ [[package]] name = "wat" -version = "1.0.52" +version = "1.0.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "584aaf7a1ecf4d383bbe1a25eeab0cbb8ff96acc6796707ff65cde48f4632f15" +checksum = "37212100d4cbe6f0f6ff6e707f1e5a5b5b675f0451231ed9e4235e234e127ed3" dependencies = [ "wast", ] [[package]] name = "web-sys" -version = "0.3.60" +version = "0.3.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcda906d8be16e728fd5adc5b729afad4e444e106ab28cd1c7256e54fa61510f" +checksum = "e33b99f4b23ba3eec1a53ac264e35a755f00e966e0065077d6027c0f575b0b97" dependencies = [ "js-sys", "wasm-bindgen", @@ -12376,9 +12390,9 @@ dependencies = [ [[package]] name = "which" -version = "4.3.0" +version = "4.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c831fbbee9e129a8cf93e7747a82da9d95ba8e16621cae60ec2cdc849bacb7b" +checksum = "2441c784c52b289a054b7201fc93253e288f094e2f4be9058343127c4226a269" dependencies = [ "either", "libc", @@ -12447,37 +12461,48 @@ dependencies = [ [[package]] name = "windows-sys" -version = "0.36.1" +version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2" +checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" dependencies = [ - "windows_aarch64_msvc 0.36.1", - "windows_i686_gnu 0.36.1", - "windows_i686_msvc 0.36.1", - "windows_x86_64_gnu 0.36.1", - "windows_x86_64_msvc 0.36.1", + "windows_aarch64_gnullvm", + "windows_aarch64_msvc 0.42.1", + "windows_i686_gnu 0.42.1", + "windows_i686_msvc 0.42.1", + "windows_x86_64_gnu 0.42.1", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc 0.42.1", ] [[package]] name = "windows-sys" -version = "0.42.0" +version = "0.45.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.42.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e2522491fbfcd58cc84d47aeb2958948c4b8982e9a2d8a2a35bbaed431390e7" dependencies = [ "windows_aarch64_gnullvm", - "windows_aarch64_msvc 0.42.0", - "windows_i686_gnu 0.42.0", - "windows_i686_msvc 0.42.0", - "windows_x86_64_gnu 0.42.0", + "windows_aarch64_msvc 0.42.1", + "windows_i686_gnu 0.42.1", + "windows_i686_msvc 0.42.1", + "windows_x86_64_gnu 0.42.1", "windows_x86_64_gnullvm", - "windows_x86_64_msvc 0.42.0", + "windows_x86_64_msvc 0.42.1", ] [[package]] name = "windows_aarch64_gnullvm" -version = "0.42.0" +version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41d2aa71f6f0cbe00ae5167d90ef3cfe66527d6f613ca78ac8024c3ccab9a19e" +checksum = "8c9864e83243fdec7fc9c5444389dcbbfd258f745e7853198f365e3c4968a608" [[package]] name = "windows_aarch64_msvc" @@ -12487,15 +12512,9 @@ checksum = "17cffbe740121affb56fad0fc0e421804adf0ae00891205213b5cecd30db881d" [[package]] name = "windows_aarch64_msvc" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.42.0" +version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd0f252f5a35cac83d6311b2e795981f5ee6e67eb1f9a7f64eb4500fbc4dcdb4" +checksum = "4c8b1b673ffc16c47a9ff48570a9d85e25d265735c503681332589af6253c6c7" [[package]] name = "windows_i686_gnu" @@ -12505,15 +12524,9 @@ checksum = "2564fde759adb79129d9b4f54be42b32c89970c18ebf93124ca8870a498688ed" [[package]] name = "windows_i686_gnu" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" - -[[package]] -name = "windows_i686_gnu" -version = "0.42.0" +version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbeae19f6716841636c28d695375df17562ca208b2b7d0dc47635a50ae6c5de7" +checksum = "de3887528ad530ba7bdbb1faa8275ec7a1155a45ffa57c37993960277145d640" [[package]] name = "windows_i686_msvc" @@ -12523,15 +12536,9 @@ checksum = "9cd9d32ba70453522332c14d38814bceeb747d80b3958676007acadd7e166956" [[package]] name = "windows_i686_msvc" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" - -[[package]] -name = "windows_i686_msvc" -version = "0.42.0" +version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84c12f65daa39dd2babe6e442988fc329d6243fdce47d7d2d155b8d874862246" +checksum = "bf4d1122317eddd6ff351aa852118a2418ad4214e6613a50e0191f7004372605" [[package]] name = "windows_x86_64_gnu" @@ -12541,21 +12548,15 @@ checksum = "cfce6deae227ee8d356d19effc141a509cc503dfd1f850622ec4b0f84428e1f4" [[package]] name = "windows_x86_64_gnu" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.42.0" +version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf7b1b21b5362cbc318f686150e5bcea75ecedc74dd157d874d754a2ca44b0ed" +checksum = "c1040f221285e17ebccbc2591ffdc2d44ee1f9186324dd3e84e99ac68d699c45" [[package]] name = "windows_x86_64_gnullvm" -version = "0.42.0" +version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09d525d2ba30eeb3297665bd434a54297e4170c7f1a44cad4ef58095b4cd2028" +checksum = "628bfdf232daa22b0d64fdb62b09fcc36bb01f05a3939e20ab73aaf9470d0463" [[package]] name = "windows_x86_64_msvc" @@ -12565,15 +12566,9 @@ checksum = "d19538ccc21819d01deaf88d6a17eae6596a12e9aafdbb97916fb49896d89de9" [[package]] name = "windows_x86_64_msvc" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.42.0" +version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5" +checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd" [[package]] name = "winreg" @@ -12622,7 +12617,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9fb9bace5b5589ffead1afb76e43e34cff39cd0f3ce7e170ae0c29e53b88eb1c" dependencies = [ "asn1-rs 0.3.1", - "base64", + "base64 0.13.1", "data-encoding", "der-parser 7.0.0", "lazy_static", @@ -12641,7 +12636,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e0ecbeb7b67ce215e40e3cc7f2ff902f94a223acf44995934763467e7b1febc8" dependencies = [ "asn1-rs 0.5.1", - "base64", + "base64 0.13.1", "data-encoding", "der-parser 8.1.0", "lazy_static", @@ -12723,10 +12718,11 @@ dependencies = [ [[package]] name = "zstd-sys" -version = "2.0.4+zstd.1.5.2" +version = "2.0.6+zstd.1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fa202f2ef00074143e219d15b62ffc317d17cc33909feac471c044087cad7b0" +checksum = "68a3f9792c0c3dc6c165840a75f47ae1f4da402c2d006881129579f6597e801b" dependencies = [ "cc", "libc", + "pkg-config", ] diff --git a/client/consensus/common/Cargo.toml b/client/consensus/common/Cargo.toml index 87b052d434e93..d9e80e1e5ce99 100644 --- a/client/consensus/common/Cargo.toml +++ b/client/consensus/common/Cargo.toml @@ -18,7 +18,7 @@ futures = { version = "0.3.21", features = ["thread-pool"] } futures-timer = "3.0.1" libp2p = "0.50.0" log = "0.4.17" -mockall = "0.11.2" +mockall = "0.11.3" parking_lot = "0.12.1" serde = { version = "1.0", features = ["derive"] } thiserror = "1.0.30" diff --git a/client/network/Cargo.toml b/client/network/Cargo.toml index 44a7973b33659..b6b21247128d7 100644 --- a/client/network/Cargo.toml +++ b/client/network/Cargo.toml @@ -28,6 +28,7 @@ ip_network = "0.4.1" libp2p = { version = "0.50.0", features = ["dns", "identify", "kad", "macros", "mdns", "mplex", "noise", "ping", "tcp", "tokio", "yamux", "websocket"] } log = "0.4.17" lru = "0.8.1" +mockall = "0.11.3" parking_lot = "0.12.1" pin-project = "1.0.12" rand = "0.8.5" @@ -52,9 +53,12 @@ sp-runtime = { version = "7.0.0", path = "../../primitives/runtime" } [dev-dependencies] assert_matches = "1.3" +multistream-select = "0.12.1" +rand = "0.8.5" tempfile = "3.1.0" tokio = { version = "1.22.0", features = ["macros"] } tokio-util = { version = "0.7.4", features = ["compat"] } +tokio-test = "0.4.2" sc-network-light = { version = "0.10.0-dev", path = "./light" } sc-network-sync = { version = "0.10.0-dev", path = "./sync" } sp-test-primitives = { version = "2.0.0", path = "../../primitives/test-primitives" } diff --git a/client/network/src/protocol/notifications/behaviour.rs b/client/network/src/protocol/notifications/behaviour.rs index 2db46867128ac..c546f6b6f2c44 100644 --- a/client/network/src/protocol/notifications/behaviour.rs +++ b/client/network/src/protocol/notifications/behaviour.rs @@ -2111,3 +2111,2420 @@ impl NetworkBehaviour for Notifications { Poll::Pending } } + +#[cfg(test)] +mod tests { + use super::*; + use crate::protocol::notifications::handler::tests::*; + use libp2p::{ + core::ConnectedPoint, + swarm::{behaviour::FromSwarm, AddressRecord}, + }; + use std::{collections::HashSet, iter}; + + impl PartialEq for ConnectionState { + fn eq(&self, other: &ConnectionState) -> bool { + match (self, other) { + (ConnectionState::Closed, ConnectionState::Closed) => true, + (ConnectionState::Closing, ConnectionState::Closing) => true, + (ConnectionState::Opening, ConnectionState::Opening) => true, + (ConnectionState::OpeningThenClosing, ConnectionState::OpeningThenClosing) => true, + (ConnectionState::OpenDesiredByRemote, ConnectionState::OpenDesiredByRemote) => + true, + (ConnectionState::Open(_), ConnectionState::Open(_)) => true, + _ => false, + } + } + } + + #[derive(Clone)] + struct MockPollParams { + peer_id: PeerId, + addr: Multiaddr, + } + + impl PollParameters for MockPollParams { + type SupportedProtocolsIter = std::vec::IntoIter>; + type ListenedAddressesIter = std::vec::IntoIter; + type ExternalAddressesIter = std::vec::IntoIter; + + fn supported_protocols(&self) -> Self::SupportedProtocolsIter { + vec![].into_iter() + } + + fn listened_addresses(&self) -> Self::ListenedAddressesIter { + vec![self.addr.clone()].into_iter() + } + + fn external_addresses(&self) -> Self::ExternalAddressesIter { + vec![].into_iter() + } + + fn local_peer_id(&self) -> &PeerId { + &self.peer_id + } + } + + fn development_notifs() -> (Notifications, sc_peerset::PeersetHandle) { + let (peerset, peerset_handle) = { + let mut sets = Vec::with_capacity(1); + + sets.push(sc_peerset::SetConfig { + in_peers: 25, + out_peers: 25, + bootnodes: Vec::new(), + reserved_nodes: HashSet::new(), + reserved_only: false, + }); + + sc_peerset::Peerset::from_config(sc_peerset::PeersetConfig { sets }) + }; + + ( + Notifications::new( + peerset, + iter::once(ProtocolConfig { + name: "/foo".into(), + fallback_names: Vec::new(), + handshake: vec![1, 2, 3, 4], + max_notification_size: u64::MAX, + }), + ), + peerset_handle, + ) + } + + #[test] + fn update_handshake() { + let (mut notif, _peerset) = development_notifs(); + + let inner = notif.notif_protocols.get_mut(0).unwrap().handshake.read().clone(); + assert_eq!(inner, vec![1, 2, 3, 4]); + + notif.set_notif_protocol_handshake(0.into(), vec![5, 6, 7, 8]); + + let inner = notif.notif_protocols.get_mut(0).unwrap().handshake.read().clone(); + assert_eq!(inner, vec![5, 6, 7, 8]); + } + + #[test] + #[should_panic] + #[cfg(debug_assertions)] + fn update_unknown_handshake() { + let (mut notif, _peerset) = development_notifs(); + + notif.set_notif_protocol_handshake(1337.into(), vec![5, 6, 7, 8]); + } + + #[test] + fn disconnect_backoff_peer() { + let (mut notif, _peerset) = development_notifs(); + + let peer = PeerId::random(); + notif.peers.insert( + (peer, 0.into()), + PeerState::Backoff { timer: DelayId(0), timer_deadline: Instant::now() }, + ); + notif.disconnect_peer(&peer, 0.into()); + + assert!(std::matches!( + notif.peers.get(&(peer, 0.into())), + Some(PeerState::Backoff { timer: DelayId(0), .. }) + )); + } + + #[test] + fn disconnect_pending_request() { + let (mut notif, _peerset) = development_notifs(); + let peer = PeerId::random(); + + notif.peers.insert( + (peer, 0.into()), + PeerState::PendingRequest { timer: DelayId(0), timer_deadline: Instant::now() }, + ); + notif.disconnect_peer(&peer, 0.into()); + + assert!(std::matches!( + notif.peers.get(&(peer, 0.into())), + Some(PeerState::PendingRequest { timer: DelayId(0), .. }) + )); + } + + #[test] + fn disconnect_requested_peer() { + let (mut notif, _peerset) = development_notifs(); + + let peer = PeerId::random(); + notif.peers.insert((peer, 0.into()), PeerState::Requested); + notif.disconnect_peer(&peer, 0.into()); + + assert!(std::matches!(notif.peers.get(&(peer, 0.into())), Some(PeerState::Requested))); + } + + #[test] + fn disconnect_disabled_peer() { + let (mut notif, _peerset) = development_notifs(); + let peer = PeerId::random(); + notif.peers.insert( + (peer, 0.into()), + PeerState::Disabled { backoff_until: None, connections: SmallVec::new() }, + ); + notif.disconnect_peer(&peer, 0.into()); + + assert!(std::matches!( + notif.peers.get(&(peer, 0.into())), + Some(PeerState::Disabled { backoff_until: None, .. }) + )); + } + + #[test] + fn remote_opens_connection_and_substream() { + let (mut notif, _peerset) = development_notifs(); + let peer = PeerId::random(); + let conn = ConnectionId::new(0usize); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + + if let Some(&PeerState::Disabled { ref connections, backoff_until: None }) = + notif.peers.get(&(peer, 0.into())) + { + assert_eq!(connections[0], (conn, ConnectionState::Closed)); + } else { + panic!("invalid state"); + } + + // remote opens a substream, verify that peer state is updated to `Incoming` + notif.on_connection_handler_event( + peer, + conn, + NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, + ); + + if let Some(&PeerState::Incoming { ref connections, backoff_until: None }) = + notif.peers.get(&(peer, 0.into())) + { + assert_eq!(connections.len(), 1); + assert_eq!(connections[0], (conn, ConnectionState::OpenDesiredByRemote)); + } else { + panic!("invalid state"); + } + + assert!(std::matches!( + notif.incoming.pop(), + Some(IncomingPeer { alive: true, incoming_id: sc_peerset::IncomingIndex(0), .. }), + )); + } + + #[tokio::test] + async fn disconnect_remote_substream_before_handled_by_peerset() { + let (mut notif, _peerset) = development_notifs(); + let peer = PeerId::random(); + let conn = ConnectionId::new(0usize); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + notif.on_connection_handler_event( + peer, + conn, + NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, + ); + notif.disconnect_peer(&peer, 0.into()); + + if let Some(&PeerState::Disabled { ref connections, backoff_until: None }) = + notif.peers.get(&(peer, 0.into())) + { + assert_eq!(connections.len(), 1); + assert_eq!(connections[0], (conn, ConnectionState::Closing)); + } else { + panic!("invalid state"); + } + } + + #[test] + fn peerset_report_connect_backoff() { + let (mut notif, _peerset) = development_notifs(); + let set_id = sc_peerset::SetId::from(0); + let peer = PeerId::random(); + let conn = ConnectionId::new(0usize); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Disabled { .. }))); + + // manually add backoff for the entry + // + // there is not straight-forward way of adding backoff to `PeerState::Disabled` + // so manually adjust the value in order to progress on to the next stage. + // This modification together with `ConnectionClosed` will conver the peer + // state into `PeerState::Backoff`. + if let Some(PeerState::Disabled { ref mut backoff_until, .. }) = + notif.peers.get_mut(&(peer, set_id)) + { + *backoff_until = + Some(Instant::now().checked_add(std::time::Duration::from_secs(5)).unwrap()); + } + + notif.on_swarm_event(FromSwarm::ConnectionClosed( + libp2p::swarm::behaviour::ConnectionClosed { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + handler: NotifsHandlerProto::new(vec![]).into_handler(&peer, &connected), + remaining_established: 0usize, + }, + )); + + let timer = if let Some(&PeerState::Backoff { timer_deadline, .. }) = + notif.peers.get(&(peer, set_id)) + { + timer_deadline + } else { + panic!("invalid state"); + }; + + // attempt to connect the backed-off peer and verify that the request is pending + notif.peerset_report_connect(peer, set_id); + + if let Some(&PeerState::PendingRequest { timer_deadline, .. }) = + notif.peers.get(&(peer, set_id)) + { + assert_eq!(timer, timer_deadline); + } else { + panic!("invalid state"); + } + } + + #[test] + fn peerset_connect_incoming() { + let (mut notif, _peerset) = development_notifs(); + let peer = PeerId::random(); + let conn = ConnectionId::new(0usize); + let set_id = sc_peerset::SetId::from(0); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Disabled { .. }))); + + // remote opens a substream, verify that peer state is updated to `Incoming` + notif.on_connection_handler_event( + peer, + conn, + NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, + ); + + // attempt to connect to the peer and verify that the peer state is `Enabled` + notif.peerset_report_connect(peer, set_id); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Enabled { .. }))); + } + + #[test] + fn peerset_disconnect_disable_pending_enable() { + let (mut notif, _peerset) = development_notifs(); + let set_id = sc_peerset::SetId::from(0); + let peer = PeerId::random(); + let conn = ConnectionId::new(0usize); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Disabled { .. }))); + + // manually add backoff for the entry + if let Some(PeerState::Disabled { ref mut backoff_until, .. }) = + notif.peers.get_mut(&(peer, set_id)) + { + *backoff_until = + Some(Instant::now().checked_add(std::time::Duration::from_secs(5)).unwrap()); + } + + // switch state to `DisabledPendingEnable` + notif.peerset_report_connect(peer, set_id); + assert!(std::matches!( + notif.peers.get(&(peer, set_id)), + Some(&PeerState::DisabledPendingEnable { .. }) + )); + + notif.peerset_report_disconnect(peer, set_id); + + if let Some(PeerState::Disabled { backoff_until, .. }) = notif.peers.get(&(peer, set_id)) { + assert!(backoff_until.is_some()); + assert!(backoff_until.unwrap() > Instant::now()); + } else { + panic!("invalid state"); + } + } + + #[test] + fn peerset_disconnect_enabled() { + let (mut notif, _peerset) = development_notifs(); + let peer = PeerId::random(); + let conn = ConnectionId::new(0usize); + let set_id = sc_peerset::SetId::from(0); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + + // Set peer into `Enabled` state. + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + notif.on_connection_handler_event( + peer, + conn, + NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, + ); + notif.peerset_report_connect(peer, set_id); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Enabled { .. }))); + + // disconnect peer and verify that the state is `Disabled` + notif.peerset_report_disconnect(peer, set_id); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Disabled { .. }))); + } + + #[test] + fn peerset_disconnect_requested() { + let (mut notif, _peerset) = development_notifs(); + let peer = PeerId::random(); + let set_id = sc_peerset::SetId::from(0); + + // Set peer into `Requested` state. + notif.peerset_report_connect(peer, set_id); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Requested))); + + // disconnect peer and verify that the state is `Disabled` + notif.peerset_report_disconnect(peer, set_id); + assert!(notif.peers.get(&(peer, set_id)).is_none()); + } + + #[test] + fn peerset_disconnect_pending_request() { + let (mut notif, _peerset) = development_notifs(); + let set_id = sc_peerset::SetId::from(0); + let peer = PeerId::random(); + let conn = ConnectionId::new(0usize); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Disabled { .. }))); + + // manually add backoff for the entry + if let Some(PeerState::Disabled { ref mut backoff_until, .. }) = + notif.peers.get_mut(&(peer, set_id)) + { + *backoff_until = + Some(Instant::now().checked_add(std::time::Duration::from_secs(5)).unwrap()); + } + + notif.on_swarm_event(FromSwarm::ConnectionClosed( + libp2p::swarm::behaviour::ConnectionClosed { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + handler: NotifsHandlerProto::new(vec![]).into_handler(&peer, &connected), + remaining_established: 0usize, + }, + )); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Backoff { .. }))); + + // attempt to connect the backed-off peer and verify that the request is pending + notif.peerset_report_connect(peer, set_id); + assert!(std::matches!( + notif.peers.get(&(peer, set_id)), + Some(&PeerState::PendingRequest { .. }) + )); + + // attempt to disconnect the backed-off peer and verify that the request is pending + notif.peerset_report_disconnect(peer, set_id); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Backoff { .. }))); + } + + #[test] + fn peerset_accept_peer_not_alive() { + let (mut notif, _peerset) = development_notifs(); + let peer = PeerId::random(); + let conn = ConnectionId::new(0usize); + let set_id = sc_peerset::SetId::from(0); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Disabled { .. }))); + + // remote opens a substream, verify that peer state is updated to `Incoming` + notif.on_connection_handler_event( + peer, + conn, + NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, + ); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Incoming { .. }))); + + assert!(std::matches!( + notif.incoming[0], + IncomingPeer { alive: true, incoming_id: sc_peerset::IncomingIndex(0), .. }, + )); + + notif.disconnect_peer(&peer, set_id); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Disabled { .. }))); + assert!(std::matches!( + notif.incoming[0], + IncomingPeer { alive: false, incoming_id: sc_peerset::IncomingIndex(0), .. }, + )); + + notif.peerset_report_accept(sc_peerset::IncomingIndex(0)); + assert_eq!(notif.incoming.len(), 0); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(PeerState::Disabled { .. }))); + } + + #[test] + fn secondary_connection_peer_state_incoming() { + let (mut notif, _peerset) = development_notifs(); + let peer = PeerId::random(); + let conn = ConnectionId::new(0usize); + let conn2 = ConnectionId::new(1usize); + let set_id = sc_peerset::SetId::from(0); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Disabled { .. }))); + + notif.on_connection_handler_event( + peer, + conn, + NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, + ); + if let Some(&PeerState::Incoming { ref connections, .. }) = notif.peers.get(&(peer, set_id)) + { + assert_eq!(connections.len(), 1); + assert_eq!(connections[0], (conn, ConnectionState::OpenDesiredByRemote)); + } else { + panic!("invalid state"); + } + + // add another connection + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn2, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + + if let Some(&PeerState::Incoming { ref connections, .. }) = notif.peers.get(&(peer, set_id)) + { + assert_eq!(connections.len(), 2); + assert_eq!(connections[0], (conn, ConnectionState::OpenDesiredByRemote)); + assert_eq!(connections[1], (conn2, ConnectionState::Closed)); + } else { + panic!("invalid state"); + } + } + + #[test] + fn close_connection_for_disabled_peer() { + let (mut notif, _peerset) = development_notifs(); + let peer = PeerId::random(); + let conn = ConnectionId::new(0usize); + let set_id = sc_peerset::SetId::from(0); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Disabled { .. }))); + + notif.on_swarm_event(FromSwarm::ConnectionClosed( + libp2p::swarm::behaviour::ConnectionClosed { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + handler: NotifsHandlerProto::new(vec![]).into_handler(&peer, &connected), + remaining_established: 0usize, + }, + )); + assert!(notif.peers.get(&(peer, set_id)).is_none()); + } + + #[test] + fn close_connection_for_incoming_peer_one_connection() { + let (mut notif, _peerset) = development_notifs(); + let peer = PeerId::random(); + let conn = ConnectionId::new(0usize); + let set_id = sc_peerset::SetId::from(0); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Disabled { .. }))); + + notif.on_connection_handler_event( + peer, + conn, + NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, + ); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Incoming { .. }))); + + notif.on_swarm_event(FromSwarm::ConnectionClosed( + libp2p::swarm::behaviour::ConnectionClosed { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + handler: NotifsHandlerProto::new(vec![]).into_handler(&peer, &connected), + remaining_established: 0usize, + }, + )); + assert!(notif.peers.get(&(peer, set_id)).is_none()); + assert!(std::matches!( + notif.incoming[0], + IncomingPeer { alive: false, incoming_id: sc_peerset::IncomingIndex(0), .. }, + )); + } + + #[test] + fn close_connection_for_incoming_peer_two_connections() { + let (mut notif, _peerset) = development_notifs(); + let peer = PeerId::random(); + let conn = ConnectionId::new(0usize); + let conn1 = ConnectionId::new(1usize); + let set_id = sc_peerset::SetId::from(0); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + let mut conns = SmallVec::< + [(ConnectionId, ConnectionState); crate::MAX_CONNECTIONS_PER_PEER], + >::from(vec![(conn, ConnectionState::Closed)]); + + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Disabled { .. }))); + + notif.on_connection_handler_event( + peer, + conn, + NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, + ); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Incoming { .. }))); + + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn1, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + conns.push((conn1, ConnectionState::Closed)); + + if let Some(PeerState::Incoming { ref connections, .. }) = notif.peers.get(&(peer, set_id)) + { + assert_eq!(connections.len(), 2); + assert_eq!(connections[0], (conn, ConnectionState::OpenDesiredByRemote)); + assert_eq!(connections[1], (conn1, ConnectionState::Closed)); + } + + notif.on_swarm_event(FromSwarm::ConnectionClosed( + libp2p::swarm::behaviour::ConnectionClosed { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + handler: NotifsHandlerProto::new(vec![]).into_handler(&peer, &connected), + remaining_established: 0usize, + }, + )); + + if let Some(&PeerState::Disabled { ref connections, .. }) = notif.peers.get(&(peer, set_id)) + { + assert_eq!(connections.len(), 1); + assert_eq!(connections[0], (conn1, ConnectionState::Closed)); + } else { + panic!("invalid state"); + } + } + + #[test] + fn connection_and_substream_open() { + let (mut notif, _peerset) = development_notifs(); + let peer = PeerId::random(); + let conn = ConnectionId::new(0usize); + let set_id = sc_peerset::SetId::from(0); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + let mut conn_yielder = ConnectionYielder::new(); + + // move the peer to `Enabled` state + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Disabled { .. }))); + + notif.on_connection_handler_event( + peer, + conn, + NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, + ); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Incoming { .. }))); + + notif.peerset_report_connect(peer, set_id); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Enabled { .. }))); + + // open new substream + let event = conn_yielder.open_substream(peer, 0, connected, vec![1, 2, 3, 4]); + + notif.on_connection_handler_event(peer, conn, event); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Enabled { .. }))); + + if let Some(PeerState::Enabled { ref connections, .. }) = notif.peers.get(&(peer, set_id)) { + assert_eq!(connections.len(), 1); + assert_eq!(connections[0].0, conn); + assert!(std::matches!(connections[0].1, ConnectionState::Open(_))); + } + + assert!(std::matches!( + notif.events[notif.events.len() - 1], + NetworkBehaviourAction::GenerateEvent(NotificationsOut::CustomProtocolOpen { .. }) + )); + } + + #[test] + fn connection_closed_sink_replaced() { + let (mut notif, _peerset) = development_notifs(); + let peer = PeerId::random(); + let conn1 = ConnectionId::new(0usize); + let conn2 = ConnectionId::new(1usize); + let set_id = sc_peerset::SetId::from(0); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + let mut conn_yielder = ConnectionYielder::new(); + + // open two connections + for conn_id in vec![conn1, conn2] { + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn_id, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + } + + if let Some(&PeerState::Disabled { ref connections, .. }) = notif.peers.get(&(peer, set_id)) + { + assert_eq!(connections[0], (conn1, ConnectionState::Closed)); + assert_eq!(connections[1], (conn2, ConnectionState::Closed)); + } else { + panic!("invalid state"); + } + + // open substreams on both active connections + notif.peerset_report_connect(peer, set_id); + notif.on_connection_handler_event( + peer, + conn2, + NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, + ); + + if let Some(&PeerState::Enabled { ref connections, .. }) = notif.peers.get(&(peer, set_id)) + { + assert_eq!(connections[0], (conn1, ConnectionState::Opening)); + assert_eq!(connections[1], (conn2, ConnectionState::Opening)); + } else { + panic!("invalid state"); + } + + // add two new substreams, one for each connection and verify that both are in open state + for conn in vec![conn1, conn2].iter() { + notif.on_connection_handler_event( + peer, + *conn, + conn_yielder.open_substream(peer, 0, connected.clone(), vec![1, 2, 3, 4]), + ); + } + + if let Some(PeerState::Enabled { ref connections, .. }) = notif.peers.get(&(peer, set_id)) { + assert_eq!(connections[0].0, conn1); + assert!(std::matches!(connections[0].1, ConnectionState::Open(_))); + assert_eq!(connections[1].0, conn2); + assert!(std::matches!(connections[1].1, ConnectionState::Open(_))); + } else { + panic!("invalid state"); + } + + // check peer information + assert_eq!(notif.open_peers().collect::>(), vec![&peer],); + assert_eq!(notif.reserved_peers(set_id).collect::>(), Vec::<&PeerId>::new(),); + assert_eq!(notif.num_discovered_peers(), 0usize); + + // close the other connection and verify that notification replacement event is emitted + notif.on_swarm_event(FromSwarm::ConnectionClosed( + libp2p::swarm::behaviour::ConnectionClosed { + peer_id: peer, + connection_id: conn1, + endpoint: &connected, + handler: NotifsHandlerProto::new(vec![]).into_handler(&peer, &connected), + remaining_established: 0usize, + }, + )); + + if let Some(PeerState::Enabled { ref connections, .. }) = notif.peers.get(&(peer, set_id)) { + assert_eq!(connections.len(), 1); + assert_eq!(connections[0].0, conn2); + assert!(std::matches!(connections[0].1, ConnectionState::Open(_))); + } else { + panic!("invalid state"); + } + + assert!(std::matches!( + notif.events[notif.events.len() - 1], + NetworkBehaviourAction::GenerateEvent(NotificationsOut::CustomProtocolReplaced { .. }) + )); + } + + #[test] + fn dial_failure_for_requested_peer() { + let (mut notif, _peerset) = development_notifs(); + let peer = PeerId::random(); + let set_id = sc_peerset::SetId::from(0); + + // Set peer into `Requested` state. + notif.peerset_report_connect(peer, set_id); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Requested))); + + notif.on_swarm_event(FromSwarm::DialFailure(libp2p::swarm::behaviour::DialFailure { + peer_id: Some(peer), + handler: NotifsHandlerProto::new(vec![]), + error: &libp2p::swarm::DialError::Banned, + })); + + if let Some(PeerState::Backoff { timer_deadline, .. }) = notif.peers.get(&(peer, set_id)) { + assert!(timer_deadline > &Instant::now()); + } else { + panic!("invalid state"); + } + } + + #[tokio::test] + async fn write_notification() { + let (mut notif, _peerset) = development_notifs(); + let peer = PeerId::random(); + let conn = ConnectionId::new(0usize); + let set_id = sc_peerset::SetId::from(0); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + let mut conn_yielder = ConnectionYielder::new(); + + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Disabled { .. }))); + + notif.peerset_report_connect(peer, set_id); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Enabled { .. }))); + + notif.on_connection_handler_event( + peer, + conn, + conn_yielder.open_substream(peer, 0, connected, vec![1, 2, 3, 4]), + ); + + if let Some(PeerState::Enabled { ref connections, .. }) = notif.peers.get(&(peer, set_id)) { + assert_eq!(connections[0].0, conn); + assert!(std::matches!(connections[0].1, ConnectionState::Open(_))); + } else { + panic!("invalid state"); + } + + notif.write_notification(&peer, set_id, vec![1, 3, 3, 7]); + assert_eq!(conn_yielder.get_next_event(peer, set_id.into()).await, Some(vec![1, 3, 3, 7])); + } + + #[test] + fn peerset_report_connect_backoff_expired() { + let (mut notif, _peerset) = development_notifs(); + let set_id = sc_peerset::SetId::from(0); + let peer = PeerId::random(); + let conn = ConnectionId::new(0usize); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + let backoff_duration = Duration::from_millis(100); + + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Disabled { .. }))); + + // manually add backoff for the entry + if let Some(PeerState::Disabled { ref mut backoff_until, .. }) = + notif.peers.get_mut(&(peer, set_id)) + { + *backoff_until = Some(Instant::now().checked_add(backoff_duration).unwrap()); + } + + notif.on_swarm_event(FromSwarm::ConnectionClosed( + libp2p::swarm::behaviour::ConnectionClosed { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + handler: NotifsHandlerProto::new(vec![]).into_handler(&peer, &connected), + remaining_established: 0usize, + }, + )); + + // wait until the backoff time has passed + std::thread::sleep(backoff_duration * 2); + + // attempt to connect the backed-off peer and verify that the request is pending + notif.peerset_report_connect(peer, set_id); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Requested { .. }))) + } + + #[test] + fn peerset_report_disconnect_disabled() { + let (mut notif, _peerset) = development_notifs(); + let peer = PeerId::random(); + let set_id = sc_peerset::SetId::from(0); + let conn = ConnectionId::new(0usize); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Disabled { .. }))); + + notif.peerset_report_disconnect(peer, set_id); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Disabled { .. }))); + } + + #[test] + fn peerset_report_disconnect_backoff() { + let (mut notif, _peerset) = development_notifs(); + let set_id = sc_peerset::SetId::from(0); + let peer = PeerId::random(); + let conn = ConnectionId::new(0usize); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + let backoff_duration = Duration::from_secs(2); + + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Disabled { .. }))); + + // manually add backoff for the entry + if let Some(PeerState::Disabled { ref mut backoff_until, .. }) = + notif.peers.get_mut(&(peer, set_id)) + { + *backoff_until = Some(Instant::now().checked_add(backoff_duration).unwrap()); + } + + notif.on_swarm_event(FromSwarm::ConnectionClosed( + libp2p::swarm::behaviour::ConnectionClosed { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + handler: NotifsHandlerProto::new(vec![]).into_handler(&peer, &connected), + remaining_established: 0usize, + }, + )); + + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Backoff { .. }))); + + notif.peerset_report_disconnect(peer, set_id); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Backoff { .. }))); + } + + #[test] + fn peer_is_backed_off_if_both_connections_get_closed_while_peer_is_disabled_with_back_off() { + let (mut notif, _peerset) = development_notifs(); + let set_id = sc_peerset::SetId::from(0); + let peer = PeerId::random(); + let conn1 = ConnectionId::new(0usize); + let conn2 = ConnectionId::new(0usize); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn1, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn2, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Disabled { .. }))); + + // manually add backoff for the entry + if let Some(PeerState::Disabled { ref mut backoff_until, .. }) = + notif.peers.get_mut(&(peer, set_id)) + { + *backoff_until = + Some(Instant::now().checked_add(std::time::Duration::from_secs(5)).unwrap()); + } + + // switch state to `DisabledPendingEnable` + notif.peerset_report_connect(peer, set_id); + assert!(std::matches!( + notif.peers.get(&(peer, set_id)), + Some(&PeerState::DisabledPendingEnable { .. }) + )); + + notif.on_swarm_event(FromSwarm::ConnectionClosed( + libp2p::swarm::behaviour::ConnectionClosed { + peer_id: peer, + connection_id: conn1, + endpoint: &connected, + handler: NotifsHandlerProto::new(vec![]).into_handler(&peer, &connected), + remaining_established: 0usize, + }, + )); + assert!(std::matches!( + notif.peers.get(&(peer, set_id)), + Some(&PeerState::DisabledPendingEnable { .. }) + )); + + notif.on_swarm_event(FromSwarm::ConnectionClosed( + libp2p::swarm::behaviour::ConnectionClosed { + peer_id: peer, + connection_id: conn2, + endpoint: &connected, + handler: NotifsHandlerProto::new(vec![]).into_handler(&peer, &connected), + remaining_established: 0usize, + }, + )); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Backoff { .. }))); + } + + #[test] + fn inject_connection_closed_incoming_with_backoff() { + let (mut notif, _peerset) = development_notifs(); + let peer = PeerId::random(); + let set_id = sc_peerset::SetId::from(0); + let conn = ConnectionId::new(0usize); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Disabled { .. }))); + + // remote opens a substream, verify that peer state is updated to `Incoming` + notif.on_connection_handler_event( + peer, + conn, + NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, + ); + + // manually add backoff for the entry + if let Some(&mut PeerState::Incoming { ref mut backoff_until, .. }) = + notif.peers.get_mut(&(peer, 0.into())) + { + *backoff_until = + Some(Instant::now().checked_add(std::time::Duration::from_secs(5)).unwrap()); + } else { + panic!("invalid state"); + } + + notif.on_swarm_event(FromSwarm::ConnectionClosed( + libp2p::swarm::behaviour::ConnectionClosed { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + handler: NotifsHandlerProto::new(vec![]).into_handler(&peer, &connected), + remaining_established: 0usize, + }, + )); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Backoff { .. }))); + } + + #[test] + fn two_connections_inactive_connection_gets_closed_peer_state_is_still_incoming() { + let (mut notif, _peerset) = development_notifs(); + let peer = PeerId::random(); + let conn1 = ConnectionId::new(0usize); + let conn2 = ConnectionId::new(1usize); + let set_id = sc_peerset::SetId::from(0); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + + // open two connections + for conn_id in vec![conn1, conn2] { + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn_id, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + } + + if let Some(&PeerState::Disabled { ref connections, .. }) = notif.peers.get(&(peer, set_id)) + { + assert_eq!(connections[0], (conn1, ConnectionState::Closed)); + assert_eq!(connections[1], (conn2, ConnectionState::Closed)); + } else { + panic!("invalid state"); + } + + // remote opens a substream, verify that peer state is updated to `Incoming` + notif.on_connection_handler_event( + peer, + conn1, + NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, + ); + assert!(std::matches!( + notif.peers.get_mut(&(peer, 0.into())), + Some(&mut PeerState::Incoming { .. }) + )); + + notif.on_swarm_event(FromSwarm::ConnectionClosed( + libp2p::swarm::behaviour::ConnectionClosed { + peer_id: peer, + connection_id: conn2, + endpoint: &connected, + handler: NotifsHandlerProto::new(vec![]).into_handler(&peer, &connected), + remaining_established: 0usize, + }, + )); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Incoming { .. }))); + } + + #[test] + fn two_connections_active_connection_gets_closed_peer_state_is_disabled() { + let (mut notif, _peerset) = development_notifs(); + let peer = PeerId::random(); + let conn1 = ConnectionId::new(0usize); + let conn2 = ConnectionId::new(1usize); + let set_id = sc_peerset::SetId::from(0); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + + // open two connections + for conn_id in vec![conn1, conn2] { + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn_id, + endpoint: &ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }, + failed_addresses: &[], + other_established: 0usize, + }, + )); + } + + if let Some(&PeerState::Disabled { ref connections, .. }) = notif.peers.get(&(peer, set_id)) + { + assert_eq!(connections[0], (conn1, ConnectionState::Closed)); + assert_eq!(connections[1], (conn2, ConnectionState::Closed)); + } else { + panic!("invalid state"); + } + + // remote opens a substream, verify that peer state is updated to `Incoming` + notif.on_connection_handler_event( + peer, + conn1, + NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, + ); + assert!(std::matches!( + notif.peers.get_mut(&(peer, 0.into())), + Some(PeerState::Incoming { .. }) + )); + + notif.on_swarm_event(FromSwarm::ConnectionClosed( + libp2p::swarm::behaviour::ConnectionClosed { + peer_id: peer, + connection_id: conn1, + endpoint: &connected, + handler: NotifsHandlerProto::new(vec![]).into_handler(&peer, &connected), + remaining_established: 0usize, + }, + )); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Disabled { .. }))); + } + + #[test] + fn inject_connection_closed_for_active_connection() { + let (mut notif, _peerset) = development_notifs(); + let peer = PeerId::random(); + let conn1 = ConnectionId::new(0usize); + let conn2 = ConnectionId::new(1usize); + let set_id = sc_peerset::SetId::from(0); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + let mut conn_yielder = ConnectionYielder::new(); + + // open two connections + for conn_id in vec![conn1, conn2] { + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn_id, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + } + + if let Some(&PeerState::Disabled { ref connections, .. }) = notif.peers.get(&(peer, set_id)) + { + assert_eq!(connections[0], (conn1, ConnectionState::Closed)); + assert_eq!(connections[1], (conn2, ConnectionState::Closed)); + } else { + panic!("invalid state"); + } + + // open substreams on both active connections + notif.peerset_report_connect(peer, set_id); + + if let Some(&PeerState::Enabled { ref connections, .. }) = notif.peers.get(&(peer, set_id)) + { + assert_eq!(connections[0], (conn1, ConnectionState::Opening)); + assert_eq!(connections[1], (conn2, ConnectionState::Closed)); + } else { + panic!("invalid state"); + } + + notif.on_connection_handler_event( + peer, + conn1, + conn_yielder.open_substream(peer, 0, connected.clone(), vec![1, 2, 3, 4]), + ); + + if let Some(PeerState::Enabled { ref connections, .. }) = notif.peers.get(&(peer, set_id)) { + assert!(std::matches!(connections[0].1, ConnectionState::Open(_))); + assert_eq!(connections[0].0, conn1); + assert_eq!(connections[1], (conn2, ConnectionState::Closed)); + } else { + panic!("invalid state"); + } + + notif.on_swarm_event(FromSwarm::ConnectionClosed( + libp2p::swarm::behaviour::ConnectionClosed { + peer_id: peer, + connection_id: conn1, + endpoint: &connected, + handler: NotifsHandlerProto::new(vec![]).into_handler(&peer, &connected), + remaining_established: 0usize, + }, + )); + } + + #[test] + fn inject_dial_failure_for_pending_request() { + let (mut notif, _peerset) = development_notifs(); + let set_id = sc_peerset::SetId::from(0); + let peer = PeerId::random(); + let conn = ConnectionId::new(0usize); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Disabled { .. }))); + + // manually add backoff for the entry + if let Some(PeerState::Disabled { ref mut backoff_until, .. }) = + notif.peers.get_mut(&(peer, set_id)) + { + *backoff_until = + Some(Instant::now().checked_add(std::time::Duration::from_secs(5)).unwrap()); + } + + notif.on_swarm_event(FromSwarm::ConnectionClosed( + libp2p::swarm::behaviour::ConnectionClosed { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + handler: NotifsHandlerProto::new(vec![]).into_handler(&peer, &connected), + remaining_established: 0usize, + }, + )); + + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Backoff { .. }))); + + // attempt to connect the backed-off peer and verify that the request is pending + notif.peerset_report_connect(peer, set_id); + assert!(std::matches!( + notif.peers.get(&(peer, set_id)), + Some(&PeerState::PendingRequest { .. }) + )); + + let now = Instant::now(); + notif.on_swarm_event(FromSwarm::DialFailure(libp2p::swarm::behaviour::DialFailure { + peer_id: Some(peer), + handler: NotifsHandlerProto::new(vec![]), + error: &libp2p::swarm::DialError::Banned, + })); + + if let Some(PeerState::PendingRequest { ref timer_deadline, .. }) = + notif.peers.get(&(peer, set_id)) + { + assert!(timer_deadline > &(now + std::time::Duration::from_secs(5))); + } + } + + #[test] + fn peerstate_incoming_open_desired_by_remote() { + let (mut notif, _peerset) = development_notifs(); + let peer = PeerId::random(); + let set_id = sc_peerset::SetId::from(0); + let conn1 = ConnectionId::new(0usize); + let conn2 = ConnectionId::new(1usize); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn1, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn2, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Disabled { .. }))); + + // remote opens a substream, verify that peer state is updated to `Incoming` + notif.on_connection_handler_event( + peer, + conn1, + NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, + ); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Incoming { .. }))); + + // add another open event from remote + notif.on_connection_handler_event( + peer, + conn2, + NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, + ); + + if let Some(PeerState::Incoming { ref connections, .. }) = notif.peers.get(&(peer, set_id)) + { + assert_eq!(connections[0], (conn1, ConnectionState::OpenDesiredByRemote)); + assert_eq!(connections[1], (conn2, ConnectionState::OpenDesiredByRemote)); + } + } + + #[tokio::test] + async fn remove_backoff_peer_after_timeout() { + let (mut notif, _peerset) = development_notifs(); + let peer = PeerId::random(); + let set_id = sc_peerset::SetId::from(0); + let conn = ConnectionId::new(0usize); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + + if let Some(&mut PeerState::Disabled { ref mut backoff_until, .. }) = + notif.peers.get_mut(&(peer, 0.into())) + { + *backoff_until = + Some(Instant::now().checked_add(std::time::Duration::from_millis(100)).unwrap()); + } else { + panic!("invalid state"); + } + + notif.on_swarm_event(FromSwarm::ConnectionClosed( + libp2p::swarm::behaviour::ConnectionClosed { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + handler: NotifsHandlerProto::new(vec![]).into_handler(&peer, &connected), + remaining_established: 0usize, + }, + )); + + let until = if let Some(&PeerState::Backoff { timer_deadline, .. }) = + notif.peers.get(&(peer, set_id)) + { + timer_deadline + } else { + panic!("invalid state"); + }; + + if until > Instant::now() { + std::thread::sleep(until - Instant::now()); + } + + assert!(notif.peers.get(&(peer, set_id)).is_some()); + + if tokio::time::timeout(Duration::from_secs(5), async { + let mut params = MockPollParams { peer_id: PeerId::random(), addr: Multiaddr::empty() }; + + loop { + futures::future::poll_fn(|cx| { + let _ = notif.poll(cx, &mut params); + Poll::Ready(()) + }) + .await; + + if notif.peers.get(&(peer, set_id)).is_none() { + break + } + } + }) + .await + .is_err() + { + panic!("backoff peer was not removed in time"); + } + + assert!(notif.peers.get(&(peer, set_id)).is_none()); + } + + #[tokio::test] + async fn reschedule_disabled_pending_enable_when_connection_not_closed() { + let (mut notif, _peerset) = development_notifs(); + let peer = PeerId::random(); + let conn = ConnectionId::new(0usize); + let set_id = sc_peerset::SetId::from(0); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + let mut conn_yielder = ConnectionYielder::new(); + + // move the peer to `Enabled` state + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn, + endpoint: &ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }, + failed_addresses: &[], + other_established: 0usize, + }, + )); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Disabled { .. }))); + + // open substream + notif.on_connection_handler_event( + peer, + conn, + NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, + ); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Incoming { .. }))); + + notif.peerset_report_connect(peer, set_id); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Enabled { .. }))); + + let event = conn_yielder.open_substream(peer, 0, connected, vec![1, 2, 3, 4]); + + notif.on_connection_handler_event(peer, conn, event); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Enabled { .. }))); + + if let Some(PeerState::Enabled { ref connections, .. }) = notif.peers.get(&(peer, set_id)) { + assert!(std::matches!(connections[0], (_, ConnectionState::Open(_)))); + assert_eq!(connections[0].0, conn); + } else { + panic!("invalid state"); + } + + notif.peerset_report_disconnect(peer, set_id); + + if let Some(PeerState::Disabled { ref connections, ref mut backoff_until }) = + notif.peers.get_mut(&(peer, set_id)) + { + assert!(std::matches!(connections[0], (_, ConnectionState::Closing))); + assert_eq!(connections[0].0, conn); + + *backoff_until = + Some(Instant::now().checked_add(std::time::Duration::from_secs(2)).unwrap()); + } else { + panic!("invalid state"); + } + + notif.peerset_report_connect(peer, set_id); + + let prev_instant = + if let Some(PeerState::DisabledPendingEnable { + ref connections, timer_deadline, .. + }) = notif.peers.get(&(peer, set_id)) + { + assert!(std::matches!(connections[0], (_, ConnectionState::Closing))); + assert_eq!(connections[0].0, conn); + + *timer_deadline + } else { + panic!("invalid state"); + }; + + // one of the peers has an active backoff timer so poll the notifications code until + // the timer has expired. Because the connection is still in the state of `Closing`, + // verify that the code continues to keep the peer disabled by resetting the timer + // after the first one expired. + if tokio::time::timeout(Duration::from_secs(5), async { + let mut params = MockPollParams { peer_id: PeerId::random(), addr: Multiaddr::empty() }; + + loop { + futures::future::poll_fn(|cx| { + let _ = notif.poll(cx, &mut params); + Poll::Ready(()) + }) + .await; + + if let Some(PeerState::DisabledPendingEnable { + timer_deadline, connections, .. + }) = notif.peers.get(&(peer, set_id)) + { + assert!(std::matches!(connections[0], (_, ConnectionState::Closing))); + + if timer_deadline != &prev_instant { + break + } + } else { + panic!("invalid state"); + } + } + }) + .await + .is_err() + { + panic!("backoff peer was not removed in time"); + } + } + + #[test] + #[should_panic] + #[cfg(debug_assertions)] + fn peerset_report_connect_with_enabled_peer() { + let (mut notif, _peerset) = development_notifs(); + let peer = PeerId::random(); + let conn = ConnectionId::new(0usize); + let set_id = sc_peerset::SetId::from(0); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + let mut conn_yielder = ConnectionYielder::new(); + + // move the peer to `Enabled` state + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Disabled { .. }))); + + notif.on_connection_handler_event( + peer, + conn, + NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, + ); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Incoming { .. }))); + + notif.peerset_report_connect(peer, set_id); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Enabled { .. }))); + + let event = conn_yielder.open_substream(peer, 0, connected, vec![1, 2, 3, 4]); + + notif.on_connection_handler_event(peer, conn, event); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Enabled { .. }))); + + if let Some(PeerState::Enabled { ref connections, .. }) = notif.peers.get(&(peer, set_id)) { + assert!(std::matches!(connections[0], (_, ConnectionState::Open(_)))); + assert_eq!(connections[0].0, conn); + } else { + panic!("invalid state"); + } + + notif.peerset_report_connect(peer, set_id); + } + + #[test] + #[should_panic] + #[cfg(debug_assertions)] + fn peerset_report_connect_with_disabled_pending_enable_peer() { + let (mut notif, _peerset) = development_notifs(); + let set_id = sc_peerset::SetId::from(0); + let peer = PeerId::random(); + let conn = ConnectionId::new(0usize); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Disabled { .. }))); + + // manually add backoff for the entry + if let Some(PeerState::Disabled { ref mut backoff_until, .. }) = + notif.peers.get_mut(&(peer, set_id)) + { + *backoff_until = + Some(Instant::now().checked_add(std::time::Duration::from_secs(5)).unwrap()); + } + + // switch state to `DisabledPendingEnable` + notif.peerset_report_connect(peer, set_id); + assert!(std::matches!( + notif.peers.get(&(peer, set_id)), + Some(&PeerState::DisabledPendingEnable { .. }) + )); + + notif.peerset_report_connect(peer, set_id); + } + + #[test] + #[should_panic] + #[cfg(debug_assertions)] + fn peerset_report_connect_with_requested_peer() { + let (mut notif, _peerset) = development_notifs(); + let peer = PeerId::random(); + let set_id = sc_peerset::SetId::from(0); + + // Set peer into `Requested` state. + notif.peerset_report_connect(peer, set_id); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Requested))); + + notif.peerset_report_connect(peer, set_id); + } + + #[test] + #[should_panic] + #[cfg(debug_assertions)] + fn peerset_report_connect_with_pending_requested() { + let (mut notif, _peerset) = development_notifs(); + let set_id = sc_peerset::SetId::from(0); + let peer = PeerId::random(); + let conn = ConnectionId::new(0usize); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Disabled { .. }))); + + // manually add backoff for the entry + if let Some(PeerState::Disabled { ref mut backoff_until, .. }) = + notif.peers.get_mut(&(peer, set_id)) + { + *backoff_until = + Some(Instant::now().checked_add(std::time::Duration::from_secs(5)).unwrap()); + } + + notif.on_swarm_event(FromSwarm::ConnectionClosed( + libp2p::swarm::behaviour::ConnectionClosed { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + handler: NotifsHandlerProto::new(vec![]).into_handler(&peer, &connected), + remaining_established: 0usize, + }, + )); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Backoff { .. }))); + + // attempt to connect the backed-off peer and verify that the request is pending + notif.peerset_report_connect(peer, set_id); + assert!(std::matches!( + notif.peers.get(&(peer, set_id)), + Some(&PeerState::PendingRequest { .. }) + )); + + notif.peerset_report_connect(peer, set_id); + } + + #[test] + #[should_panic] + #[cfg(debug_assertions)] + fn peerset_report_disconnect_with_incoming_peer() { + let (mut notif, _peerset) = development_notifs(); + let peer = PeerId::random(); + let set_id = sc_peerset::SetId::from(0); + let conn = ConnectionId::new(0usize); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Disabled { .. }))); + + // remote opens a substream, verify that peer state is updated to `Incoming` + notif.on_connection_handler_event( + peer, + conn, + NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, + ); + + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Incoming { .. }))); + + notif.peerset_report_disconnect(peer, set_id); + } + + #[test] + #[should_panic] + #[cfg(debug_assertions)] + fn peerset_report_accept_incoming_peer() { + let (mut notif, _peerset) = development_notifs(); + let peer = PeerId::random(); + let conn = ConnectionId::new(0usize); + let set_id = sc_peerset::SetId::from(0); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Disabled { .. }))); + + // remote opens a substream, verify that peer state is updated to `Incoming` + notif.on_connection_handler_event( + peer, + conn, + NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, + ); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Incoming { .. }))); + + assert!(std::matches!( + notif.incoming[0], + IncomingPeer { alive: true, incoming_id: sc_peerset::IncomingIndex(0), .. }, + )); + + notif.peers.remove(&(peer, set_id)); + notif.peerset_report_accept(sc_peerset::IncomingIndex(0)); + } + + #[test] + #[should_panic] + #[cfg(debug_assertions)] + fn peerset_report_accept_not_incoming_peer() { + let (mut notif, _peerset) = development_notifs(); + let peer = PeerId::random(); + let conn = ConnectionId::new(0usize); + let set_id = sc_peerset::SetId::from(0); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + let mut conn_yielder = ConnectionYielder::new(); + + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Disabled { .. }))); + + // remote opens a substream, verify that peer state is updated to `Incoming` + notif.on_connection_handler_event( + peer, + conn, + NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, + ); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Incoming { .. }))); + + assert!(std::matches!( + notif.incoming[0], + IncomingPeer { alive: true, incoming_id: sc_peerset::IncomingIndex(0), .. }, + )); + + notif.peerset_report_connect(peer, set_id); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Enabled { .. }))); + + let event = conn_yielder.open_substream(peer, 0, connected, vec![1, 2, 3, 4]); + notif.on_connection_handler_event(peer, conn, event); + + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Enabled { .. }))); + notif.incoming[0].alive = true; + notif.peerset_report_accept(sc_peerset::IncomingIndex(0)); + } + + #[test] + #[should_panic] + #[cfg(debug_assertions)] + fn inject_connection_closed_non_existent_peer() { + let (mut notif, _peerset) = development_notifs(); + let peer = PeerId::random(); + let endpoint = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + + notif.on_swarm_event(FromSwarm::ConnectionClosed( + libp2p::swarm::behaviour::ConnectionClosed { + peer_id: peer, + connection_id: ConnectionId::new(0usize), + endpoint: &endpoint, + handler: NotifsHandlerProto::new(vec![]).into_handler(&peer, &endpoint), + remaining_established: 0usize, + }, + )); + } + + #[test] + fn disconnect_non_existent_peer() { + let (mut notif, _peerset) = development_notifs(); + let peer = PeerId::random(); + let set_id = sc_peerset::SetId::from(0); + + notif.peerset_report_disconnect(peer, set_id); + + assert!(notif.peers.is_empty()); + assert!(notif.incoming.is_empty()); + } + + #[test] + fn accept_non_existent_connection() { + let (mut notif, _peerset) = development_notifs(); + + notif.peerset_report_accept(0.into()); + + assert!(notif.peers.is_empty()); + assert!(notif.incoming.is_empty()); + } + + #[test] + fn reject_non_existent_connection() { + let (mut notif, _peerset) = development_notifs(); + + notif.peerset_report_reject(0.into()); + + assert!(notif.peers.is_empty()); + assert!(notif.incoming.is_empty()); + } + + #[test] + fn reject_non_active_connection() { + let (mut notif, _peerset) = development_notifs(); + let peer = PeerId::random(); + let conn = ConnectionId::new(0usize); + let set_id = sc_peerset::SetId::from(0); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Disabled { .. }))); + + // remote opens a substream, verify that peer state is updated to `Incoming` + notif.on_connection_handler_event( + peer, + conn, + NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, + ); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Incoming { .. }))); + + notif.incoming[0].alive = false; + notif.peerset_report_reject(0.into()); + + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Incoming { .. }))); + } + + #[test] + #[should_panic] + #[cfg(debug_assertions)] + fn reject_non_existent_peer_but_alive_connection() { + let (mut notif, _peerset) = development_notifs(); + let peer = PeerId::random(); + let conn = ConnectionId::new(0usize); + let set_id = sc_peerset::SetId::from(0); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Disabled { .. }))); + + // remote opens a substream, verify that peer state is updated to `Incoming` + notif.on_connection_handler_event( + peer, + conn, + NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, + ); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Incoming { .. }))); + assert!(std::matches!( + notif.incoming[0], + IncomingPeer { alive: true, incoming_id: sc_peerset::IncomingIndex(0), .. }, + )); + + notif.peers.remove(&(peer, set_id)); + notif.peerset_report_reject(0.into()); + } + + #[test] + #[should_panic] + #[cfg(debug_assertions)] + fn inject_non_existent_connection_closed_for_incoming_peer() { + let (mut notif, _peerset) = development_notifs(); + let peer = PeerId::random(); + let conn = ConnectionId::new(0usize); + let set_id = sc_peerset::SetId::from(0); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Disabled { .. }))); + + // remote opens a substream, verify that peer state is updated to `Incoming` + notif.on_connection_handler_event( + peer, + conn, + NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, + ); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Incoming { .. }))); + + notif.on_swarm_event(FromSwarm::ConnectionClosed( + libp2p::swarm::behaviour::ConnectionClosed { + peer_id: peer, + connection_id: ConnectionId::new(1337usize), + endpoint: &connected, + handler: NotifsHandlerProto::new(vec![]).into_handler(&peer, &connected), + remaining_established: 0usize, + }, + )); + } + + #[test] + #[should_panic] + #[cfg(debug_assertions)] + fn inject_non_existent_connection_closed_for_disabled_peer() { + let (mut notif, _peerset) = development_notifs(); + let set_id = sc_peerset::SetId::from(0); + let peer = PeerId::random(); + let conn = ConnectionId::new(0usize); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Disabled { .. }))); + + notif.on_swarm_event(FromSwarm::ConnectionClosed( + libp2p::swarm::behaviour::ConnectionClosed { + peer_id: peer, + connection_id: ConnectionId::new(1337usize), + endpoint: &connected, + handler: NotifsHandlerProto::new(vec![]).into_handler(&peer, &connected), + remaining_established: 0usize, + }, + )); + } + + #[test] + #[should_panic] + #[cfg(debug_assertions)] + fn inject_non_existent_connection_closed_for_disabled_pending_enable() { + let (mut notif, _peerset) = development_notifs(); + let set_id = sc_peerset::SetId::from(0); + let peer = PeerId::random(); + let conn = ConnectionId::new(0usize); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Disabled { .. }))); + + // manually add backoff for the entry + if let Some(PeerState::Disabled { ref mut backoff_until, .. }) = + notif.peers.get_mut(&(peer, set_id)) + { + *backoff_until = + Some(Instant::now().checked_add(std::time::Duration::from_secs(5)).unwrap()); + } + + // switch state to `DisabledPendingEnable` + notif.peerset_report_connect(peer, set_id); + + assert!(std::matches!( + notif.peers.get(&(peer, set_id)), + Some(&PeerState::DisabledPendingEnable { .. }) + )); + + notif.on_swarm_event(FromSwarm::ConnectionClosed( + libp2p::swarm::behaviour::ConnectionClosed { + peer_id: peer, + connection_id: ConnectionId::new(1337usize), + endpoint: &connected, + handler: NotifsHandlerProto::new(vec![]).into_handler(&peer, &connected), + remaining_established: 0usize, + }, + )); + } + + #[test] + #[should_panic] + #[cfg(debug_assertions)] + fn inject_connection_closed_for_incoming_peer_state_mismatch() { + let (mut notif, _peerset) = development_notifs(); + let peer = PeerId::random(); + let conn = ConnectionId::new(0usize); + let set_id = sc_peerset::SetId::from(0); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Disabled { .. }))); + + // remote opens a substream, verify that peer state is updated to `Incoming` + notif.on_connection_handler_event( + peer, + conn, + NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, + ); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Incoming { .. }))); + notif.incoming[0].alive = false; + + notif.on_swarm_event(FromSwarm::ConnectionClosed( + libp2p::swarm::behaviour::ConnectionClosed { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + handler: NotifsHandlerProto::new(vec![]).into_handler(&peer, &connected), + remaining_established: 0usize, + }, + )); + } + + #[test] + #[should_panic] + #[cfg(debug_assertions)] + fn inject_connection_closed_for_enabled_state_mismatch() { + let (mut notif, _peerset) = development_notifs(); + let peer = PeerId::random(); + let conn = ConnectionId::new(0usize); + let set_id = sc_peerset::SetId::from(0); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Disabled { .. }))); + + // remote opens a substream, verify that peer state is updated to `Incoming` + notif.on_connection_handler_event( + peer, + conn, + NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, + ); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Incoming { .. }))); + + // attempt to connect to the peer and verify that the peer state is `Enabled` + notif.peerset_report_connect(peer, set_id); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Enabled { .. }))); + + notif.on_swarm_event(FromSwarm::ConnectionClosed( + libp2p::swarm::behaviour::ConnectionClosed { + peer_id: peer, + connection_id: ConnectionId::new(1337usize), + endpoint: &connected, + handler: NotifsHandlerProto::new(vec![]).into_handler(&peer, &connected), + remaining_established: 0usize, + }, + )); + } + + #[test] + #[should_panic] + #[cfg(debug_assertions)] + fn inject_connection_closed_for_backoff_peer() { + let (mut notif, _peerset) = development_notifs(); + let set_id = sc_peerset::SetId::from(0); + let peer = PeerId::random(); + let conn = ConnectionId::new(0usize); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + + notif.on_swarm_event(FromSwarm::ConnectionEstablished( + libp2p::swarm::behaviour::ConnectionEstablished { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + failed_addresses: &[], + other_established: 0usize, + }, + )); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Disabled { .. }))); + + // manually add backoff for the entry + if let Some(PeerState::Disabled { ref mut backoff_until, .. }) = + notif.peers.get_mut(&(peer, set_id)) + { + *backoff_until = + Some(Instant::now().checked_add(std::time::Duration::from_secs(5)).unwrap()); + } + + notif.on_swarm_event(FromSwarm::ConnectionClosed( + libp2p::swarm::behaviour::ConnectionClosed { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + handler: NotifsHandlerProto::new(vec![]).into_handler(&peer, &connected), + remaining_established: 0usize, + }, + )); + assert!(std::matches!(notif.peers.get(&(peer, set_id)), Some(&PeerState::Backoff { .. }))); + + notif.on_swarm_event(FromSwarm::ConnectionClosed( + libp2p::swarm::behaviour::ConnectionClosed { + peer_id: peer, + connection_id: conn, + endpoint: &connected, + handler: NotifsHandlerProto::new(vec![]).into_handler(&peer, &connected), + remaining_established: 0usize, + }, + )); + } + + #[test] + #[should_panic] + #[cfg(debug_assertions)] + fn open_result_ok_non_existent_peer() { + let (mut notif, _peerset) = development_notifs(); + let conn = ConnectionId::new(0usize); + let connected = ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }; + let mut conn_yielder = ConnectionYielder::new(); + + notif.on_connection_handler_event( + PeerId::random(), + conn, + conn_yielder.open_substream(PeerId::random(), 0, connected, vec![1, 2, 3, 4]), + ); + } +} diff --git a/client/network/src/protocol/notifications/handler.rs b/client/network/src/protocol/notifications/handler.rs index ea09cb76edce1..57561c7b9879d 100644 --- a/client/network/src/protocol/notifications/handler.rs +++ b/client/network/src/protocol/notifications/handler.rs @@ -58,8 +58,8 @@ //! [`NotifsHandlerIn::Open`] has gotten an answer. use crate::protocol::notifications::upgrade::{ - NotificationsHandshakeError, NotificationsIn, NotificationsInSubstream, NotificationsOut, - NotificationsOutSubstream, UpgradeCollec, + NotificationsIn, NotificationsInSubstream, NotificationsOut, NotificationsOutSubstream, + UpgradeCollec, }; use bytes::BytesMut; @@ -69,12 +69,9 @@ use futures::{ prelude::*, }; use libp2p::{ - core::{ - upgrade::{InboundUpgrade, OutboundUpgrade}, - ConnectedPoint, PeerId, - }, + core::{ConnectedPoint, PeerId}, swarm::{ - ConnectionHandler, ConnectionHandlerEvent, ConnectionHandlerUpgrErr, IntoConnectionHandler, + handler::ConnectionEvent, ConnectionHandler, ConnectionHandlerEvent, IntoConnectionHandler, KeepAlive, NegotiatedSubstream, SubstreamProtocol, }, }; @@ -494,98 +491,128 @@ impl ConnectionHandler for NotifsHandler { SubstreamProtocol::new(protocols, ()) } - fn inject_fully_negotiated_inbound( + fn on_connection_event( &mut self, - (mut in_substream_open, protocol_index): >::Output, - (): (), + event: ConnectionEvent< + '_, + Self::InboundProtocol, + Self::OutboundProtocol, + Self::InboundOpenInfo, + Self::OutboundOpenInfo, + >, ) { - let mut protocol_info = &mut self.protocols[protocol_index]; - match protocol_info.state { - State::Closed { pending_opening } => { - self.events_queue.push_back(ConnectionHandlerEvent::Custom( - NotifsHandlerOut::OpenDesiredByRemote { protocol_index }, - )); + match event { + ConnectionEvent::FullyNegotiatedInbound(inbound) => { + let (mut in_substream_open, protocol_index) = inbound.protocol; + let mut protocol_info = &mut self.protocols[protocol_index]; - protocol_info.state = State::OpenDesiredByRemote { - in_substream: in_substream_open.substream, - pending_opening, - }; - }, - State::OpenDesiredByRemote { .. } => { - // If a substream already exists, silently drop the new one. - // Note that we drop the substream, which will send an equivalent to a - // TCP "RST" to the remote and force-close the substream. It might - // seem like an unclean way to get rid of a substream. However, keep - // in mind that it is invalid for the remote to open multiple such - // substreams, and therefore sending a "RST" is the most correct thing - // to do. - return - }, - State::Opening { ref mut in_substream, .. } | - State::Open { ref mut in_substream, .. } => { - if in_substream.is_some() { - // Same remark as above. - return - } + match protocol_info.state { + State::Closed { pending_opening } => { + self.events_queue.push_back(ConnectionHandlerEvent::Custom( + NotifsHandlerOut::OpenDesiredByRemote { protocol_index }, + )); - // Create `handshake_message` on a separate line to be sure that the - // lock is released as soon as possible. - let handshake_message = protocol_info.config.handshake.read().clone(); - in_substream_open.substream.send_handshake(handshake_message); - *in_substream = Some(in_substream_open.substream); - }, - } - } + protocol_info.state = State::OpenDesiredByRemote { + in_substream: in_substream_open.substream, + pending_opening, + }; + }, + State::OpenDesiredByRemote { .. } => { + // If a substream already exists, silently drop the new one. + // Note that we drop the substream, which will send an equivalent to a + // TCP "RST" to the remote and force-close the substream. It might + // seem like an unclean way to get rid of a substream. However, keep + // in mind that it is invalid for the remote to open multiple such + // substreams, and therefore sending a "RST" is the most correct thing + // to do. + return + }, + State::Opening { ref mut in_substream, .. } | + State::Open { ref mut in_substream, .. } => { + if in_substream.is_some() { + // Same remark as above. + return + } - fn inject_fully_negotiated_outbound( - &mut self, - new_open: >::Output, - protocol_index: Self::OutboundOpenInfo, - ) { - match self.protocols[protocol_index].state { - State::Closed { ref mut pending_opening } | - State::OpenDesiredByRemote { ref mut pending_opening, .. } => { - debug_assert!(*pending_opening); - *pending_opening = false; - }, - State::Open { .. } => { - error!(target: "sub-libp2p", "☎️ State mismatch in notifications handler"); - debug_assert!(false); + // Create `handshake_message` on a separate line to be sure that the + // lock is released as soon as possible. + let handshake_message = protocol_info.config.handshake.read().clone(); + in_substream_open.substream.send_handshake(handshake_message); + *in_substream = Some(in_substream_open.substream); + }, + } }, - State::Opening { ref mut in_substream } => { - let (async_tx, async_rx) = mpsc::channel(ASYNC_NOTIFICATIONS_BUFFER_SIZE); - let (sync_tx, sync_rx) = mpsc::channel(SYNC_NOTIFICATIONS_BUFFER_SIZE); - let notifications_sink = NotificationsSink { - inner: Arc::new(NotificationsSinkInner { - peer_id: self.peer_id, - async_channel: FuturesMutex::new(async_tx), - sync_channel: Mutex::new(Some(sync_tx)), - }), - }; - - self.protocols[protocol_index].state = State::Open { - notifications_sink_rx: stream::select(async_rx.fuse(), sync_rx.fuse()) - .peekable(), - out_substream: Some(new_open.substream), - in_substream: in_substream.take(), - }; + ConnectionEvent::FullyNegotiatedOutbound(outbound) => { + let (new_open, protocol_index) = (outbound.protocol, outbound.info); - self.events_queue.push_back(ConnectionHandlerEvent::Custom( - NotifsHandlerOut::OpenResultOk { - protocol_index, - negotiated_fallback: new_open.negotiated_fallback, - endpoint: self.endpoint.clone(), - received_handshake: new_open.handshake, - notifications_sink, + match self.protocols[protocol_index].state { + State::Closed { ref mut pending_opening } | + State::OpenDesiredByRemote { ref mut pending_opening, .. } => { + debug_assert!(*pending_opening); + *pending_opening = false; }, - )); + State::Open { .. } => { + error!(target: "sub-libp2p", "☎️ State mismatch in notifications handler"); + debug_assert!(false); + }, + State::Opening { ref mut in_substream } => { + let (async_tx, async_rx) = mpsc::channel(ASYNC_NOTIFICATIONS_BUFFER_SIZE); + let (sync_tx, sync_rx) = mpsc::channel(SYNC_NOTIFICATIONS_BUFFER_SIZE); + let notifications_sink = NotificationsSink { + inner: Arc::new(NotificationsSinkInner { + peer_id: self.peer_id, + async_channel: FuturesMutex::new(async_tx), + sync_channel: Mutex::new(Some(sync_tx)), + }), + }; + + self.protocols[protocol_index].state = State::Open { + notifications_sink_rx: stream::select(async_rx.fuse(), sync_rx.fuse()) + .peekable(), + out_substream: Some(new_open.substream), + in_substream: in_substream.take(), + }; + + self.events_queue.push_back(ConnectionHandlerEvent::Custom( + NotifsHandlerOut::OpenResultOk { + protocol_index, + negotiated_fallback: new_open.negotiated_fallback, + endpoint: self.endpoint.clone(), + received_handshake: new_open.handshake, + notifications_sink, + }, + )); + }, + } }, + ConnectionEvent::AddressChange(_address_change) => {}, + ConnectionEvent::DialUpgradeError(dial_upgrade_error) => match self.protocols + [dial_upgrade_error.info] + .state + { + State::Closed { ref mut pending_opening } | + State::OpenDesiredByRemote { ref mut pending_opening, .. } => { + debug_assert!(*pending_opening); + *pending_opening = false; + }, + + State::Opening { .. } => { + self.protocols[dial_upgrade_error.info].state = + State::Closed { pending_opening: false }; + + self.events_queue.push_back(ConnectionHandlerEvent::Custom( + NotifsHandlerOut::OpenResultErr { protocol_index: dial_upgrade_error.info }, + )); + }, + + // No substream is being open when already `Open`. + State::Open { .. } => debug_assert!(false), + }, + ConnectionEvent::ListenUpgradeError(_listen_upgrade_error) => {}, } } - fn inject_event(&mut self, message: NotifsHandlerIn) { + fn on_behaviour_event(&mut self, message: NotifsHandlerIn) { match message { NotifsHandlerIn::Open { protocol_index } => { let protocol_info = &mut self.protocols[protocol_index]; @@ -676,31 +703,6 @@ impl ConnectionHandler for NotifsHandler { } } - fn inject_dial_upgrade_error( - &mut self, - num: usize, - _: ConnectionHandlerUpgrErr, - ) { - match self.protocols[num].state { - State::Closed { ref mut pending_opening } | - State::OpenDesiredByRemote { ref mut pending_opening, .. } => { - debug_assert!(*pending_opening); - *pending_opening = false; - }, - - State::Opening { .. } => { - self.protocols[num].state = State::Closed { pending_opening: false }; - - self.events_queue.push_back(ConnectionHandlerEvent::Custom( - NotifsHandlerOut::OpenResultErr { protocol_index: num }, - )); - }, - - // No substream is being open when already `Open`. - State::Open { .. } => debug_assert!(false), - } - } - fn connection_keep_alive(&self) -> KeepAlive { // `Yes` if any protocol has some activity. if self.protocols.iter().any(|p| !matches!(p.state, State::Closed { .. })) { @@ -850,3 +852,792 @@ impl ConnectionHandler for NotifsHandler { Poll::Pending } } + +#[cfg(test)] +pub mod tests { + use super::*; + use crate::protocol::notifications::upgrade::{ + NotificationsInOpen, NotificationsInSubstreamHandshake, NotificationsOutOpen, + }; + use asynchronous_codec::Framed; + use libp2p::{ + core::muxing::SubstreamBox, + swarm::{handler, ConnectionHandlerUpgrErr}, + Multiaddr, + }; + use multistream_select::{dialer_select_proto, listener_select_proto, Negotiated, Version}; + use std::{ + collections::HashMap, + io::{Error, IoSlice, IoSliceMut}, + }; + use tokio::sync::mpsc; + use unsigned_varint::codec::UviBytes; + + struct OpenSubstream { + notifications: stream::Peekable< + stream::Select< + stream::Fuse>, + stream::Fuse>, + >, + >, + _in_substream: MockSubstream, + _out_substream: MockSubstream, + } + + pub struct ConnectionYielder { + connections: HashMap<(PeerId, usize), OpenSubstream>, + } + + impl ConnectionYielder { + /// Create new [`ConnectionYielder`]. + pub fn new() -> Self { + Self { connections: HashMap::new() } + } + + /// Open a new substream for peer. + pub fn open_substream( + &mut self, + peer: PeerId, + protocol_index: usize, + endpoint: ConnectedPoint, + received_handshake: Vec, + ) -> NotifsHandlerOut { + let (async_tx, async_rx) = + futures::channel::mpsc::channel(ASYNC_NOTIFICATIONS_BUFFER_SIZE); + let (sync_tx, sync_rx) = + futures::channel::mpsc::channel(SYNC_NOTIFICATIONS_BUFFER_SIZE); + let notifications_sink = NotificationsSink { + inner: Arc::new(NotificationsSinkInner { + peer_id: peer, + async_channel: FuturesMutex::new(async_tx), + sync_channel: Mutex::new(Some(sync_tx)), + }), + }; + let (in_substream, out_substream) = MockSubstream::new(); + + self.connections.insert( + (peer, protocol_index), + OpenSubstream { + notifications: stream::select(async_rx.fuse(), sync_rx.fuse()).peekable(), + _in_substream: in_substream, + _out_substream: out_substream, + }, + ); + + NotifsHandlerOut::OpenResultOk { + protocol_index, + negotiated_fallback: None, + endpoint, + received_handshake, + notifications_sink, + } + } + + /// Attempt to get next pending event from one of the notification sinks. + pub async fn get_next_event(&mut self, peer: PeerId, set: usize) -> Option> { + let substream = if let Some(info) = self.connections.get_mut(&(peer, set)) { + info + } else { + return None + }; + + futures::future::poll_fn(|cx| match substream.notifications.poll_next_unpin(cx) { + Poll::Ready(Some(NotificationsSinkMessage::Notification { message })) => + Poll::Ready(Some(message)), + Poll::Pending => Poll::Ready(None), + Poll::Ready(Some(NotificationsSinkMessage::ForceClose)) | Poll::Ready(None) => + panic!("sink closed"), + }) + .await + } + } + + struct MockSubstream { + pub rx: mpsc::Receiver>, + pub tx: mpsc::Sender>, + rx_buffer: BytesMut, + } + + impl MockSubstream { + /// Create new substream pair. + pub fn new() -> (Self, Self) { + let (tx1, rx1) = mpsc::channel(32); + let (tx2, rx2) = mpsc::channel(32); + + ( + Self { rx: rx1, tx: tx2, rx_buffer: BytesMut::with_capacity(512) }, + Self { rx: rx2, tx: tx1, rx_buffer: BytesMut::with_capacity(512) }, + ) + } + + /// Create new negotiated substream pair. + pub async fn negotiated() -> (Negotiated, Negotiated) { + let (socket1, socket2) = Self::new(); + let socket1 = SubstreamBox::new(socket1); + let socket2 = SubstreamBox::new(socket2); + + let protos = vec![b"/echo/1.0.0", b"/echo/2.5.0"]; + let (res1, res2) = tokio::join!( + dialer_select_proto(socket1, protos.clone(), Version::V1), + listener_select_proto(socket2, protos), + ); + + (res1.unwrap().1, res2.unwrap().1) + } + } + + impl AsyncWrite for MockSubstream { + fn poll_write<'a>( + self: Pin<&mut Self>, + _cx: &mut Context<'a>, + buf: &[u8], + ) -> Poll> { + match self.tx.try_send(buf.to_vec()) { + Ok(_) => Poll::Ready(Ok(buf.len())), + Err(_) => Poll::Ready(Err(std::io::ErrorKind::UnexpectedEof.into())), + } + } + + fn poll_flush<'a>(self: Pin<&mut Self>, _cx: &mut Context<'a>) -> Poll> { + Poll::Ready(Ok(())) + } + + fn poll_close<'a>(self: Pin<&mut Self>, _cx: &mut Context<'a>) -> Poll> { + Poll::Ready(Ok(())) + } + + fn poll_write_vectored<'a, 'b>( + self: Pin<&mut Self>, + _cx: &mut Context<'a>, + _bufs: &[IoSlice<'b>], + ) -> Poll> { + unimplemented!(); + } + } + + impl AsyncRead for MockSubstream { + fn poll_read<'a>( + mut self: Pin<&mut Self>, + cx: &mut Context<'a>, + buf: &mut [u8], + ) -> Poll> { + match self.rx.poll_recv(cx) { + Poll::Ready(Some(data)) => self.rx_buffer.extend_from_slice(&data), + Poll::Ready(None) => + return Poll::Ready(Err(std::io::ErrorKind::UnexpectedEof.into())), + _ => {}, + } + + let nsize = std::cmp::min(self.rx_buffer.len(), buf.len()); + let data = self.rx_buffer.split_to(nsize); + buf[..nsize].copy_from_slice(&data[..]); + + if nsize > 0 { + return Poll::Ready(Ok(nsize)) + } + + Poll::Pending + } + + fn poll_read_vectored<'a, 'b>( + self: Pin<&mut Self>, + _cx: &mut Context<'a>, + _bufs: &mut [IoSliceMut<'b>], + ) -> Poll> { + unimplemented!(); + } + } + + /// Create new [`NotifsHandler`]. + fn notifs_handler() -> NotifsHandler { + let proto = Protocol { + config: ProtocolConfig { + name: "/foo".into(), + fallback_names: vec![], + handshake: Arc::new(RwLock::new(b"hello, world".to_vec())), + max_notification_size: u64::MAX, + }, + in_upgrade: NotificationsIn::new("/foo", Vec::new(), u64::MAX), + state: State::Closed { pending_opening: false }, + }; + + NotifsHandler { + protocols: vec![proto], + when_connection_open: Instant::now(), + endpoint: ConnectedPoint::Listener { + local_addr: Multiaddr::empty(), + send_back_addr: Multiaddr::empty(), + }, + peer_id: PeerId::random(), + events_queue: VecDeque::new(), + } + } + + // verify that if another substream is attempted to be opened by remote while an inbound + // substream already exists, the new inbound stream is rejected and closed by the local node. + #[tokio::test] + async fn second_open_desired_by_remote_rejected() { + let mut handler = notifs_handler(); + let (io, mut io2) = MockSubstream::negotiated().await; + let mut codec = UviBytes::default(); + codec.set_max_len(usize::MAX); + + let notif_in = NotificationsInOpen { + handshake: b"hello, world".to_vec(), + negotiated_fallback: None, + substream: NotificationsInSubstream::new( + Framed::new(io, codec), + NotificationsInSubstreamHandshake::NotSent, + ), + }; + + handler.on_connection_event(handler::ConnectionEvent::FullyNegotiatedInbound( + handler::FullyNegotiatedInbound { protocol: (notif_in, 0), info: () }, + )); + + // verify that the substream is in (partly) opened state + assert!(std::matches!(handler.protocols[0].state, State::OpenDesiredByRemote { .. })); + futures::future::poll_fn(|cx| { + let mut buf = Vec::with_capacity(512); + assert!(std::matches!(Pin::new(&mut io2).poll_read(cx, &mut buf), Poll::Pending)); + Poll::Ready(()) + }) + .await; + + // attempt to open another inbound substream and verify that it is rejected + let (io, mut io2) = MockSubstream::negotiated().await; + let mut codec = UviBytes::default(); + codec.set_max_len(usize::MAX); + + let notif_in = NotificationsInOpen { + handshake: b"hello, world".to_vec(), + negotiated_fallback: None, + substream: NotificationsInSubstream::new( + Framed::new(io, codec), + NotificationsInSubstreamHandshake::NotSent, + ), + }; + + handler.on_connection_event(handler::ConnectionEvent::FullyNegotiatedInbound( + handler::FullyNegotiatedInbound { protocol: (notif_in, 0), info: () }, + )); + + // verify that the new substream is rejected and closed + futures::future::poll_fn(|cx| { + let mut buf = Vec::with_capacity(512); + + if let Poll::Ready(Err(err)) = Pin::new(&mut io2).poll_read(cx, &mut buf) { + assert_eq!(err.kind(), std::io::ErrorKind::UnexpectedEof,); + } + + Poll::Ready(()) + }) + .await; + } + + #[tokio::test] + async fn open_rejected_if_substream_is_opening() { + let mut handler = notifs_handler(); + let (io, mut io2) = MockSubstream::negotiated().await; + let mut codec = UviBytes::default(); + codec.set_max_len(usize::MAX); + + let notif_in = NotificationsInOpen { + handshake: b"hello, world".to_vec(), + negotiated_fallback: None, + substream: NotificationsInSubstream::new( + Framed::new(io, codec), + NotificationsInSubstreamHandshake::NotSent, + ), + }; + + handler.on_connection_event(handler::ConnectionEvent::FullyNegotiatedInbound( + handler::FullyNegotiatedInbound { protocol: (notif_in, 0), info: () }, + )); + + // verify that the substream is in (partly) opened state + assert!(std::matches!(handler.protocols[0].state, State::OpenDesiredByRemote { .. })); + futures::future::poll_fn(|cx| { + let mut buf = Vec::with_capacity(512); + assert!(std::matches!(Pin::new(&mut io2).poll_read(cx, &mut buf), Poll::Pending)); + Poll::Ready(()) + }) + .await; + + // move the handler state to 'Opening' + handler.on_behaviour_event(NotifsHandlerIn::Open { protocol_index: 0 }); + assert!(std::matches!( + handler.protocols[0].state, + State::Opening { in_substream: Some(_) } + )); + + // remote now tries to open another substream, verify that it is rejected and closed + let (io, mut io2) = MockSubstream::negotiated().await; + let mut codec = UviBytes::default(); + codec.set_max_len(usize::MAX); + + let notif_in = NotificationsInOpen { + handshake: b"hello, world".to_vec(), + negotiated_fallback: None, + substream: NotificationsInSubstream::new( + Framed::new(io, codec), + NotificationsInSubstreamHandshake::NotSent, + ), + }; + + handler.on_connection_event(handler::ConnectionEvent::FullyNegotiatedInbound( + handler::FullyNegotiatedInbound { protocol: (notif_in, 0), info: () }, + )); + + // verify that the new substream is rejected and closed but that the first substream is + // still in correct state + futures::future::poll_fn(|cx| { + let mut buf = Vec::with_capacity(512); + + if let Poll::Ready(Err(err)) = Pin::new(&mut io2).poll_read(cx, &mut buf) { + assert_eq!(err.kind(), std::io::ErrorKind::UnexpectedEof,); + } else { + panic!("unexpected result"); + } + + Poll::Ready(()) + }) + .await; + assert!(std::matches!( + handler.protocols[0].state, + State::Opening { in_substream: Some(_) } + )); + } + + #[tokio::test] + async fn open_rejected_if_substream_already_open() { + let mut handler = notifs_handler(); + let (io, mut io2) = MockSubstream::negotiated().await; + let mut codec = UviBytes::default(); + codec.set_max_len(usize::MAX); + + let notif_in = NotificationsInOpen { + handshake: b"hello, world".to_vec(), + negotiated_fallback: None, + substream: NotificationsInSubstream::new( + Framed::new(io, codec), + NotificationsInSubstreamHandshake::NotSent, + ), + }; + handler.on_connection_event(handler::ConnectionEvent::FullyNegotiatedInbound( + handler::FullyNegotiatedInbound { protocol: (notif_in, 0), info: () }, + )); + + // verify that the substream is in (partly) opened state + assert!(std::matches!(handler.protocols[0].state, State::OpenDesiredByRemote { .. })); + futures::future::poll_fn(|cx| { + let mut buf = Vec::with_capacity(512); + assert!(std::matches!(Pin::new(&mut io2).poll_read(cx, &mut buf), Poll::Pending)); + Poll::Ready(()) + }) + .await; + + // move the handler state to 'Opening' + handler.on_behaviour_event(NotifsHandlerIn::Open { protocol_index: 0 }); + assert!(std::matches!( + handler.protocols[0].state, + State::Opening { in_substream: Some(_) } + )); + + // accept the substream and move its state to `Open` + let (io, _io2) = MockSubstream::negotiated().await; + let mut codec = UviBytes::default(); + codec.set_max_len(usize::MAX); + + let notif_out = NotificationsOutOpen { + handshake: b"hello, world".to_vec(), + negotiated_fallback: None, + substream: NotificationsOutSubstream::new(Framed::new(io, codec)), + }; + handler.on_connection_event(handler::ConnectionEvent::FullyNegotiatedOutbound( + handler::FullyNegotiatedOutbound { protocol: notif_out, info: 0 }, + )); + + assert!(std::matches!( + handler.protocols[0].state, + State::Open { in_substream: Some(_), .. } + )); + + // remote now tries to open another substream, verify that it is rejected and closed + let (io, mut io2) = MockSubstream::negotiated().await; + let mut codec = UviBytes::default(); + codec.set_max_len(usize::MAX); + let notif_in = NotificationsInOpen { + handshake: b"hello, world".to_vec(), + negotiated_fallback: None, + substream: NotificationsInSubstream::new( + Framed::new(io, codec), + NotificationsInSubstreamHandshake::NotSent, + ), + }; + handler.on_connection_event(handler::ConnectionEvent::FullyNegotiatedInbound( + handler::FullyNegotiatedInbound { protocol: (notif_in, 0), info: () }, + )); + + // verify that the new substream is rejected and closed but that the first substream is + // still in correct state + futures::future::poll_fn(|cx| { + let mut buf = Vec::with_capacity(512); + + if let Poll::Ready(Err(err)) = Pin::new(&mut io2).poll_read(cx, &mut buf) { + assert_eq!(err.kind(), std::io::ErrorKind::UnexpectedEof); + } else { + panic!("unexpected result"); + } + + Poll::Ready(()) + }) + .await; + assert!(std::matches!( + handler.protocols[0].state, + State::Open { in_substream: Some(_), .. } + )); + } + + #[tokio::test] + async fn fully_negotiated_resets_state_for_closed_substream() { + let mut handler = notifs_handler(); + let (io, mut io2) = MockSubstream::negotiated().await; + let mut codec = UviBytes::default(); + codec.set_max_len(usize::MAX); + + let notif_in = NotificationsInOpen { + handshake: b"hello, world".to_vec(), + negotiated_fallback: None, + substream: NotificationsInSubstream::new( + Framed::new(io, codec), + NotificationsInSubstreamHandshake::NotSent, + ), + }; + handler.on_connection_event(handler::ConnectionEvent::FullyNegotiatedInbound( + handler::FullyNegotiatedInbound { protocol: (notif_in, 0), info: () }, + )); + + // verify that the substream is in (partly) opened state + assert!(std::matches!(handler.protocols[0].state, State::OpenDesiredByRemote { .. })); + futures::future::poll_fn(|cx| { + let mut buf = Vec::with_capacity(512); + assert!(std::matches!(Pin::new(&mut io2).poll_read(cx, &mut buf), Poll::Pending)); + Poll::Ready(()) + }) + .await; + + // first instruct the handler to open a connection and then close it right after + // so the handler is in state `Closed { pending_opening: true }` + handler.on_behaviour_event(NotifsHandlerIn::Open { protocol_index: 0 }); + assert!(std::matches!( + handler.protocols[0].state, + State::Opening { in_substream: Some(_) } + )); + + handler.on_behaviour_event(NotifsHandlerIn::Close { protocol_index: 0 }); + assert!(std::matches!(handler.protocols[0].state, State::Closed { pending_opening: true })); + + // verify that if the the outbound substream is successfully negotiated, the state is not + // changed as the substream was commanded to be closed by the handler. + let (io, _io2) = MockSubstream::negotiated().await; + let mut codec = UviBytes::default(); + codec.set_max_len(usize::MAX); + + let notif_out = NotificationsOutOpen { + handshake: b"hello, world".to_vec(), + negotiated_fallback: None, + substream: NotificationsOutSubstream::new(Framed::new(io, codec)), + }; + handler.on_connection_event(handler::ConnectionEvent::FullyNegotiatedOutbound( + handler::FullyNegotiatedOutbound { protocol: notif_out, info: 0 }, + )); + + assert!(std::matches!( + handler.protocols[0].state, + State::Closed { pending_opening: false } + )); + } + + #[tokio::test] + async fn fully_negotiated_resets_state_for_open_desired_substream() { + let mut handler = notifs_handler(); + let (io, mut io2) = MockSubstream::negotiated().await; + let mut codec = UviBytes::default(); + codec.set_max_len(usize::MAX); + + let notif_in = NotificationsInOpen { + handshake: b"hello, world".to_vec(), + negotiated_fallback: None, + substream: NotificationsInSubstream::new( + Framed::new(io, codec), + NotificationsInSubstreamHandshake::NotSent, + ), + }; + handler.on_connection_event(handler::ConnectionEvent::FullyNegotiatedInbound( + handler::FullyNegotiatedInbound { protocol: (notif_in, 0), info: () }, + )); + + // verify that the substream is in (partly) opened state + assert!(std::matches!(handler.protocols[0].state, State::OpenDesiredByRemote { .. })); + futures::future::poll_fn(|cx| { + let mut buf = Vec::with_capacity(512); + assert!(std::matches!(Pin::new(&mut io2).poll_read(cx, &mut buf), Poll::Pending)); + Poll::Ready(()) + }) + .await; + + // first instruct the handler to open a connection and then close it right after + // so the handler is in state `Closed { pending_opening: true }` + handler.on_behaviour_event(NotifsHandlerIn::Open { protocol_index: 0 }); + assert!(std::matches!( + handler.protocols[0].state, + State::Opening { in_substream: Some(_) } + )); + + handler.on_behaviour_event(NotifsHandlerIn::Close { protocol_index: 0 }); + assert!(std::matches!(handler.protocols[0].state, State::Closed { pending_opening: true })); + + // attempt to open another inbound substream and verify that it is rejected + let (io, _io2) = MockSubstream::negotiated().await; + let mut codec = UviBytes::default(); + codec.set_max_len(usize::MAX); + + let notif_in = NotificationsInOpen { + handshake: b"hello, world".to_vec(), + negotiated_fallback: None, + substream: NotificationsInSubstream::new( + Framed::new(io, codec), + NotificationsInSubstreamHandshake::NotSent, + ), + }; + handler.on_connection_event(handler::ConnectionEvent::FullyNegotiatedInbound( + handler::FullyNegotiatedInbound { protocol: (notif_in, 0), info: () }, + )); + + assert!(std::matches!( + handler.protocols[0].state, + State::OpenDesiredByRemote { pending_opening: true, .. } + )); + + // verify that if the the outbound substream is successfully negotiated, the state is not + // changed as the substream was commanded to be closed by the handler. + let (io, _io2) = MockSubstream::negotiated().await; + let mut codec = UviBytes::default(); + codec.set_max_len(usize::MAX); + + let notif_out = NotificationsOutOpen { + handshake: b"hello, world".to_vec(), + negotiated_fallback: None, + substream: NotificationsOutSubstream::new(Framed::new(io, codec)), + }; + + handler.on_connection_event(handler::ConnectionEvent::FullyNegotiatedOutbound( + handler::FullyNegotiatedOutbound { protocol: notif_out, info: 0 }, + )); + + assert!(std::matches!( + handler.protocols[0].state, + State::OpenDesiredByRemote { pending_opening: false, .. } + )); + } + + #[tokio::test] + async fn dial_upgrade_error_resets_closed_outbound_state() { + let mut handler = notifs_handler(); + let (io, mut io2) = MockSubstream::negotiated().await; + let mut codec = UviBytes::default(); + codec.set_max_len(usize::MAX); + + let notif_in = NotificationsInOpen { + handshake: b"hello, world".to_vec(), + negotiated_fallback: None, + substream: NotificationsInSubstream::new( + Framed::new(io, codec), + NotificationsInSubstreamHandshake::NotSent, + ), + }; + handler.on_connection_event(handler::ConnectionEvent::FullyNegotiatedInbound( + handler::FullyNegotiatedInbound { protocol: (notif_in, 0), info: () }, + )); + + // verify that the substream is in (partly) opened state + assert!(std::matches!(handler.protocols[0].state, State::OpenDesiredByRemote { .. })); + futures::future::poll_fn(|cx| { + let mut buf = Vec::with_capacity(512); + assert!(std::matches!(Pin::new(&mut io2).poll_read(cx, &mut buf), Poll::Pending)); + Poll::Ready(()) + }) + .await; + + // first instruct the handler to open a connection and then close it right after + // so the handler is in state `Closed { pending_opening: true }` + handler.on_behaviour_event(NotifsHandlerIn::Open { protocol_index: 0 }); + assert!(std::matches!( + handler.protocols[0].state, + State::Opening { in_substream: Some(_) } + )); + + handler.on_behaviour_event(NotifsHandlerIn::Close { protocol_index: 0 }); + assert!(std::matches!(handler.protocols[0].state, State::Closed { pending_opening: true })); + + // inject dial failure to an already closed substream and verify outbound state is reset + handler.on_connection_event(handler::ConnectionEvent::DialUpgradeError( + handler::DialUpgradeError { info: 0, error: ConnectionHandlerUpgrErr::Timeout }, + )); + assert!(std::matches!( + handler.protocols[0].state, + State::Closed { pending_opening: false } + )); + } + + #[tokio::test] + async fn dial_upgrade_error_resets_open_desired_state() { + let mut handler = notifs_handler(); + let (io, mut io2) = MockSubstream::negotiated().await; + let mut codec = UviBytes::default(); + codec.set_max_len(usize::MAX); + + let notif_in = NotificationsInOpen { + handshake: b"hello, world".to_vec(), + negotiated_fallback: None, + substream: NotificationsInSubstream::new( + Framed::new(io, codec), + NotificationsInSubstreamHandshake::NotSent, + ), + }; + handler.on_connection_event(handler::ConnectionEvent::FullyNegotiatedInbound( + handler::FullyNegotiatedInbound { protocol: (notif_in, 0), info: () }, + )); + + // verify that the substream is in (partly) opened state + assert!(std::matches!(handler.protocols[0].state, State::OpenDesiredByRemote { .. })); + futures::future::poll_fn(|cx| { + let mut buf = Vec::with_capacity(512); + assert!(std::matches!(Pin::new(&mut io2).poll_read(cx, &mut buf), Poll::Pending)); + Poll::Ready(()) + }) + .await; + + // first instruct the handler to open a connection and then close it right after + // so the handler is in state `Closed { pending_opening: true }` + handler.on_behaviour_event(NotifsHandlerIn::Open { protocol_index: 0 }); + assert!(std::matches!( + handler.protocols[0].state, + State::Opening { in_substream: Some(_) } + )); + + handler.on_behaviour_event(NotifsHandlerIn::Close { protocol_index: 0 }); + assert!(std::matches!(handler.protocols[0].state, State::Closed { pending_opening: true })); + + let (io, _io2) = MockSubstream::negotiated().await; + let mut codec = UviBytes::default(); + codec.set_max_len(usize::MAX); + + let notif_in = NotificationsInOpen { + handshake: b"hello, world".to_vec(), + negotiated_fallback: None, + substream: NotificationsInSubstream::new( + Framed::new(io, codec), + NotificationsInSubstreamHandshake::NotSent, + ), + }; + handler.on_connection_event(handler::ConnectionEvent::FullyNegotiatedInbound( + handler::FullyNegotiatedInbound { protocol: (notif_in, 0), info: () }, + )); + + assert!(std::matches!( + handler.protocols[0].state, + State::OpenDesiredByRemote { pending_opening: true, .. } + )); + + // inject dial failure to an already closed substream and verify outbound state is reset + handler.on_connection_event(handler::ConnectionEvent::DialUpgradeError( + handler::DialUpgradeError { info: 0, error: ConnectionHandlerUpgrErr::Timeout }, + )); + assert!(std::matches!( + handler.protocols[0].state, + State::OpenDesiredByRemote { pending_opening: false, .. } + )); + } + + #[tokio::test] + async fn sync_notifications_clogged() { + let mut handler = notifs_handler(); + let (io, _) = MockSubstream::negotiated().await; + let codec = UviBytes::default(); + + let (async_tx, async_rx) = futures::channel::mpsc::channel(ASYNC_NOTIFICATIONS_BUFFER_SIZE); + let (sync_tx, sync_rx) = futures::channel::mpsc::channel(1); + let notifications_sink = NotificationsSink { + inner: Arc::new(NotificationsSinkInner { + peer_id: PeerId::random(), + async_channel: FuturesMutex::new(async_tx), + sync_channel: Mutex::new(Some(sync_tx)), + }), + }; + + handler.protocols[0].state = State::Open { + notifications_sink_rx: stream::select(async_rx.fuse(), sync_rx.fuse()).peekable(), + out_substream: Some(NotificationsOutSubstream::new(Framed::new(io, codec))), + in_substream: None, + }; + + notifications_sink.send_sync_notification(vec![1, 3, 3, 7]); + notifications_sink.send_sync_notification(vec![1, 3, 3, 8]); + notifications_sink.send_sync_notification(vec![1, 3, 3, 9]); + notifications_sink.send_sync_notification(vec![1, 3, 4, 0]); + + futures::future::poll_fn(|cx| { + assert!(std::matches!( + handler.poll(cx), + Poll::Ready(ConnectionHandlerEvent::Close( + NotifsHandlerError::SyncNotificationsClogged, + )) + )); + Poll::Ready(()) + }) + .await; + } + + #[tokio::test] + async fn close_desired_by_remote() { + let mut handler = notifs_handler(); + let (io, io2) = MockSubstream::negotiated().await; + let mut codec = UviBytes::default(); + codec.set_max_len(usize::MAX); + + let notif_in = NotificationsInOpen { + handshake: b"hello, world".to_vec(), + negotiated_fallback: None, + substream: NotificationsInSubstream::new( + Framed::new(io, codec), + NotificationsInSubstreamHandshake::PendingSend(vec![1, 2, 3, 4]), + ), + }; + + // add new inbound substream but close it immediately and verify that correct events are + // emitted + handler.on_connection_event(handler::ConnectionEvent::FullyNegotiatedInbound( + handler::FullyNegotiatedInbound { protocol: (notif_in, 0), info: () }, + )); + drop(io2); + + futures::future::poll_fn(|cx| { + assert!(std::matches!( + handler.poll(cx), + Poll::Ready(ConnectionHandlerEvent::Custom( + NotifsHandlerOut::OpenDesiredByRemote { protocol_index: 0 }, + )) + )); + assert!(std::matches!( + handler.poll(cx), + Poll::Ready(ConnectionHandlerEvent::Custom(NotifsHandlerOut::CloseDesired { + protocol_index: 0 + },)) + )); + Poll::Ready(()) + }) + .await; + } +} diff --git a/client/network/src/protocol/notifications/upgrade.rs b/client/network/src/protocol/notifications/upgrade.rs index c273361acabdd..89fede25f6ae7 100644 --- a/client/network/src/protocol/notifications/upgrade.rs +++ b/client/network/src/protocol/notifications/upgrade.rs @@ -20,8 +20,8 @@ pub use self::{ collec::UpgradeCollec, notifications::{ NotificationsHandshakeError, NotificationsIn, NotificationsInOpen, - NotificationsInSubstream, NotificationsOut, NotificationsOutError, NotificationsOutOpen, - NotificationsOutSubstream, + NotificationsInSubstream, NotificationsInSubstreamHandshake, NotificationsOut, + NotificationsOutError, NotificationsOutOpen, NotificationsOutSubstream, }, }; diff --git a/client/network/src/protocol/notifications/upgrade/collec.rs b/client/network/src/protocol/notifications/upgrade/collec.rs index db9850c8da74b..288b8bfd4849c 100644 --- a/client/network/src/protocol/notifications/upgrade/collec.rs +++ b/client/network/src/protocol/notifications/upgrade/collec.rs @@ -73,7 +73,7 @@ where } /// Groups a `ProtocolName` with a `usize`. -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq)] pub struct ProtoNameWithUsize(T, usize); impl ProtocolName for ProtoNameWithUsize { @@ -99,3 +99,81 @@ impl>, O, E> Future for FutWithUsize { } } } + +#[cfg(test)] +mod tests { + use super::*; + use libp2p::core::upgrade::{ProtocolName, UpgradeInfo}; + use sc_network_common::protocol::ProtocolName as ProtoName; + + // TODO: move to mocks + mockall::mock! { + pub ProtocolUpgrade {} + + impl UpgradeInfo for ProtocolUpgrade { + type Info = T; + type InfoIter = vec::IntoIter; + fn protocol_info(&self) -> vec::IntoIter; + } + } + + #[test] + fn protocol_info() { + let upgrades = (1..=3) + .map(|i| { + let mut upgrade = MockProtocolUpgrade::>::new(); + upgrade.expect_protocol_info().return_once(move || { + vec![ProtoNameWithUsize(ProtoName::from(format!("protocol{i}")), i)].into_iter() + }); + upgrade + }) + .collect::>(); + + let upgrade: UpgradeCollec<_> = upgrades.into_iter().collect::>(); + let protos = vec![ + ProtoNameWithUsize(ProtoNameWithUsize(ProtoName::from("protocol1".to_string()), 1), 0), + ProtoNameWithUsize(ProtoNameWithUsize(ProtoName::from("protocol2".to_string()), 2), 1), + ProtoNameWithUsize(ProtoNameWithUsize(ProtoName::from("protocol3".to_string()), 3), 2), + ]; + let upgrades = upgrade.protocol_info().collect::>(); + + assert_eq!(upgrades, protos,); + } + + #[test] + fn nested_protocol_info() { + let mut upgrades = (1..=2) + .map(|i| { + let mut upgrade = MockProtocolUpgrade::>::new(); + upgrade.expect_protocol_info().return_once(move || { + vec![ProtoNameWithUsize(ProtoName::from(format!("protocol{i}")), i)].into_iter() + }); + upgrade + }) + .collect::>(); + + upgrades.push({ + let mut upgrade = MockProtocolUpgrade::>::new(); + upgrade.expect_protocol_info().return_once(move || { + vec![ + ProtoNameWithUsize(ProtoName::from("protocol22".to_string()), 1), + ProtoNameWithUsize(ProtoName::from("protocol33".to_string()), 2), + ProtoNameWithUsize(ProtoName::from("protocol44".to_string()), 3), + ] + .into_iter() + }); + upgrade + }); + + let upgrade: UpgradeCollec<_> = upgrades.into_iter().collect::>(); + let protos = vec![ + ProtoNameWithUsize(ProtoNameWithUsize(ProtoName::from("protocol1".to_string()), 1), 0), + ProtoNameWithUsize(ProtoNameWithUsize(ProtoName::from("protocol2".to_string()), 2), 1), + ProtoNameWithUsize(ProtoNameWithUsize(ProtoName::from("protocol22".to_string()), 1), 2), + ProtoNameWithUsize(ProtoNameWithUsize(ProtoName::from("protocol33".to_string()), 2), 2), + ProtoNameWithUsize(ProtoNameWithUsize(ProtoName::from("protocol44".to_string()), 3), 2), + ]; + let upgrades = upgrade.protocol_info().collect::>(); + assert_eq!(upgrades, protos,); + } +} diff --git a/client/network/src/protocol/notifications/upgrade/notifications.rs b/client/network/src/protocol/notifications/upgrade/notifications.rs index 5a4ec832dbea1..71afc3c90e37f 100644 --- a/client/network/src/protocol/notifications/upgrade/notifications.rs +++ b/client/network/src/protocol/notifications/upgrade/notifications.rs @@ -88,7 +88,8 @@ pub struct NotificationsInSubstream { } /// State of the handshake sending back process. -enum NotificationsInSubstreamHandshake { +#[derive(Debug)] +pub enum NotificationsInSubstreamHandshake { /// Waiting for the user to give us the handshake message. NotSent, /// User gave us the handshake message. Trying to push it in the socket. @@ -111,6 +112,13 @@ pub struct NotificationsOutSubstream { socket: Framed>>>, } +#[cfg(test)] +impl NotificationsOutSubstream { + pub fn new(socket: Framed>>>) -> Self { + Self { socket } + } +} + impl NotificationsIn { /// Builds a new potential upgrade. pub fn new( @@ -193,6 +201,14 @@ impl NotificationsInSubstream where TSubstream: AsyncRead + AsyncWrite + Unpin, { + #[cfg(test)] + pub fn new( + socket: Framed>>>, + handshake: NotificationsInSubstreamHandshake, + ) -> Self { + Self { socket, handshake } + } + /// Sends the handshake in order to inform the remote that we accept the substream. pub fn send_handshake(&mut self, message: impl Into>) { if !matches!(self.handshake, NotificationsInSubstreamHandshake::NotSent) { diff --git a/client/network/sync/Cargo.toml b/client/network/sync/Cargo.toml index ff72b4e993026..532e873836204 100644 --- a/client/network/sync/Cargo.toml +++ b/client/network/sync/Cargo.toml @@ -23,7 +23,7 @@ futures = "0.3.21" libp2p = "0.50.0" log = "0.4.17" lru = "0.8.1" -mockall = "0.11.2" +mockall = "0.11.3" prost = "0.11" smallvec = "1.8.0" thiserror = "1.0" From 4123495407542eb3285f1bc963041e894ae27539 Mon Sep 17 00:00:00 2001 From: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Date: Wed, 8 Feb 2023 11:37:36 -0300 Subject: [PATCH 114/162] Configurable voting-degree in council elections pallet (#13305) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * configurable council elections pallet * configurable council elections pallet * add warning * reduce sizes * ".git/.scripts/commands/bench/bench.sh" pallet dev pallet_elections_phragmen * fix stuff * make assert * fix docs * fix docs again * fix docs again * Update frame/elections-phragmen/src/lib.rs Co-authored-by: Gonçalo Pestana * Update frame/elections-phragmen/src/lib.rs Co-authored-by: Gonçalo Pestana * Update frame/elections-phragmen/src/lib.rs Co-authored-by: Gonçalo Pestana * fix docs --------- Co-authored-by: command-bot <> Co-authored-by: Gonçalo Pestana --- bin/node/runtime/src/lib.rs | 6 +- frame/elections-phragmen/src/benchmarking.rs | 88 +----- frame/elections-phragmen/src/lib.rs | 96 +++++-- frame/elections-phragmen/src/weights.rs | 265 +++++++++--------- .../procedural/src/construct_runtime/mod.rs | 1 + 5 files changed, 216 insertions(+), 240 deletions(-) diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 3f4c464241f8d..4298a6eced430 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -1003,8 +1003,9 @@ parameter_types! { pub const TermDuration: BlockNumber = 7 * DAYS; pub const DesiredMembers: u32 = 13; pub const DesiredRunnersUp: u32 = 7; - pub const MaxVoters: u32 = 10 * 1000; - pub const MaxCandidates: u32 = 1000; + pub const MaxVotesPerVoter: u32 = 16; + pub const MaxVoters: u32 = 512; + pub const MaxCandidates: u32 = 64; pub const ElectionsPhragmenPalletId: LockIdentifier = *b"phrelect"; } @@ -1029,6 +1030,7 @@ impl pallet_elections_phragmen::Config for Runtime { type DesiredRunnersUp = DesiredRunnersUp; type TermDuration = TermDuration; type MaxVoters = MaxVoters; + type MaxVotesPerVoter = MaxVotesPerVoter; type MaxCandidates = MaxCandidates; type WeightInfo = pallet_elections_phragmen::weights::SubstrateWeight; } diff --git a/frame/elections-phragmen/src/benchmarking.rs b/frame/elections-phragmen/src/benchmarking.rs index 1fc500a8e3464..b7c04bad318b0 100644 --- a/frame/elections-phragmen/src/benchmarking.rs +++ b/frame/elections-phragmen/src/benchmarking.rs @@ -148,7 +148,7 @@ fn clean() { benchmarks! { // -- Signed ones vote_equal { - let v in 1 .. (MAXIMUM_VOTE as u32); + let v in 1 .. T::MaxVotesPerVoter::get(); clean::(); // create a bunch of candidates. @@ -168,7 +168,7 @@ benchmarks! { }: vote(RawOrigin::Signed(caller), votes, stake) vote_more { - let v in 2 .. (MAXIMUM_VOTE as u32); + let v in 2 .. T::MaxVotesPerVoter::get(); clean::(); // create a bunch of candidates. @@ -190,7 +190,7 @@ benchmarks! { }: vote(RawOrigin::Signed(caller), votes, stake / >::from(10u32)) vote_less { - let v in 2 .. (MAXIMUM_VOTE as u32); + let v in 2 .. T::MaxVotesPerVoter::get(); clean::(); // create a bunch of candidates. @@ -212,7 +212,7 @@ benchmarks! { remove_voter { // we fix the number of voted candidates to max - let v = MAXIMUM_VOTE as u32; + let v = T::MaxVotesPerVoter::get(); clean::(); // create a bunch of candidates. @@ -368,7 +368,7 @@ benchmarks! { clean::(); let all_candidates = submit_candidates::(T::MaxCandidates::get(), "candidates")?; - distribute_voters::(all_candidates, v, MAXIMUM_VOTE)?; + distribute_voters::(all_candidates, v, T::MaxVotesPerVoter::get() as usize)?; // all candidates leave. >::kill(); @@ -389,17 +389,17 @@ benchmarks! { // that we give all candidates a self vote to make sure they are all considered. let c in 1 .. T::MaxCandidates::get(); let v in 1 .. T::MaxVoters::get(); - let e in (T::MaxVoters::get()) .. T::MaxVoters::get() as u32 * MAXIMUM_VOTE as u32; + let e in (T::MaxVoters::get()) .. T::MaxVoters::get() * T::MaxVotesPerVoter::get(); clean::(); // so we have a situation with v and e. we want e to basically always be in the range of `e - // -> e * MAXIMUM_VOTE`, but we cannot express that now with the benchmarks. So what we do - // is: when c is being iterated, v, and e are max and fine. when v is being iterated, e is - // being set to max and this is a problem. In these cases, we cap e to a lower value, namely - // v * MAXIMUM_VOTE. when e is being iterated, v is at max, and again fine. all in all, - // votes_per_voter can never be more than MAXIMUM_VOTE. Note that this might cause `v` to be - // an overestimate. - let votes_per_voter = (e / v).min(MAXIMUM_VOTE as u32); + // -> e * T::MaxVotesPerVoter::get()`, but we cannot express that now with the benchmarks. + // So what we do is: when c is being iterated, v, and e are max and fine. when v is being + // iterated, e is being set to max and this is a problem. In these cases, we cap e to a + // lower value, namely v * T::MaxVotesPerVoter::get(). when e is being iterated, v is at + // max, and again fine. all in all, votes_per_voter can never be more than + // T::MaxVotesPerVoter::get(). Note that this might cause `v` to be an overestimate. + let votes_per_voter = (e / v).min(T::MaxVotesPerVoter::get()); let all_candidates = submit_candidates_with_self_vote::(c, "candidates")?; let _ = distribute_voters::(all_candidates, v.saturating_sub(c), votes_per_voter as usize)?; @@ -421,68 +421,6 @@ benchmarks! { } } - #[extra] - election_phragmen_c_e { - let c in 1 .. T::MaxCandidates::get(); - let e in (T::MaxVoters::get()) .. T::MaxVoters::get() * MAXIMUM_VOTE as u32; - let fixed_v = T::MaxVoters::get(); - clean::(); - - let votes_per_voter = e / fixed_v; - - let all_candidates = submit_candidates_with_self_vote::(c, "candidates")?; - let _ = distribute_voters::( - all_candidates, - fixed_v - c, - votes_per_voter as usize, - )?; - }: { - >::on_initialize(T::TermDuration::get()); - } - verify { - assert_eq!(>::members().len() as u32, T::DesiredMembers::get().min(c)); - assert_eq!( - >::runners_up().len() as u32, - T::DesiredRunnersUp::get().min(c.saturating_sub(T::DesiredMembers::get())), - ); - - #[cfg(test)] - { - // reset members in between benchmark tests. - use crate::tests::MEMBERS; - MEMBERS.with(|m| *m.borrow_mut() = vec![]); - } - } - - #[extra] - election_phragmen_v { - let v in 4 .. 16; - let fixed_c = T::MaxCandidates::get() / 10; - let fixed_e = 64; - clean::(); - - let votes_per_voter = fixed_e / v; - - let all_candidates = submit_candidates_with_self_vote::(fixed_c, "candidates")?; - let _ = distribute_voters::(all_candidates, v, votes_per_voter as usize)?; - }: { - >::on_initialize(T::TermDuration::get()); - } - verify { - assert_eq!(>::members().len() as u32, T::DesiredMembers::get().min(fixed_c)); - assert_eq!( - >::runners_up().len() as u32, - T::DesiredRunnersUp::get().min(fixed_c.saturating_sub(T::DesiredMembers::get())), - ); - - #[cfg(test)] - { - // reset members in between benchmark tests. - use crate::tests::MEMBERS; - MEMBERS.with(|m| *m.borrow_mut() = vec![]); - } - } - impl_benchmark_test_suite!( Elections, crate::tests::ExtBuilder::default().desired_members(13).desired_runners_up(7), diff --git a/frame/elections-phragmen/src/lib.rs b/frame/elections-phragmen/src/lib.rs index 1a020adb28632..c655d4a16230b 100644 --- a/frame/elections-phragmen/src/lib.rs +++ b/frame/elections-phragmen/src/lib.rs @@ -43,14 +43,14 @@ //! ### Voting //! //! Voters can vote for a limited number of the candidates by providing a list of account ids, -//! bounded by [`MAXIMUM_VOTE`]. Invalid votes (voting for non-candidates) and duplicate votes are -//! ignored during election. Yet, a voter _might_ vote for a future candidate. Voters reserve a bond -//! as they vote. Each vote defines a `value`. This amount is locked from the account of the voter -//! and indicates the weight of the vote. Voters can update their votes at any time by calling -//! `vote()` again. This can update the vote targets (which might update the deposit) or update the -//! vote's stake ([`Voter::stake`]). After a round, votes are kept and might still be valid for -//! further rounds. A voter is responsible for calling `remove_voter` once they are done to have -//! their bond back and remove the lock. +//! bounded by [`Config::MaxVotesPerVoter`]. Invalid votes (voting for non-candidates) and duplicate +//! votes are ignored during election. Yet, a voter _might_ vote for a future candidate. Voters +//! reserve a bond as they vote. Each vote defines a `value`. This amount is locked from the account +//! of the voter and indicates the weight of the vote. Voters can update their votes at any time by +//! calling `vote()` again. This can update the vote targets (which might update the deposit) or +//! update the vote's stake ([`Voter::stake`]). After a round, votes are kept and might still be +//! valid for further rounds. A voter is responsible for calling `remove_voter` once they are done +//! to have their bond back and remove the lock. //! //! See [`Call::vote`], [`Call::remove_voter`]. //! @@ -124,9 +124,6 @@ pub mod migrations; const LOG_TARGET: &str = "runtime::elections-phragmen"; -/// The maximum votes allowed per voter. -pub const MAXIMUM_VOTE: usize = 16; - type BalanceOf = <::Currency as Currency<::AccountId>>::Balance; type NegativeImbalanceOf = <::Currency as Currency< @@ -254,19 +251,29 @@ pub mod pallet { /// The maximum number of candidates in a phragmen election. /// - /// Warning: The election happens onchain, and this value will determine - /// the size of the election. When this limit is reached no more - /// candidates are accepted in the election. + /// Warning: This impacts the size of the election which is run onchain. Chose wisely, and + /// consider how it will impact `T::WeightInfo::election_phragmen`. + /// + /// When this limit is reached no more candidates are accepted in the election. #[pallet::constant] type MaxCandidates: Get; /// The maximum number of voters to allow in a phragmen election. /// - /// Warning: This impacts the size of the election which is run onchain. + /// Warning: This impacts the size of the election which is run onchain. Chose wisely, and + /// consider how it will impact `T::WeightInfo::election_phragmen`. + /// /// When the limit is reached the new voters are ignored. #[pallet::constant] type MaxVoters: Get; + /// Maximum numbers of votes per voter. + /// + /// Warning: This impacts the size of the election which is run onchain. Chose wisely, and + /// consider how it will impact `T::WeightInfo::election_phragmen`. + #[pallet::constant] + type MaxVotesPerVoter: Get; + /// Weight information for extrinsics in this pallet. type WeightInfo: WeightInfo; } @@ -284,6 +291,41 @@ pub mod pallet { Weight::zero() } } + + fn integrity_test() { + let block_weight = T::BlockWeights::get().max_block; + // mind the order. + let election_weight = T::WeightInfo::election_phragmen( + T::MaxCandidates::get(), + T::MaxVoters::get(), + T::MaxVotesPerVoter::get() * T::MaxVoters::get(), + ); + + let to_seconds = |w: &Weight| { + w.ref_time() as f32 / + frame_support::weights::constants::WEIGHT_REF_TIME_PER_SECOND as f32 + }; + + frame_support::log::debug!( + target: LOG_TARGET, + "election weight {}s ({:?}) // chain's block weight {}s ({:?})", + to_seconds(&election_weight), + election_weight, + to_seconds(&block_weight), + block_weight, + ); + assert!( + election_weight.all_lt(block_weight), + "election weight {}s ({:?}) will exceed a {}s chain's block weight ({:?}) (MaxCandidates {}, MaxVoters {}, MaxVotesPerVoter {} -- tweak these parameters)", + election_weight, + to_seconds(&election_weight), + to_seconds(&block_weight), + block_weight, + T::MaxCandidates::get(), + T::MaxVoters::get(), + T::MaxVotesPerVoter::get(), + ); + } } #[pallet::call] @@ -307,10 +349,6 @@ pub mod pallet { /// /// It is the responsibility of the caller to **NOT** place all of their balance into the /// lock and keep some for further operations. - /// - /// # - /// We assume the maximum weight among all 3 cases: vote_equal, vote_more and vote_less. - /// # #[pallet::call_index(0)] #[pallet::weight( T::WeightInfo::vote_more(votes.len() as u32) @@ -324,8 +362,10 @@ pub mod pallet { ) -> DispatchResultWithPostInfo { let who = ensure_signed(origin)?; - // votes should not be empty and more than `MAXIMUM_VOTE` in any case. - ensure!(votes.len() <= MAXIMUM_VOTE, Error::::MaximumVotesExceeded); + ensure!( + votes.len() <= T::MaxVotesPerVoter::get() as usize, + Error::::MaximumVotesExceeded + ); ensure!(!votes.is_empty(), Error::::NoVotes); let candidates_count = >::decode_len().unwrap_or(0); @@ -1006,7 +1046,7 @@ impl Pallet { // count](https://en.wikipedia.org/wiki/Borda_count). We weigh everyone's vote for // that new member by a multiplier based on the order of the votes. i.e. the // first person a voter votes for gets a 16x multiplier, the next person gets a - // 15x multiplier, an so on... (assuming `MAXIMUM_VOTE` = 16) + // 15x multiplier, an so on... (assuming `T::MaxVotesPerVoter` = 16) let mut prime_votes = new_members_sorted_by_id .iter() .map(|c| (&c.0, BalanceOf::::zero())) @@ -1014,7 +1054,7 @@ impl Pallet { for (_, stake, votes) in voters_and_stakes.into_iter() { for (vote_multiplier, who) in votes.iter().enumerate().map(|(vote_position, who)| { - ((MAXIMUM_VOTE - vote_position) as u32, who) + ((T::MaxVotesPerVoter::get() as usize - vote_position) as u32, who) }) { if let Ok(i) = prime_votes.binary_search_by_key(&who, |k| k.0) { prime_votes[i].1 = prime_votes[i] @@ -1173,16 +1213,9 @@ mod tests { }; use substrate_test_utils::assert_eq_uvec; - parameter_types! { - pub BlockWeights: frame_system::limits::BlockWeights = - frame_system::limits::BlockWeights::simple_max( - frame_support::weights::Weight::from_ref_time(1024).set_proof_size(u64::MAX), - ); - } - impl frame_system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; - type BlockWeights = BlockWeights; + type BlockWeights = (); type BlockLength = (); type DbWeight = (); type RuntimeOrigin = RuntimeOrigin; @@ -1297,6 +1330,7 @@ mod tests { type KickedMember = (); type WeightInfo = (); type MaxVoters = PhragmenMaxVoters; + type MaxVotesPerVoter = ConstU32<16>; type MaxCandidates = PhragmenMaxCandidates; } diff --git a/frame/elections-phragmen/src/weights.rs b/frame/elections-phragmen/src/weights.rs index dc5d937e33eaf..a13dadf210ec0 100644 --- a/frame/elections-phragmen/src/weights.rs +++ b/frame/elections-phragmen/src/weights.rs @@ -18,25 +18,26 @@ //! Autogenerated weights for pallet_elections_phragmen //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-01-24, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-02-03, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `runner-b3zmxxc-project-145-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// ./target/production/substrate +// target/production/substrate // benchmark // pallet -// --chain=dev // --steps=50 // --repeat=20 -// --pallet=pallet_elections_phragmen // --extrinsic=* // --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=./frame/elections-phragmen/src/weights.rs +// --json-file=/builds/parity/mirrors/substrate/.git/.artifacts/bench.json +// --pallet=pallet_elections_phragmen +// --chain=dev // --header=./HEADER-APACHE2 +// --output=./frame/elections-phragmen/src/weights.rs // --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] @@ -80,10 +81,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `499 + v * (80 ±0)` // Estimated: `9726 + v * (320 ±0)` - // Minimum execution time: 25_407 nanoseconds. - Weight::from_parts(26_035_742, 9726) - // Standard Error: 2_162 - .saturating_add(Weight::from_ref_time(120_321).saturating_mul(v.into())) + // Minimum execution time: 27_362 nanoseconds. + Weight::from_parts(28_497_963, 9726) + // Standard Error: 3_968 + .saturating_add(Weight::from_ref_time(176_840).saturating_mul(v.into())) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) .saturating_add(Weight::from_proof_size(320).saturating_mul(v.into())) @@ -103,10 +104,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `467 + v * (80 ±0)` // Estimated: `9598 + v * (320 ±0)` - // Minimum execution time: 34_477 nanoseconds. - Weight::from_parts(35_197_694, 9598) - // Standard Error: 2_089 - .saturating_add(Weight::from_ref_time(116_792).saturating_mul(v.into())) + // Minimum execution time: 37_120 nanoseconds. + Weight::from_parts(38_455_302, 9598) + // Standard Error: 5_478 + .saturating_add(Weight::from_ref_time(219_678).saturating_mul(v.into())) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) .saturating_add(Weight::from_proof_size(320).saturating_mul(v.into())) @@ -126,10 +127,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `499 + v * (80 ±0)` // Estimated: `9726 + v * (320 ±0)` - // Minimum execution time: 34_573 nanoseconds. - Weight::from_parts(35_254_508, 9726) - // Standard Error: 2_076 - .saturating_add(Weight::from_ref_time(110_656).saturating_mul(v.into())) + // Minimum execution time: 36_928 nanoseconds. + Weight::from_parts(38_334_669, 9726) + // Standard Error: 5_271 + .saturating_add(Weight::from_ref_time(232_355).saturating_mul(v.into())) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) .saturating_add(Weight::from_proof_size(320).saturating_mul(v.into())) @@ -142,8 +143,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `989` // Estimated: `7238` - // Minimum execution time: 31_469 nanoseconds. - Weight::from_parts(31_877_000, 7238) + // Minimum execution time: 34_338 nanoseconds. + Weight::from_parts(35_672_000, 7238) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -153,30 +154,30 @@ impl WeightInfo for SubstrateWeight { /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) /// Storage: Elections RunnersUp (r:1 w:0) /// Proof Skipped: Elections RunnersUp (max_values: Some(1), max_size: None, mode: Measured) - /// The range of component `c` is `[1, 1000]`. + /// The range of component `c` is `[1, 64]`. fn submit_candidacy(c: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1687 + c * (48 ±0)` - // Estimated: `6540 + c * (144 ±0)` - // Minimum execution time: 26_969 nanoseconds. - Weight::from_parts(28_584_266, 6540) - // Standard Error: 93 - .saturating_add(Weight::from_ref_time(52_393).saturating_mul(c.into())) + // Measured: `1697 + c * (48 ±0)` + // Estimated: `6576 + c * (144 ±0)` + // Minimum execution time: 31_864 nanoseconds. + Weight::from_parts(33_490_161, 6576) + // Standard Error: 2_643 + .saturating_add(Weight::from_ref_time(158_386).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) .saturating_add(Weight::from_proof_size(144).saturating_mul(c.into())) } /// Storage: Elections Candidates (r:1 w:1) /// Proof Skipped: Elections Candidates (max_values: Some(1), max_size: None, mode: Measured) - /// The range of component `c` is `[1, 1000]`. + /// The range of component `c` is `[1, 64]`. fn renounce_candidacy_candidate(c: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `348 + c * (48 ±0)` - // Estimated: `830 + c * (48 ±0)` - // Minimum execution time: 23_635 nanoseconds. - Weight::from_parts(23_482_193, 830) - // Standard Error: 103 - .saturating_add(Weight::from_ref_time(33_759).saturating_mul(c.into())) + // Measured: `349 + c * (48 ±0)` + // Estimated: `844 + c * (48 ±0)` + // Minimum execution time: 27_292 nanoseconds. + Weight::from_parts(28_364_955, 844) + // Standard Error: 1_335 + .saturating_add(Weight::from_ref_time(78_086).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) .saturating_add(Weight::from_proof_size(48).saturating_mul(c.into())) @@ -195,8 +196,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `2027` // Estimated: `12115` - // Minimum execution time: 39_124 nanoseconds. - Weight::from_parts(39_575_000, 12115) + // Minimum execution time: 45_975 nanoseconds. + Weight::from_parts(47_103_000, 12115) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -206,8 +207,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `975` // Estimated: `1470` - // Minimum execution time: 25_377 nanoseconds. - Weight::from_parts(25_696_000, 1470) + // Minimum execution time: 29_243 nanoseconds. + Weight::from_parts(30_582_000, 1470) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -236,12 +237,12 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `2027` // Estimated: `14718` - // Minimum execution time: 44_919 nanoseconds. - Weight::from_parts(45_548_000, 14718) + // Minimum execution time: 52_527 nanoseconds. + Weight::from_parts(53_538_000, 14718) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } - /// Storage: Elections Voting (r:10001 w:10000) + /// Storage: Elections Voting (r:513 w:512) /// Proof Skipped: Elections Voting (max_values: None, max_size: None, mode: Measured) /// Storage: Elections Members (r:1 w:0) /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) @@ -249,24 +250,24 @@ impl WeightInfo for SubstrateWeight { /// Proof Skipped: Elections RunnersUp (max_values: Some(1), max_size: None, mode: Measured) /// Storage: Elections Candidates (r:1 w:0) /// Proof Skipped: Elections Candidates (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Balances Locks (r:10000 w:10000) + /// Storage: Balances Locks (r:512 w:512) /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: System Account (r:10000 w:10000) + /// Storage: System Account (r:512 w:512) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// The range of component `v` is `[5000, 10000]`. - /// The range of component `d` is `[0, 5000]`. + /// The range of component `v` is `[256, 512]`. + /// The range of component `d` is `[0, 256]`. fn clean_defunct_voters(v: u32, _d: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `36028 + v * (872 ±0)` - // Estimated: `149172 + v * (12340 ±0)` - // Minimum execution time: 297_544_939 nanoseconds. - Weight::from_parts(298_088_024_000, 149172) - // Standard Error: 264_599 - .saturating_add(Weight::from_ref_time(38_142_857).saturating_mul(v.into())) + // Measured: `1115 + v * (875 ±0)` + // Estimated: `8448 + v * (12352 ±0)` + // Minimum execution time: 14_934_185 nanoseconds. + Weight::from_parts(15_014_057_000, 8448) + // Standard Error: 245_588 + .saturating_add(Weight::from_ref_time(35_586_946).saturating_mul(v.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(v.into()))) .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(v.into()))) - .saturating_add(Weight::from_proof_size(12340).saturating_mul(v.into())) + .saturating_add(Weight::from_proof_size(12352).saturating_mul(v.into())) } /// Storage: Elections Candidates (r:1 w:1) /// Proof Skipped: Elections Candidates (max_values: Some(1), max_size: None, mode: Measured) @@ -274,11 +275,11 @@ impl WeightInfo for SubstrateWeight { /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) /// Storage: Elections RunnersUp (r:1 w:1) /// Proof Skipped: Elections RunnersUp (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Elections Voting (r:10001 w:0) + /// Storage: Elections Voting (r:513 w:0) /// Proof Skipped: Elections Voting (max_values: None, max_size: None, mode: Measured) /// Storage: Council Proposals (r:1 w:0) /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: System Account (r:980 w:980) + /// Storage: System Account (r:44 w:44) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// Storage: Elections ElectionRounds (r:1 w:1) /// Proof Skipped: Elections ElectionRounds (max_values: Some(1), max_size: None, mode: Measured) @@ -286,27 +287,27 @@ impl WeightInfo for SubstrateWeight { /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) /// Storage: Council Prime (r:0 w:1) /// Proof Skipped: Council Prime (max_values: Some(1), max_size: None, mode: Measured) - /// The range of component `c` is `[1, 1000]`. - /// The range of component `v` is `[1, 10000]`. - /// The range of component `e` is `[10000, 160000]`. + /// The range of component `c` is `[1, 64]`. + /// The range of component `v` is `[1, 512]`. + /// The range of component `e` is `[512, 8192]`. fn election_phragmen(c: u32, v: u32, e: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `0 + v * (639 ±0) + e * (28 ±0)` - // Estimated: `5350105 + c * (2582 ±0) + v * (5721 ±6) + e * (123 ±0)` - // Minimum execution time: 21_844_965 nanoseconds. - Weight::from_parts(21_979_826_000, 5350105) - // Standard Error: 229_799 - .saturating_add(Weight::from_ref_time(24_976_612).saturating_mul(v.into())) - // Standard Error: 14_747 - .saturating_add(Weight::from_ref_time(1_025_848).saturating_mul(e.into())) - .saturating_add(T::DbWeight::get().reads(280_u64)) + // Measured: `0 + v * (638 ±0) + e * (28 ±0)` + // Estimated: `330033 + v * (5229 ±6) + e * (89 ±0) + c * (2135 ±7)` + // Minimum execution time: 1_273_671 nanoseconds. + Weight::from_parts(1_279_716_000, 330033) + // Standard Error: 543_277 + .saturating_add(Weight::from_ref_time(20_613_753).saturating_mul(v.into())) + // Standard Error: 34_857 + .saturating_add(Weight::from_ref_time(688_354).saturating_mul(e.into())) + .saturating_add(T::DbWeight::get().reads(21_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(c.into()))) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(v.into()))) .saturating_add(T::DbWeight::get().writes(6_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(c.into()))) - .saturating_add(Weight::from_proof_size(2582).saturating_mul(c.into())) - .saturating_add(Weight::from_proof_size(5721).saturating_mul(v.into())) - .saturating_add(Weight::from_proof_size(123).saturating_mul(e.into())) + .saturating_add(Weight::from_proof_size(5229).saturating_mul(v.into())) + .saturating_add(Weight::from_proof_size(89).saturating_mul(e.into())) + .saturating_add(Weight::from_proof_size(2135).saturating_mul(c.into())) } } @@ -327,10 +328,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `499 + v * (80 ±0)` // Estimated: `9726 + v * (320 ±0)` - // Minimum execution time: 25_407 nanoseconds. - Weight::from_parts(26_035_742, 9726) - // Standard Error: 2_162 - .saturating_add(Weight::from_ref_time(120_321).saturating_mul(v.into())) + // Minimum execution time: 27_362 nanoseconds. + Weight::from_parts(28_497_963, 9726) + // Standard Error: 3_968 + .saturating_add(Weight::from_ref_time(176_840).saturating_mul(v.into())) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) .saturating_add(Weight::from_proof_size(320).saturating_mul(v.into())) @@ -350,10 +351,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `467 + v * (80 ±0)` // Estimated: `9598 + v * (320 ±0)` - // Minimum execution time: 34_477 nanoseconds. - Weight::from_parts(35_197_694, 9598) - // Standard Error: 2_089 - .saturating_add(Weight::from_ref_time(116_792).saturating_mul(v.into())) + // Minimum execution time: 37_120 nanoseconds. + Weight::from_parts(38_455_302, 9598) + // Standard Error: 5_478 + .saturating_add(Weight::from_ref_time(219_678).saturating_mul(v.into())) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) .saturating_add(Weight::from_proof_size(320).saturating_mul(v.into())) @@ -373,10 +374,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `499 + v * (80 ±0)` // Estimated: `9726 + v * (320 ±0)` - // Minimum execution time: 34_573 nanoseconds. - Weight::from_parts(35_254_508, 9726) - // Standard Error: 2_076 - .saturating_add(Weight::from_ref_time(110_656).saturating_mul(v.into())) + // Minimum execution time: 36_928 nanoseconds. + Weight::from_parts(38_334_669, 9726) + // Standard Error: 5_271 + .saturating_add(Weight::from_ref_time(232_355).saturating_mul(v.into())) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) .saturating_add(Weight::from_proof_size(320).saturating_mul(v.into())) @@ -389,8 +390,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `989` // Estimated: `7238` - // Minimum execution time: 31_469 nanoseconds. - Weight::from_parts(31_877_000, 7238) + // Minimum execution time: 34_338 nanoseconds. + Weight::from_parts(35_672_000, 7238) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -400,30 +401,30 @@ impl WeightInfo for () { /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) /// Storage: Elections RunnersUp (r:1 w:0) /// Proof Skipped: Elections RunnersUp (max_values: Some(1), max_size: None, mode: Measured) - /// The range of component `c` is `[1, 1000]`. + /// The range of component `c` is `[1, 64]`. fn submit_candidacy(c: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1687 + c * (48 ±0)` - // Estimated: `6540 + c * (144 ±0)` - // Minimum execution time: 26_969 nanoseconds. - Weight::from_parts(28_584_266, 6540) - // Standard Error: 93 - .saturating_add(Weight::from_ref_time(52_393).saturating_mul(c.into())) + // Measured: `1697 + c * (48 ±0)` + // Estimated: `6576 + c * (144 ±0)` + // Minimum execution time: 31_864 nanoseconds. + Weight::from_parts(33_490_161, 6576) + // Standard Error: 2_643 + .saturating_add(Weight::from_ref_time(158_386).saturating_mul(c.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) .saturating_add(Weight::from_proof_size(144).saturating_mul(c.into())) } /// Storage: Elections Candidates (r:1 w:1) /// Proof Skipped: Elections Candidates (max_values: Some(1), max_size: None, mode: Measured) - /// The range of component `c` is `[1, 1000]`. + /// The range of component `c` is `[1, 64]`. fn renounce_candidacy_candidate(c: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `348 + c * (48 ±0)` - // Estimated: `830 + c * (48 ±0)` - // Minimum execution time: 23_635 nanoseconds. - Weight::from_parts(23_482_193, 830) - // Standard Error: 103 - .saturating_add(Weight::from_ref_time(33_759).saturating_mul(c.into())) + // Measured: `349 + c * (48 ±0)` + // Estimated: `844 + c * (48 ±0)` + // Minimum execution time: 27_292 nanoseconds. + Weight::from_parts(28_364_955, 844) + // Standard Error: 1_335 + .saturating_add(Weight::from_ref_time(78_086).saturating_mul(c.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) .saturating_add(Weight::from_proof_size(48).saturating_mul(c.into())) @@ -442,8 +443,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `2027` // Estimated: `12115` - // Minimum execution time: 39_124 nanoseconds. - Weight::from_parts(39_575_000, 12115) + // Minimum execution time: 45_975 nanoseconds. + Weight::from_parts(47_103_000, 12115) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -453,8 +454,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `975` // Estimated: `1470` - // Minimum execution time: 25_377 nanoseconds. - Weight::from_parts(25_696_000, 1470) + // Minimum execution time: 29_243 nanoseconds. + Weight::from_parts(30_582_000, 1470) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -483,12 +484,12 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `2027` // Estimated: `14718` - // Minimum execution time: 44_919 nanoseconds. - Weight::from_parts(45_548_000, 14718) + // Minimum execution time: 52_527 nanoseconds. + Weight::from_parts(53_538_000, 14718) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } - /// Storage: Elections Voting (r:10001 w:10000) + /// Storage: Elections Voting (r:513 w:512) /// Proof Skipped: Elections Voting (max_values: None, max_size: None, mode: Measured) /// Storage: Elections Members (r:1 w:0) /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) @@ -496,24 +497,24 @@ impl WeightInfo for () { /// Proof Skipped: Elections RunnersUp (max_values: Some(1), max_size: None, mode: Measured) /// Storage: Elections Candidates (r:1 w:0) /// Proof Skipped: Elections Candidates (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Balances Locks (r:10000 w:10000) + /// Storage: Balances Locks (r:512 w:512) /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: System Account (r:10000 w:10000) + /// Storage: System Account (r:512 w:512) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// The range of component `v` is `[5000, 10000]`. - /// The range of component `d` is `[0, 5000]`. + /// The range of component `v` is `[256, 512]`. + /// The range of component `d` is `[0, 256]`. fn clean_defunct_voters(v: u32, _d: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `36028 + v * (872 ±0)` - // Estimated: `149172 + v * (12340 ±0)` - // Minimum execution time: 297_544_939 nanoseconds. - Weight::from_parts(298_088_024_000, 149172) - // Standard Error: 264_599 - .saturating_add(Weight::from_ref_time(38_142_857).saturating_mul(v.into())) + // Measured: `1115 + v * (875 ±0)` + // Estimated: `8448 + v * (12352 ±0)` + // Minimum execution time: 14_934_185 nanoseconds. + Weight::from_parts(15_014_057_000, 8448) + // Standard Error: 245_588 + .saturating_add(Weight::from_ref_time(35_586_946).saturating_mul(v.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().reads((3_u64).saturating_mul(v.into()))) .saturating_add(RocksDbWeight::get().writes((3_u64).saturating_mul(v.into()))) - .saturating_add(Weight::from_proof_size(12340).saturating_mul(v.into())) + .saturating_add(Weight::from_proof_size(12352).saturating_mul(v.into())) } /// Storage: Elections Candidates (r:1 w:1) /// Proof Skipped: Elections Candidates (max_values: Some(1), max_size: None, mode: Measured) @@ -521,11 +522,11 @@ impl WeightInfo for () { /// Proof Skipped: Elections Members (max_values: Some(1), max_size: None, mode: Measured) /// Storage: Elections RunnersUp (r:1 w:1) /// Proof Skipped: Elections RunnersUp (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Elections Voting (r:10001 w:0) + /// Storage: Elections Voting (r:513 w:0) /// Proof Skipped: Elections Voting (max_values: None, max_size: None, mode: Measured) /// Storage: Council Proposals (r:1 w:0) /// Proof Skipped: Council Proposals (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: System Account (r:980 w:980) + /// Storage: System Account (r:44 w:44) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// Storage: Elections ElectionRounds (r:1 w:1) /// Proof Skipped: Elections ElectionRounds (max_values: Some(1), max_size: None, mode: Measured) @@ -533,26 +534,26 @@ impl WeightInfo for () { /// Proof Skipped: Council Members (max_values: Some(1), max_size: None, mode: Measured) /// Storage: Council Prime (r:0 w:1) /// Proof Skipped: Council Prime (max_values: Some(1), max_size: None, mode: Measured) - /// The range of component `c` is `[1, 1000]`. - /// The range of component `v` is `[1, 10000]`. - /// The range of component `e` is `[10000, 160000]`. + /// The range of component `c` is `[1, 64]`. + /// The range of component `v` is `[1, 512]`. + /// The range of component `e` is `[512, 8192]`. fn election_phragmen(c: u32, v: u32, e: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `0 + v * (639 ±0) + e * (28 ±0)` - // Estimated: `5350105 + c * (2582 ±0) + v * (5721 ±6) + e * (123 ±0)` - // Minimum execution time: 21_844_965 nanoseconds. - Weight::from_parts(21_979_826_000, 5350105) - // Standard Error: 229_799 - .saturating_add(Weight::from_ref_time(24_976_612).saturating_mul(v.into())) - // Standard Error: 14_747 - .saturating_add(Weight::from_ref_time(1_025_848).saturating_mul(e.into())) - .saturating_add(RocksDbWeight::get().reads(280_u64)) + // Measured: `0 + v * (638 ±0) + e * (28 ±0)` + // Estimated: `330033 + v * (5229 ±6) + e * (89 ±0) + c * (2135 ±7)` + // Minimum execution time: 1_273_671 nanoseconds. + Weight::from_parts(1_279_716_000, 330033) + // Standard Error: 543_277 + .saturating_add(Weight::from_ref_time(20_613_753).saturating_mul(v.into())) + // Standard Error: 34_857 + .saturating_add(Weight::from_ref_time(688_354).saturating_mul(e.into())) + .saturating_add(RocksDbWeight::get().reads(21_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(c.into()))) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(v.into()))) .saturating_add(RocksDbWeight::get().writes(6_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(c.into()))) - .saturating_add(Weight::from_proof_size(2582).saturating_mul(c.into())) - .saturating_add(Weight::from_proof_size(5721).saturating_mul(v.into())) - .saturating_add(Weight::from_proof_size(123).saturating_mul(e.into())) + .saturating_add(Weight::from_proof_size(5229).saturating_mul(v.into())) + .saturating_add(Weight::from_proof_size(89).saturating_mul(e.into())) + .saturating_add(Weight::from_proof_size(2135).saturating_mul(c.into())) } } diff --git a/frame/support/procedural/src/construct_runtime/mod.rs b/frame/support/procedural/src/construct_runtime/mod.rs index 9e22037a6782e..18b66ddff5ffa 100644 --- a/frame/support/procedural/src/construct_runtime/mod.rs +++ b/frame/support/procedural/src/construct_runtime/mod.rs @@ -579,6 +579,7 @@ fn decl_integrity_test(scrate: &TokenStream2) -> TokenStream2 { #[test] pub fn runtime_integrity_tests() { + #scrate::sp_tracing::try_init_simple(); ::integrity_test(); } } From 23fb86b379c8bb17d02af7b9cdbfa470099425e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Thei=C3=9Fen?= Date: Wed, 8 Feb 2023 16:40:45 -0300 Subject: [PATCH 115/162] Rework generated API docs (#13178) --- frame/contracts/proc-macro/src/lib.rs | 219 +++++++++++++++----------- frame/contracts/src/wasm/mod.rs | 7 +- 2 files changed, 132 insertions(+), 94 deletions(-) diff --git a/frame/contracts/proc-macro/src/lib.rs b/frame/contracts/proc-macro/src/lib.rs index de7b9b881d305..c5f52f43a7d87 100644 --- a/frame/contracts/proc-macro/src/lib.rs +++ b/frame/contracts/proc-macro/src/lib.rs @@ -25,10 +25,12 @@ extern crate alloc; use alloc::{ + collections::BTreeMap, format, string::{String, ToString}, vec::Vec, }; +use core::cmp::Reverse; use proc_macro::TokenStream; use proc_macro2::{Span, TokenStream as TokenStream2}; use quote::{quote, quote_spanned, ToTokens}; @@ -160,7 +162,7 @@ struct EnvDef { /// Parsed host function definition. struct HostFn { item: syn::ItemFn, - module: String, + version: u8, name: String, returns: HostFnReturn, is_stable: bool, @@ -208,7 +210,7 @@ impl HostFn { let span = item.span(); let mut attrs = item.attrs.clone(); attrs.retain(|a| !a.path.is_ident("doc")); - let mut maybe_module = None; + let mut maybe_version = None; let mut is_stable = true; let mut alias_to = None; let mut not_deprecated = true; @@ -216,12 +218,11 @@ impl HostFn { let ident = attr.path.get_ident().ok_or(err(span, msg))?.to_string(); match ident.as_str() { "version" => { - if maybe_module.is_some() { + if maybe_version.is_some() { return Err(err(span, "#[version] can only be specified once")) } - let ver: u8 = - attr.parse_args::().and_then(|lit| lit.base10_parse())?; - maybe_module = Some(format!("seal{}", ver)); + maybe_version = + Some(attr.parse_args::().and_then(|lit| lit.base10_parse())?); }, "unstable" => { if !is_stable { @@ -341,7 +342,7 @@ impl HostFn { Ok(Self { item, - module: maybe_module.unwrap_or_else(|| "seal0".to_string()), + version: maybe_version.unwrap_or_default(), name, returns, is_stable, @@ -355,6 +356,10 @@ impl HostFn { _ => Err(err(span, &msg)), } } + + fn module(&self) -> String { + format!("seal{}", self.version) + } } impl EnvDef { @@ -409,83 +414,116 @@ fn is_valid_special_arg(idx: usize, arg: &FnArg) -> bool { matches!(*pat.ty, syn::Type::Infer(_)) } -/// Expands documentation for host functions. -fn expand_docs(def: &mut EnvDef) -> TokenStream2 { - let mut modules = def.host_funcs.iter().map(|f| f.module.clone()).collect::>(); - modules.sort(); - modules.dedup(); - - let doc_selector = |a: &syn::Attribute| a.path.is_ident("doc"); - let docs = modules.iter().map(|m| { - let funcs = def.host_funcs.iter_mut().map(|f| { - if *m == f.module { - // Remove auxiliary args: `ctx: _` and `memory: _` - f.item.sig.inputs = f - .item - .sig - .inputs - .iter() - .skip(2) - .map(|p| p.clone()) - .collect::>(); - let func_decl = f.item.sig.to_token_stream(); - let func_doc = if let Some(origin_fn) = &f.alias_to { - let alias_doc = format!( - "This is just an alias function to [`{0}()`][`Self::{0}`] with backwards-compatible prefixed identifier.", - origin_fn, - ); - quote! { #[doc = #alias_doc] } - - } else { - let func_docs = f.item.attrs.iter().filter(|a| doc_selector(a)).map(|d| { - let docs = d.to_token_stream(); - quote! { #docs } - }); - let unstable_notice = if !f.is_stable { - let warning = "\n # Unstable\n\n \ - This function is unstable and it is a subject to change (or removal) in the future.\n \ - Do not deploy a contract using it to a production chain."; - quote! { #[doc = #warning] } - } else { - quote! {} - }; - quote! { - #( #func_docs )* - #unstable_notice - } - }; - quote! { - #func_doc - #func_decl; - } - } else { - quote! {} - } - }); +fn expand_func_doc(func: &HostFn) -> TokenStream2 { + // Remove auxiliary args: `ctx: _` and `memory: _` + let func_decl = { + let mut sig = func.item.sig.clone(); + sig.inputs = sig + .inputs + .iter() + .skip(2) + .map(|p| p.clone()) + .collect::>(); + sig.to_token_stream() + }; + let func_doc = { + let func_docs = if let Some(origin_fn) = &func.alias_to { + let alias_doc = format!( + "This is just an alias function to [`{0}()`][`Self::{0}`] with backwards-compatible prefixed identifier.", + origin_fn, + ); + quote! { #[doc = #alias_doc] } + } else { + let docs = func.item.attrs.iter().filter(|a| a.path.is_ident("doc")).map(|d| { + let docs = d.to_token_stream(); + quote! { #docs } + }); + quote! { #( #docs )* } + }; + let deprecation_notice = if !func.not_deprecated { + let warning = "\n # Deprecated\n\n \ + This function is deprecated and will be removed in future versions.\n \ + No new code or contracts with this API can be deployed."; + quote! { #[doc = #warning] } + } else { + quote! {} + }; + let import_notice = { + let info = format!( + "\n# Wasm Import Statement\n```wat\n(import \"seal{}\" \"{}\" (func ...))\n```", + func.version, func.name, + ); + quote! { #[doc = #info] } + }; + let unstable_notice = if !func.is_stable { + let warning = "\n # Unstable\n\n \ + This function is unstable and it is a subject to change (or removal) in the future.\n \ + Do not deploy a contract using it to a production chain."; + quote! { #[doc = #warning] } + } else { + quote! {} + }; + quote! { + #deprecation_notice + #func_docs + #import_notice + #unstable_notice + } + }; + quote! { + #func_doc + #func_decl; + } +} - let module = Ident::new(m, Span::call_site()); - let module_doc = format!( - "Documentation of the API available to contracts by importing `{}` WASM module.", - module - ); +/// Expands documentation for host functions. +fn expand_docs(def: &EnvDef) -> TokenStream2 { + // Create the `Current` trait with only the newest versions + // we sort so that only the newest versions make it into `docs` + let mut current_docs = BTreeMap::new(); + let mut funcs: Vec<_> = def.host_funcs.iter().filter(|f| f.alias_to.is_none()).collect(); + funcs.sort_unstable_by_key(|func| Reverse(func.version)); + for func in funcs { + if current_docs.contains_key(&func.name) { + continue + } + current_docs.insert(func.name.clone(), expand_func_doc(&func)); + } + let current_docs = current_docs.values(); + // Create the `legacy` module with all functions + // Maps from version to list of functions that have this version + let mut legacy_doc = BTreeMap::>::new(); + for func in def.host_funcs.iter() { + legacy_doc.entry(func.version).or_default().push(expand_func_doc(&func)); + } + let legacy_doc = legacy_doc.into_iter().map(|(version, funcs)| { + let doc = format!("All functions available in the **seal{}** module", version); + let version = Ident::new(&format!("Version{version}"), Span::call_site()); quote! { - #[doc = #module_doc] - pub mod #module { - use crate::wasm::runtime::{TrapReason, ReturnCode}; - /// Every function in this trait represents (at least) one function that can be imported by a contract. - /// - /// The function's identifier is to be set as the name in the import definition. - /// Where it is specifically indicated, an _alias_ function having `seal_`-prefixed identifier and - /// just the same signature and body, is also available (for backwards-compatibility purposes). - pub trait Api { - #( #funcs )* - } + #[doc = #doc] + pub trait #version { + #( #funcs )* } } }); + quote! { - #( #docs )* + /// Contains only the latest version of each function. + /// + /// In reality there are more functions available but they are all obsolete: When a function + /// is updated a new **version** is added and the old versions stays available as-is. + /// We only list the newest version here. Some functions are available under additional + /// names (aliases) for historic reasons which are omitted here. + /// + /// If you want an overview of all the functions available to a contact all you need + /// to look at is this trait. It contains only the latest version of each + /// function and no aliases. If you are writing a contract(language) from scratch + /// this is where you should look at. + pub trait Current { + #( #current_docs )* + } + #( #legacy_doc )* } } @@ -493,25 +531,26 @@ fn expand_docs(def: &mut EnvDef) -> TokenStream2 { /// Should generate source code for: /// - implementations of the host functions to be added to the wasm runtime environment (see /// `expand_impls()`). -fn expand_env(def: &mut EnvDef, docs: bool) -> TokenStream2 { +fn expand_env(def: &EnvDef, docs: bool) -> TokenStream2 { let impls = expand_impls(def); let docs = docs.then_some(expand_docs(def)).unwrap_or(TokenStream2::new()); quote! { pub struct Env; #impls - /// Contains the documentation of the API available to contracts. + /// Documentation of the API (host functions) available to contracts. /// - /// In order to generate this documentation, pass `doc` attribute to the [`#[define_env]`][`macro@define_env`] macro: - /// `#[define_env(doc)]`, and then run `cargo doc`. + /// The `Current` trait might be the most useful doc to look at. The versioned + /// traits only exist for reference: If trying to find out if a specific version of + /// `pallet-contracts` contains a certain function. /// - /// This module is not meant to be used by any code. Rather, it is meant to be consumed by humans through rustdoc. + /// # Note /// - /// Every function described in this module's sub module's traits uses this sub module's identifier - /// as its imported module name. The identifier of the function is the function's imported name. - /// According to the [WASM spec of imports](https://webassembly.github.io/spec/core/text/modules.html#text-import). + /// This module is not meant to be used by any code. Rather, it is meant to be + /// consumed by humans through rustdoc. #[cfg(doc)] pub mod api_doc { + use super::{TrapReason, ReturnCode}; #docs } } @@ -520,7 +559,7 @@ fn expand_env(def: &mut EnvDef, docs: bool) -> TokenStream2 { /// Generates for every host function: /// - real implementation, to register it in the contract execution environment; /// - dummy implementation, to be used as mocks for contract validation step. -fn expand_impls(def: &mut EnvDef) -> TokenStream2 { +fn expand_impls(def: &EnvDef) -> TokenStream2 { let impls = expand_functions(def, true, quote! { crate::wasm::Runtime }); let dummy_impls = expand_functions(def, false, quote! { () }); @@ -553,16 +592,12 @@ fn expand_impls(def: &mut EnvDef) -> TokenStream2 { } } -fn expand_functions( - def: &mut EnvDef, - expand_blocks: bool, - host_state: TokenStream2, -) -> TokenStream2 { +fn expand_functions(def: &EnvDef, expand_blocks: bool, host_state: TokenStream2) -> TokenStream2 { let impls = def.host_funcs.iter().map(|f| { // skip the context and memory argument let params = f.item.sig.inputs.iter().skip(2); let (module, name, body, wasm_output, output) = ( - &f.module, + f.module(), &f.name, &f.item.block, f.returns.to_wasm_sig(), diff --git a/frame/contracts/src/wasm/mod.rs b/frame/contracts/src/wasm/mod.rs index 6b9cefcdd2d96..9bf36b47f0b06 100644 --- a/frame/contracts/src/wasm/mod.rs +++ b/frame/contracts/src/wasm/mod.rs @@ -24,8 +24,13 @@ mod runtime; #[cfg(feature = "runtime-benchmarks")] pub use crate::wasm::code_cache::reinstrument; + #[cfg(doc)] pub use crate::wasm::runtime::api_doc; + +#[cfg(test)] +pub use tests::MockExt; + pub use crate::wasm::{ prepare::TryInstantiate, runtime::{ @@ -45,8 +50,6 @@ use frame_support::dispatch::{DispatchError, DispatchResult}; use sp_core::Get; use sp_runtime::RuntimeDebug; use sp_std::prelude::*; -#[cfg(test)] -pub use tests::MockExt; use wasmi::{ Config as WasmiConfig, Engine, Instance, Linker, Memory, MemoryType, Module, StackLimits, Store, }; From be6a11c3e21cd2544c5725591f5dabe6a4c39844 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Thu, 9 Feb 2023 11:00:55 +0100 Subject: [PATCH 116/162] pallet-scheduler: Ensure we request a preimage (#13340) * pallet-scheduler: Ensure we request a preimage The scheduler was not requesting a preimage. When a preimage is requested, a user can deposit it without paying any fees. * Review changes --- frame/scheduler/src/lib.rs | 23 ++++++++++++++++-- frame/scheduler/src/tests.rs | 23 +++++++++++++----- frame/support/src/traits/preimages.rs | 35 ++++++++++++++++++--------- 3 files changed, 62 insertions(+), 19 deletions(-) diff --git a/frame/scheduler/src/lib.rs b/frame/scheduler/src/lib.rs index afc4fd66e76cb..dfec98d4e443a 100644 --- a/frame/scheduler/src/lib.rs +++ b/frame/scheduler/src/lib.rs @@ -777,6 +777,8 @@ impl Pallet { ) -> Result, DispatchError> { let when = Self::resolve_time(when)?; + let lookup_hash = call.lookup_hash(); + // sanitize maybe_periodic let maybe_periodic = maybe_periodic .filter(|p| p.1 > 1 && !p.0.is_zero()) @@ -790,7 +792,14 @@ impl Pallet { origin, _phantom: PhantomData, }; - Self::place_task(when, task).map_err(|x| x.0) + let res = Self::place_task(when, task).map_err(|x| x.0)?; + + if let Some(hash) = lookup_hash { + // Request the call to be made available. + T::Preimages::request(&hash); + } + + Ok(res) } fn do_cancel( @@ -862,6 +871,8 @@ impl Pallet { let when = Self::resolve_time(when)?; + let lookup_hash = call.lookup_hash(); + // sanitize maybe_periodic let maybe_periodic = maybe_periodic .filter(|p| p.1 > 1 && !p.0.is_zero()) @@ -876,7 +887,14 @@ impl Pallet { origin, _phantom: Default::default(), }; - Self::place_task(when, task).map_err(|x| x.0) + let res = Self::place_task(when, task).map_err(|x| x.0)?; + + if let Some(hash) = lookup_hash { + // Request the call to be made available. + T::Preimages::request(&hash); + } + + Ok(res) } fn do_cancel_named(origin: Option, id: TaskName) -> DispatchResult { @@ -1027,6 +1045,7 @@ impl Pallet { } else { Agenda::::remove(when); } + postponed == 0 } diff --git a/frame/scheduler/src/tests.rs b/frame/scheduler/src/tests.rs index e5467fc8db55f..a261c6718616d 100644 --- a/frame/scheduler/src/tests.rs +++ b/frame/scheduler/src/tests.rs @@ -58,9 +58,10 @@ fn scheduling_with_preimages_works() { RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(10) }); let hash = ::Hashing::hash_of(&call); let len = call.using_encoded(|x| x.len()) as u32; - let hashed = Preimage::pick(hash, len); - assert_ok!(Preimage::note_preimage(RuntimeOrigin::signed(0), call.encode())); + // Important to use here `Bounded::Lookup` to ensure that we request the hash. + let hashed = Bounded::Lookup { hash, len }; assert_ok!(Scheduler::do_schedule(DispatchTime::At(4), None, 127, root(), hashed)); + assert_ok!(Preimage::note_preimage(RuntimeOrigin::signed(0), call.encode())); assert!(Preimage::is_requested(&hash)); run_to_block(3); assert!(logger::log().is_empty()); @@ -479,8 +480,10 @@ fn scheduler_handles_periodic_unavailable_preimage() { let call = RuntimeCall::Logger(LoggerCall::log { i: 42, weight: (max_weight / 3) * 2 }); let hash = ::Hashing::hash_of(&call); let len = call.using_encoded(|x| x.len()) as u32; - let bound = Preimage::pick(hash, len); - assert_ok!(Preimage::note(call.encode().into())); + // Important to use here `Bounded::Lookup` to ensure that we request the hash. + let bound = Bounded::Lookup { hash, len }; + // The preimage isn't requested yet. + assert!(!Preimage::is_requested(&hash)); assert_ok!(Scheduler::do_schedule( DispatchTime::At(4), @@ -489,11 +492,18 @@ fn scheduler_handles_periodic_unavailable_preimage() { root(), bound.clone(), )); + + // The preimage is requested. + assert!(Preimage::is_requested(&hash)); + + // Note the preimage. + assert_ok!(Preimage::note_preimage(RuntimeOrigin::signed(1), call.encode())); + // Executes 1 times till block 4. run_to_block(4); assert_eq!(logger::log().len(), 1); - // Unnote the preimage. + // Unnote the preimage Preimage::unnote(&hash); // Does not ever execute again. @@ -1129,7 +1139,8 @@ fn postponed_named_task_cannot_be_rescheduled() { RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(1000) }); let hash = ::Hashing::hash_of(&call); let len = call.using_encoded(|x| x.len()) as u32; - let hashed = Preimage::pick(hash, len); + // Important to use here `Bounded::Lookup` to ensure that we request the hash. + let hashed = Bounded::Lookup { hash, len }; let name: [u8; 32] = hash.as_ref().try_into().unwrap(); let address = Scheduler::do_schedule_named( diff --git a/frame/support/src/traits/preimages.rs b/frame/support/src/traits/preimages.rs index 594532ba96903..ce3537c792c08 100644 --- a/frame/support/src/traits/preimages.rs +++ b/frame/support/src/traits/preimages.rs @@ -26,6 +26,9 @@ use sp_std::borrow::Cow; pub type Hash = H256; pub type BoundedInline = crate::BoundedVec>; +/// The maximum we expect a single legacy hash lookup to be. +const MAX_LEGACY_LEN: u32 = 1_000_000; + #[derive( Encode, Decode, MaxEncodedLen, Clone, Eq, PartialEq, scale_info::TypeInfo, RuntimeDebug, )] @@ -67,20 +70,25 @@ impl Bounded { /// Returns the hash of the preimage. /// /// The hash is re-calculated every time if the preimage is inlined. - pub fn hash(&self) -> H256 { + pub fn hash(&self) -> Hash { use Bounded::*; match self { - Legacy { hash, .. } => *hash, + Lookup { hash, .. } | Legacy { hash, .. } => *hash, Inline(x) => blake2_256(x.as_ref()).into(), - Lookup { hash, .. } => *hash, } } -} -// The maximum we expect a single legacy hash lookup to be. -const MAX_LEGACY_LEN: u32 = 1_000_000; + /// Returns the hash to lookup the preimage. + /// + /// If this is a `Bounded::Inline`, `None` is returned as no lookup is required. + pub fn lookup_hash(&self) -> Option { + use Bounded::*; + match self { + Lookup { hash, .. } | Legacy { hash, .. } => Some(*hash), + Inline(_) => None, + } + } -impl Bounded { /// Returns the length of the preimage or `None` if the length is unknown. pub fn len(&self) -> Option { match self { @@ -168,8 +176,11 @@ pub trait QueryPreimage { } } - /// Create a `Bounded` instance based on the `hash` and `len` of the encoded value. This may not - /// be `peek`-able or `realize`-able. + /// Create a `Bounded` instance based on the `hash` and `len` of the encoded value. + /// + /// It also directly requests the given `hash` using [`Self::request`]. + /// + /// This may not be `peek`-able or `realize`-able. fn pick(hash: Hash, len: u32) -> Bounded { Self::request(&hash); Bounded::Lookup { hash, len } @@ -228,10 +239,12 @@ pub trait StorePreimage: QueryPreimage { Self::unrequest(hash) } - /// Convert an otherwise unbounded or large value into a type ready for placing in storage. The - /// result is a type whose `MaxEncodedLen` is 131 bytes. + /// Convert an otherwise unbounded or large value into a type ready for placing in storage. + /// + /// The result is a type whose `MaxEncodedLen` is 131 bytes. /// /// NOTE: Once this API is used, you should use either `drop` or `realize`. + /// The value is also noted using [`Self::note`]. fn bound(t: T) -> Result, DispatchError> { let data = t.encode(); let len = data.len() as u32; From 4b23fdb3b9e583f3d2693841dd0d4275803975d2 Mon Sep 17 00:00:00 2001 From: Roman Useinov Date: Thu, 9 Feb 2023 12:47:39 +0100 Subject: [PATCH 117/162] [Fix] Try-state feature-gated for BagsList (#13296) * [Fix] Try-state feature-gated for BagsList * fix comment * fix try_state remote-tests * feature-gate try-state remote test for bags-list * remove try-state from a migration * more SortedListProvider fixes * more fixes * more fixes to allow do_try_state usage in other crates * do-try-state for fuzz * more fixes * more fixes * remove feature-flag * do-try-state * fix review comments * Update frame/bags-list/src/mock.rs Co-authored-by: Anton --------- Co-authored-by: parity-processbot <> Co-authored-by: Anton --- frame/bags-list/Cargo.toml | 2 +- frame/bags-list/fuzzer/src/main.rs | 2 +- frame/bags-list/remote-tests/Cargo.toml | 2 +- frame/bags-list/remote-tests/src/try_state.rs | 5 ++-- frame/bags-list/src/lib.rs | 10 +++++++- frame/bags-list/src/list/mod.rs | 17 +++++++------ frame/bags-list/src/list/tests.rs | 25 ++++++++++--------- frame/bags-list/src/mock.rs | 2 +- frame/election-provider-support/Cargo.toml | 1 + frame/election-provider-support/src/lib.rs | 3 ++- frame/staking/Cargo.toml | 2 +- frame/staking/src/migrations.rs | 1 - frame/staking/src/pallet/impls.rs | 4 +++ 13 files changed, 46 insertions(+), 30 deletions(-) diff --git a/frame/bags-list/Cargo.toml b/frame/bags-list/Cargo.toml index e3a4965f6c086..379698b1d39e1 100644 --- a/frame/bags-list/Cargo.toml +++ b/frame/bags-list/Cargo.toml @@ -75,4 +75,4 @@ fuzz = [ "sp-tracing", "frame-election-provider-support/fuzz", ] -try-runtime = [ "frame-support/try-runtime" ] +try-runtime = [ "frame-support/try-runtime", "frame-election-provider-support/try-runtime" ] diff --git a/frame/bags-list/fuzzer/src/main.rs b/frame/bags-list/fuzzer/src/main.rs index 9f7ca464cc2b8..c78e2a13076d5 100644 --- a/frame/bags-list/fuzzer/src/main.rs +++ b/frame/bags-list/fuzzer/src/main.rs @@ -88,7 +88,7 @@ fn main() { }, } - assert!(BagsList::try_state().is_ok()); + assert!(BagsList::do_try_state().is_ok()); }) }); } diff --git a/frame/bags-list/remote-tests/Cargo.toml b/frame/bags-list/remote-tests/Cargo.toml index 9fb6d0154b302..6e951b43a4aeb 100644 --- a/frame/bags-list/remote-tests/Cargo.toml +++ b/frame/bags-list/remote-tests/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] # frame pallet-staking = { path = "../../staking", version = "4.0.0-dev" } -pallet-bags-list = { path = "../../bags-list", version = "4.0.0-dev" } +pallet-bags-list = { path = "../../bags-list", version = "4.0.0-dev", features = ["fuzz"] } frame-election-provider-support = { path = "../../election-provider-support", version = "4.0.0-dev" } frame-system = { path = "../../system", version = "4.0.0-dev" } frame-support = { path = "../../support", version = "4.0.0-dev" } diff --git a/frame/bags-list/remote-tests/src/try_state.rs b/frame/bags-list/remote-tests/src/try_state.rs index 514c80d72ab67..9ed877a43afe1 100644 --- a/frame/bags-list/remote-tests/src/try_state.rs +++ b/frame/bags-list/remote-tests/src/try_state.rs @@ -16,7 +16,6 @@ //! Test to execute the sanity-check of the voter bag. -use frame_election_provider_support::SortedListProvider; use frame_support::{ storage::generator::StorageMap, traits::{Get, PalletInfoAccess}, @@ -51,7 +50,9 @@ pub async fn execute( ext.execute_with(|| { sp_core::crypto::set_default_ss58_version(Runtime::SS58Prefix::get().try_into().unwrap()); - pallet_bags_list::Pallet::::try_state().unwrap(); + + pallet_bags_list::Pallet::::do_try_state().unwrap(); + log::info!(target: crate::LOG_TARGET, "executed bags-list sanity check with no errors."); crate::display_and_check_bags::(currency_unit, currency_name); diff --git a/frame/bags-list/src/lib.rs b/frame/bags-list/src/lib.rs index 14f8a613eb798..f04c685ae386c 100644 --- a/frame/bags-list/src/lib.rs +++ b/frame/bags-list/src/lib.rs @@ -274,6 +274,13 @@ pub mod pallet { } } +#[cfg(any(test, feature = "try-runtime", feature = "fuzz"))] +impl, I: 'static> Pallet { + pub fn do_try_state() -> Result<(), &'static str> { + List::::do_try_state() + } +} + impl, I: 'static> Pallet { /// Move an account from one bag to another, depositing an event on success. /// @@ -348,8 +355,9 @@ impl, I: 'static> SortedListProvider for Pallet List::::unsafe_regenerate(all, score_of) } + #[cfg(feature = "try-runtime")] fn try_state() -> Result<(), &'static str> { - List::::try_state() + Self::do_try_state() } fn unsafe_clear() { diff --git a/frame/bags-list/src/list/mod.rs b/frame/bags-list/src/list/mod.rs index 272526ad1a636..4082a5324091b 100644 --- a/frame/bags-list/src/list/mod.rs +++ b/frame/bags-list/src/list/mod.rs @@ -220,9 +220,6 @@ impl, I: 'static> List { crate::ListBags::::remove(removed_bag); } - #[cfg(feature = "std")] - debug_assert_eq!(Self::try_state(), Ok(())); - num_affected } @@ -514,7 +511,8 @@ impl, I: 'static> List { /// * length of this list is in sync with `ListNodes::count()`, /// * and sanity-checks all bags and nodes. This will cascade down all the checks and makes sure /// all bags and nodes are checked per *any* update to `List`. - pub(crate) fn try_state() -> Result<(), &'static str> { + #[cfg(any(test, feature = "try-runtime", feature = "fuzz"))] + pub(crate) fn do_try_state() -> Result<(), &'static str> { let mut seen_in_list = BTreeSet::new(); ensure!( Self::iter().map(|node| node.id).all(|id| seen_in_list.insert(id)), @@ -542,7 +540,7 @@ impl, I: 'static> List { thresholds.into_iter().filter_map(|t| Bag::::get(t)) }; - let _ = active_bags.clone().try_for_each(|b| b.try_state())?; + let _ = active_bags.clone().try_for_each(|b| b.do_try_state())?; let nodes_in_bags_count = active_bags.clone().fold(0u32, |acc, cur| acc + cur.iter().count() as u32); @@ -553,7 +551,7 @@ impl, I: 'static> List { // check that all nodes are sane. We check the `ListNodes` storage item directly in case we // have some "stale" nodes that are not in a bag. for (_id, node) in crate::ListNodes::::iter() { - node.try_state()? + node.do_try_state()? } Ok(()) @@ -751,7 +749,8 @@ impl, I: 'static> Bag { /// * Ensures head has no prev. /// * Ensures tail has no next. /// * Ensures there are no loops, traversal from head to tail is correct. - fn try_state(&self) -> Result<(), &'static str> { + #[cfg(any(test, feature = "try-runtime", feature = "fuzz"))] + fn do_try_state(&self) -> Result<(), &'static str> { frame_support::ensure!( self.head() .map(|head| head.prev().is_none()) @@ -790,6 +789,7 @@ impl, I: 'static> Bag { } /// Check if the bag contains a node with `id`. + #[cfg(any(test, feature = "try-runtime", feature = "fuzz"))] fn contains(&self, id: &T::AccountId) -> bool { self.iter().any(|n| n.id() == id) } @@ -894,7 +894,8 @@ impl, I: 'static> Node { self.bag_upper } - fn try_state(&self) -> Result<(), &'static str> { + #[cfg(any(test, feature = "try-runtime", feature = "fuzz"))] + fn do_try_state(&self) -> Result<(), &'static str> { let expected_bag = Bag::::get(self.bag_upper).ok_or("bag not found for node")?; let id = self.id(); diff --git a/frame/bags-list/src/list/tests.rs b/frame/bags-list/src/list/tests.rs index 966ea1a74c71c..3c4aa7c86634d 100644 --- a/frame/bags-list/src/list/tests.rs +++ b/frame/bags-list/src/list/tests.rs @@ -137,6 +137,7 @@ fn migrate_works() { BagThresholds::set(NEW_THRESHOLDS); // and we call List::::migrate(old_thresholds); + assert_eq!(List::::do_try_state(), Ok(())); // then assert_eq!( @@ -352,13 +353,13 @@ mod list { #[test] fn try_state_works() { ExtBuilder::default().build_and_execute_no_post_check(|| { - assert_ok!(List::::try_state()); + assert_ok!(List::::do_try_state()); }); // make sure there are no duplicates. ExtBuilder::default().build_and_execute_no_post_check(|| { Bag::::get(10).unwrap().insert_unchecked(2, 10); - assert_eq!(List::::try_state(), Err("duplicate identified")); + assert_eq!(List::::do_try_state(), Err("duplicate identified")); }); // ensure count is in sync with `ListNodes::count()`. @@ -372,7 +373,7 @@ mod list { CounterForListNodes::::mutate(|counter| *counter += 1); assert_eq!(crate::ListNodes::::count(), 5); - assert_eq!(List::::try_state(), Err("iter_count != stored_count")); + assert_eq!(List::::do_try_state(), Err("iter_count != stored_count")); }); } @@ -804,7 +805,7 @@ mod bags { // then assert_eq!(bag_as_ids(&bag_1000), vec![2, 3, 13, 14]); - assert_ok!(bag_1000.try_state()); + assert_ok!(bag_1000.do_try_state()); // and the node isn't mutated when its removed assert_eq!(node_4, node_4_pre_remove); @@ -814,7 +815,7 @@ mod bags { // then assert_eq!(bag_as_ids(&bag_1000), vec![3, 13, 14]); - assert_ok!(bag_1000.try_state()); + assert_ok!(bag_1000.do_try_state()); // when removing a tail that is not pointing at the head let node_14 = Node::::get(&14).unwrap(); @@ -822,7 +823,7 @@ mod bags { // then assert_eq!(bag_as_ids(&bag_1000), vec![3, 13]); - assert_ok!(bag_1000.try_state()); + assert_ok!(bag_1000.do_try_state()); // when removing a tail that is pointing at the head let node_13 = Node::::get(&13).unwrap(); @@ -830,7 +831,7 @@ mod bags { // then assert_eq!(bag_as_ids(&bag_1000), vec![3]); - assert_ok!(bag_1000.try_state()); + assert_ok!(bag_1000.do_try_state()); // when removing a node that is both the head & tail let node_3 = Node::::get(&3).unwrap(); @@ -846,7 +847,7 @@ mod bags { // then assert_eq!(bag_as_ids(&bag_10), vec![1, 12]); - assert_ok!(bag_10.try_state()); + assert_ok!(bag_10.do_try_state()); // when removing a head that is pointing at the tail let node_1 = Node::::get(&1).unwrap(); @@ -854,7 +855,7 @@ mod bags { // then assert_eq!(bag_as_ids(&bag_10), vec![12]); - assert_ok!(bag_10.try_state()); + assert_ok!(bag_10.do_try_state()); // and since we updated the bag's head/tail, we need to write this storage so we // can correctly `get` it again in later checks bag_10.put(); @@ -865,7 +866,7 @@ mod bags { // then assert_eq!(bag_as_ids(&bag_2000), vec![15, 17, 18, 19]); - assert_ok!(bag_2000.try_state()); + assert_ok!(bag_2000.do_try_state()); // when removing a node that is pointing at tail, but not head let node_18 = Node::::get(&18).unwrap(); @@ -873,7 +874,7 @@ mod bags { // then assert_eq!(bag_as_ids(&bag_2000), vec![15, 17, 19]); - assert_ok!(bag_2000.try_state()); + assert_ok!(bag_2000.do_try_state()); // finally, when reading from storage, the state of all bags is as expected assert_eq!( @@ -905,7 +906,7 @@ mod bags { // .. and the bag it was removed from let bag_1000 = Bag::::get(1_000).unwrap(); // is sane - assert_ok!(bag_1000.try_state()); + assert_ok!(bag_1000.do_try_state()); // and has the correct head and tail. assert_eq!(bag_1000.head, Some(3)); assert_eq!(bag_1000.tail, Some(4)); diff --git a/frame/bags-list/src/mock.rs b/frame/bags-list/src/mock.rs index 8cc96a988e72a..32f6bb09e4772 100644 --- a/frame/bags-list/src/mock.rs +++ b/frame/bags-list/src/mock.rs @@ -148,7 +148,7 @@ impl ExtBuilder { pub fn build_and_execute(self, test: impl FnOnce() -> ()) { self.build().execute_with(|| { test(); - List::::try_state().expect("Try-state post condition failed") + List::::do_try_state().expect("do_try_state post condition failed") }) } diff --git a/frame/election-provider-support/Cargo.toml b/frame/election-provider-support/Cargo.toml index c7f47e721d1aa..114caee793f1a 100644 --- a/frame/election-provider-support/Cargo.toml +++ b/frame/election-provider-support/Cargo.toml @@ -43,3 +43,4 @@ std = [ "sp-std/std", ] runtime-benchmarks = [] +try-runtime = [] diff --git a/frame/election-provider-support/src/lib.rs b/frame/election-provider-support/src/lib.rs index 9d5d6c018e5e1..9e60eb3be1a6f 100644 --- a/frame/election-provider-support/src/lib.rs +++ b/frame/election-provider-support/src/lib.rs @@ -562,7 +562,8 @@ pub trait SortedListProvider { /// unbounded amount of storage accesses. fn unsafe_clear(); - /// Check internal state of list. Only meant for debugging. + /// Check internal state of the list. Only meant for debugging. + #[cfg(feature = "try-runtime")] fn try_state() -> Result<(), &'static str>; /// If `who` changes by the returned amount they are guaranteed to have a worst case change diff --git a/frame/staking/Cargo.toml b/frame/staking/Cargo.toml index 3d5cf1161e8e5..79c0bb5c2a32d 100644 --- a/frame/staking/Cargo.toml +++ b/frame/staking/Cargo.toml @@ -74,4 +74,4 @@ runtime-benchmarks = [ "rand_chacha", "sp-staking/runtime-benchmarks", ] -try-runtime = ["frame-support/try-runtime"] +try-runtime = ["frame-support/try-runtime", "frame-election-provider-support/try-runtime"] diff --git a/frame/staking/src/migrations.rs b/frame/staking/src/migrations.rs index 6253c3feed17d..a8d360c098137 100644 --- a/frame/staking/src/migrations.rs +++ b/frame/staking/src/migrations.rs @@ -386,7 +386,6 @@ pub mod v8 { Nominators::::iter().map(|(id, _)| id), Pallet::::weight_of_fn(), ); - debug_assert_eq!(T::VoterList::try_state(), Ok(())); StorageVersion::::put(ObsoleteReleases::V8_0_0); crate::log!( diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index 994a6b55f8355..7e5f4415267b7 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -1476,9 +1476,11 @@ impl SortedListProvider for UseValidatorsMap { // nothing to do upon regenerate. 0 } + #[cfg(feature = "try-runtime")] fn try_state() -> Result<(), &'static str> { Ok(()) } + fn unsafe_clear() { #[allow(deprecated)] Validators::::remove_all(); @@ -1550,6 +1552,8 @@ impl SortedListProvider for UseNominatorsAndValidatorsM // nothing to do upon regenerate. 0 } + + #[cfg(feature = "try-runtime")] fn try_state() -> Result<(), &'static str> { Ok(()) } From 821ad7ef267e31e9ba1d7a0e9eeff1ca4f52d318 Mon Sep 17 00:00:00 2001 From: Javier Viola Date: Fri, 10 Feb 2023 11:11:10 -0300 Subject: [PATCH 118/162] bump version of zombienet and update snaps links (#13359) --- .gitlab-ci.yml | 2 +- zombienet/0001-basic-warp-sync/test-warp-sync.toml | 6 +++--- .../test-validators-warp-sync.toml | 6 +++--- .../test-block-building-warp-sync.toml | 6 +++--- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index ae25a2c5953f5..ab3fd84d6e9ee 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -55,7 +55,7 @@ variables: RUSTY_CACHIER_COMPRESSION_METHOD: zstd NEXTEST_FAILURE_OUTPUT: immediate-final NEXTEST_SUCCESS_OUTPUT: final - ZOMBIENET_IMAGE: "docker.io/paritytech/zombienet:v1.3.22" + ZOMBIENET_IMAGE: "docker.io/paritytech/zombienet:v1.3.34" .shared-default: &shared-default retry: diff --git a/zombienet/0001-basic-warp-sync/test-warp-sync.toml b/zombienet/0001-basic-warp-sync/test-warp-sync.toml index ae2810b6ecccd..272b5862e8e89 100644 --- a/zombienet/0001-basic-warp-sync/test-warp-sync.toml +++ b/zombienet/0001-basic-warp-sync/test-warp-sync.toml @@ -11,18 +11,18 @@ chain_spec_path = "zombienet/0001-basic-warp-sync/chain-spec.json" [[relaychain.nodes]] name = "alice" validator = false - db_snapshot="https://storage.googleapis.com/zombienet-db-snaps/substrate/0001-basic-warp-sync/chains-0bb3f0be2ce41b5615b224215bcc8363aa0416a6.tgz" + db_snapshot="https://storage.googleapis.com/zombienet-db-snaps/substrate/0001-basic-warp-sync/chains-a233bbacff650aac6bcb56b4e4ef7db7dc143cfb.tgz" [[relaychain.nodes]] name = "bob" validator = false - db_snapshot="https://storage.googleapis.com/zombienet-db-snaps/substrate/0001-basic-warp-sync/chains-0bb3f0be2ce41b5615b224215bcc8363aa0416a6.tgz" + db_snapshot="https://storage.googleapis.com/zombienet-db-snaps/substrate/0001-basic-warp-sync/chains-a233bbacff650aac6bcb56b4e4ef7db7dc143cfb.tgz" #we need at least 3 nodes for warp sync [[relaychain.nodes]] name = "charlie" validator = false - db_snapshot="https://storage.googleapis.com/zombienet-db-snaps/substrate/0001-basic-warp-sync/chains-0bb3f0be2ce41b5615b224215bcc8363aa0416a6.tgz" + db_snapshot="https://storage.googleapis.com/zombienet-db-snaps/substrate/0001-basic-warp-sync/chains-a233bbacff650aac6bcb56b4e4ef7db7dc143cfb.tgz" [[relaychain.nodes]] name = "dave" diff --git a/zombienet/0002-validators-warp-sync/test-validators-warp-sync.toml b/zombienet/0002-validators-warp-sync/test-validators-warp-sync.toml index dae6e406f04da..df4414f5c8b5f 100644 --- a/zombienet/0002-validators-warp-sync/test-validators-warp-sync.toml +++ b/zombienet/0002-validators-warp-sync/test-validators-warp-sync.toml @@ -22,14 +22,14 @@ chain_spec_path = "zombienet/0002-validators-warp-sync/chain-spec.json" [[relaychain.nodes]] name = "charlie" validator = false - db_snapshot="https://storage.googleapis.com/zombienet-db-snaps/substrate/0001-basic-warp-sync/chains-0bb3f0be2ce41b5615b224215bcc8363aa0416a6.tgz" + db_snapshot="https://storage.googleapis.com/zombienet-db-snaps/substrate/0001-basic-warp-sync/chains-a233bbacff650aac6bcb56b4e4ef7db7dc143cfb.tgz" [[relaychain.nodes]] name = "dave" validator = false - db_snapshot="https://storage.googleapis.com/zombienet-db-snaps/substrate/0001-basic-warp-sync/chains-0bb3f0be2ce41b5615b224215bcc8363aa0416a6.tgz" + db_snapshot="https://storage.googleapis.com/zombienet-db-snaps/substrate/0001-basic-warp-sync/chains-a233bbacff650aac6bcb56b4e4ef7db7dc143cfb.tgz" [[relaychain.nodes]] name = "eve" validator = false - db_snapshot="https://storage.googleapis.com/zombienet-db-snaps/substrate/0001-basic-warp-sync/chains-0bb3f0be2ce41b5615b224215bcc8363aa0416a6.tgz" + db_snapshot="https://storage.googleapis.com/zombienet-db-snaps/substrate/0001-basic-warp-sync/chains-a233bbacff650aac6bcb56b4e4ef7db7dc143cfb.tgz" diff --git a/zombienet/0003-block-building-warp-sync/test-block-building-warp-sync.toml b/zombienet/0003-block-building-warp-sync/test-block-building-warp-sync.toml index 66176845cc78d..5119c919c70c4 100644 --- a/zombienet/0003-block-building-warp-sync/test-block-building-warp-sync.toml +++ b/zombienet/0003-block-building-warp-sync/test-block-building-warp-sync.toml @@ -12,17 +12,17 @@ chain_spec_path = "zombienet/0003-block-building-warp-sync/chain-spec.json" [[relaychain.nodes]] name = "alice" validator = true - db_snapshot="https://storage.googleapis.com/zombienet-db-snaps/substrate/0001-basic-warp-sync/chains-0bb3f0be2ce41b5615b224215bcc8363aa0416a6.tgz" + db_snapshot="https://storage.googleapis.com/zombienet-db-snaps/substrate/0001-basic-warp-sync/chains-a233bbacff650aac6bcb56b4e4ef7db7dc143cfb.tgz" [[relaychain.nodes]] name = "bob" validator = true - db_snapshot="https://storage.googleapis.com/zombienet-db-snaps/substrate/0001-basic-warp-sync/chains-0bb3f0be2ce41b5615b224215bcc8363aa0416a6.tgz" + db_snapshot="https://storage.googleapis.com/zombienet-db-snaps/substrate/0001-basic-warp-sync/chains-a233bbacff650aac6bcb56b4e4ef7db7dc143cfb.tgz" [[relaychain.nodes]] name = "charlie" validator = false - db_snapshot="https://storage.googleapis.com/zombienet-db-snaps/substrate/0001-basic-warp-sync/chains-0bb3f0be2ce41b5615b224215bcc8363aa0416a6.tgz" + db_snapshot="https://storage.googleapis.com/zombienet-db-snaps/substrate/0001-basic-warp-sync/chains-a233bbacff650aac6bcb56b4e4ef7db7dc143cfb.tgz" [[relaychain.nodes]] name = "dave" From 826cfb25505fc7d93e9495e8b60a80cfec9cbe8a Mon Sep 17 00:00:00 2001 From: Davide Galassi Date: Sat, 11 Feb 2023 18:35:04 +0100 Subject: [PATCH 119/162] Fix longest chain finalization target lookup (#13289) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Finalization target should be chosed as some ancestor of SelectChain::best_chain * More test assertions * Improve docs * Removed stale docs * Rename 'target' to 'base' in lookup method * Fix typo * Apply suggestions from code review Co-authored-by: André Silva <123550+andresilva@users.noreply.github.com> * Rename 'target_hash' to 'base_hash' in 'SelectChain::finality_target()' * Apply suggestions from code review Co-authored-by: Anton * Docs improvement * Doc fix * Apply suggestions from code review Co-authored-by: Bastian Köcher * Apply more code suggestions --------- Co-authored-by: André Silva <123550+andresilva@users.noreply.github.com> Co-authored-by: Anton Co-authored-by: Bastian Köcher --- client/consensus/common/src/longest_chain.rs | 80 ++++++- client/finality-grandpa/src/tests.rs | 2 +- client/service/test/src/client/mod.rs | 217 ++++++++++++------ primitives/blockchain/src/backend.rs | 84 ++----- .../consensus/common/src/select_chain.rs | 8 +- 5 files changed, 242 insertions(+), 149 deletions(-) diff --git a/client/consensus/common/src/longest_chain.rs b/client/consensus/common/src/longest_chain.rs index fab2c3a4c06fd..ece2486209ff3 100644 --- a/client/consensus/common/src/longest_chain.rs +++ b/client/consensus/common/src/longest_chain.rs @@ -21,7 +21,7 @@ use sc_client_api::backend; use sp_blockchain::{Backend, HeaderBackend}; use sp_consensus::{Error as ConsensusError, SelectChain}; -use sp_runtime::traits::{Block as BlockT, NumberFor}; +use sp_runtime::traits::{Block as BlockT, Header, NumberFor}; use std::{marker::PhantomData, sync::Arc}; /// Implement Longest Chain Select implementation @@ -48,15 +48,19 @@ where LongestChain { backend, _phantom: Default::default() } } - fn best_block_header(&self) -> sp_blockchain::Result<::Header> { + fn best_hash(&self) -> sp_blockchain::Result<::Hash> { let info = self.backend.blockchain().info(); let import_lock = self.backend.get_import_lock(); let best_hash = self .backend .blockchain() - .best_containing(info.best_hash, None, import_lock)? + .longest_containing(info.best_hash, import_lock)? .unwrap_or(info.best_hash); + Ok(best_hash) + } + fn best_header(&self) -> sp_blockchain::Result<::Header> { + let best_hash = self.best_hash()?; Ok(self .backend .blockchain() @@ -64,6 +68,65 @@ where .expect("given block hash was fetched from block in db; qed")) } + /// Returns the highest descendant of the given block that is a valid + /// candidate to be finalized. + /// + /// In this context, being a valid target means being an ancestor of + /// the best chain according to the `best_header` method. + /// + /// If `maybe_max_number` is `Some(max_block_number)` the search is + /// limited to block `number <= max_block_number`. In other words + /// as if there were no blocks greater than `max_block_number`. + fn finality_target( + &self, + base_hash: Block::Hash, + maybe_max_number: Option>, + ) -> sp_blockchain::Result { + use sp_blockchain::Error::{Application, MissingHeader}; + let blockchain = self.backend.blockchain(); + + let mut current_head = self.best_header()?; + let mut best_hash = current_head.hash(); + + let base_header = blockchain + .header(base_hash)? + .ok_or_else(|| MissingHeader(base_hash.to_string()))?; + let base_number = *base_header.number(); + + if let Some(max_number) = maybe_max_number { + if max_number < base_number { + let msg = format!( + "Requested a finality target using max number {} below the base number {}", + max_number, base_number + ); + return Err(Application(msg.into())) + } + + while current_head.number() > &max_number { + best_hash = *current_head.parent_hash(); + current_head = blockchain + .header(best_hash)? + .ok_or_else(|| MissingHeader(format!("{best_hash:?}")))?; + } + } + + while current_head.hash() != base_hash { + if *current_head.number() < base_number { + let msg = format!( + "Requested a finality target using a base {:?} not in the best chain {:?}", + base_hash, best_hash, + ); + return Err(Application(msg.into())) + } + let current_hash = *current_head.parent_hash(); + current_head = blockchain + .header(current_hash)? + .ok_or_else(|| MissingHeader(format!("{best_hash:?}")))?; + } + + Ok(best_hash) + } + fn leaves(&self) -> Result::Hash>, sp_blockchain::Error> { self.backend.blockchain().leaves() } @@ -80,20 +143,15 @@ where } async fn best_chain(&self) -> Result<::Header, ConsensusError> { - LongestChain::best_block_header(self) - .map_err(|e| ConsensusError::ChainLookup(e.to_string())) + LongestChain::best_header(self).map_err(|e| ConsensusError::ChainLookup(e.to_string())) } async fn finality_target( &self, - target_hash: Block::Hash, + base_hash: Block::Hash, maybe_max_number: Option>, ) -> Result { - let import_lock = self.backend.get_import_lock(); - self.backend - .blockchain() - .best_containing(target_hash, maybe_max_number, import_lock) - .map(|maybe_hash| maybe_hash.unwrap_or(target_hash)) + LongestChain::finality_target(self, base_hash, maybe_max_number) .map_err(|e| ConsensusError::ChainLookup(e.to_string())) } } diff --git a/client/finality-grandpa/src/tests.rs b/client/finality-grandpa/src/tests.rs index 07ea4649148fb..62ef4709e1909 100644 --- a/client/finality-grandpa/src/tests.rs +++ b/client/finality-grandpa/src/tests.rs @@ -237,7 +237,7 @@ impl SelectChain for MockSelectChain { async fn finality_target( &self, - _target_hash: Hash, + _base_hash: Hash, _maybe_max_number: Option>, ) -> Result { Ok(self.finality_target.lock().take().unwrap()) diff --git a/client/service/test/src/client/mod.rs b/client/service/test/src/client/mod.rs index 97c22a1cb509e..12b92afc458b4 100644 --- a/client/service/test/src/client/mod.rs +++ b/client/service/test/src/client/mod.rs @@ -581,7 +581,7 @@ fn uncles_with_multiple_forks() { } #[test] -fn best_containing_on_longest_chain_with_single_chain_3_blocks() { +fn finality_target_on_longest_chain_with_single_chain_3_blocks() { // block tree: // G -> A1 -> A2 @@ -606,7 +606,7 @@ fn best_containing_on_longest_chain_with_single_chain_3_blocks() { } #[test] -fn best_containing_on_longest_chain_with_multiple_forks() { +fn finality_target_on_longest_chain_with_multiple_forks() { // block tree: // G -> A1 -> A2 -> A3 -> A4 -> A5 // A1 -> B2 -> B3 -> B4 @@ -731,8 +731,13 @@ fn best_containing_on_longest_chain_with_multiple_forks() { assert!(leaves.contains(&d2.hash())); assert_eq!(leaves.len(), 4); - let finality_target = |target_hash, number| { - block_on(longest_chain_select.finality_target(target_hash, number)).unwrap() + // On error we return a quite improbable hash + let error_hash = Hash::from([0xff; 32]); + let finality_target = |target_hash, number| match block_on( + longest_chain_select.finality_target(target_hash, number), + ) { + Ok(hash) => hash, + Err(_) => error_hash, }; // search without restriction @@ -742,11 +747,11 @@ fn best_containing_on_longest_chain_with_multiple_forks() { assert_eq!(a5.hash(), finality_target(a3.hash(), None)); assert_eq!(a5.hash(), finality_target(a4.hash(), None)); assert_eq!(a5.hash(), finality_target(a5.hash(), None)); - assert_eq!(b4.hash(), finality_target(b2.hash(), None)); - assert_eq!(b4.hash(), finality_target(b3.hash(), None)); - assert_eq!(b4.hash(), finality_target(b4.hash(), None)); - assert_eq!(c3.hash(), finality_target(c3.hash(), None)); - assert_eq!(d2.hash(), finality_target(d2.hash(), None)); + assert_eq!(error_hash, finality_target(b2.hash(), None)); + assert_eq!(error_hash, finality_target(b3.hash(), None)); + assert_eq!(error_hash, finality_target(b4.hash(), None)); + assert_eq!(error_hash, finality_target(c3.hash(), None)); + assert_eq!(error_hash, finality_target(d2.hash(), None)); // search only blocks with number <= 5. equivalent to without restriction for this scenario assert_eq!(a5.hash(), finality_target(genesis_hash, Some(5))); @@ -755,11 +760,11 @@ fn best_containing_on_longest_chain_with_multiple_forks() { assert_eq!(a5.hash(), finality_target(a3.hash(), Some(5))); assert_eq!(a5.hash(), finality_target(a4.hash(), Some(5))); assert_eq!(a5.hash(), finality_target(a5.hash(), Some(5))); - assert_eq!(b4.hash(), finality_target(b2.hash(), Some(5))); - assert_eq!(b4.hash(), finality_target(b3.hash(), Some(5))); - assert_eq!(b4.hash(), finality_target(b4.hash(), Some(5))); - assert_eq!(c3.hash(), finality_target(c3.hash(), Some(5))); - assert_eq!(d2.hash(), finality_target(d2.hash(), Some(5))); + assert_eq!(error_hash, finality_target(b2.hash(), Some(5))); + assert_eq!(error_hash, finality_target(b3.hash(), Some(5))); + assert_eq!(error_hash, finality_target(b4.hash(), Some(5))); + assert_eq!(error_hash, finality_target(c3.hash(), Some(5))); + assert_eq!(error_hash, finality_target(d2.hash(), Some(5))); // search only blocks with number <= 4 assert_eq!(a4.hash(), finality_target(genesis_hash, Some(4))); @@ -767,73 +772,72 @@ fn best_containing_on_longest_chain_with_multiple_forks() { assert_eq!(a4.hash(), finality_target(a2.hash(), Some(4))); assert_eq!(a4.hash(), finality_target(a3.hash(), Some(4))); assert_eq!(a4.hash(), finality_target(a4.hash(), Some(4))); - assert_eq!(a5.hash(), finality_target(a5.hash(), Some(4))); - assert_eq!(b4.hash(), finality_target(b2.hash(), Some(4))); - assert_eq!(b4.hash(), finality_target(b3.hash(), Some(4))); - assert_eq!(b4.hash(), finality_target(b4.hash(), Some(4))); - assert_eq!(c3.hash(), finality_target(c3.hash(), Some(4))); - assert_eq!(d2.hash(), finality_target(d2.hash(), Some(4))); + assert_eq!(error_hash, finality_target(a5.hash(), Some(4))); + assert_eq!(error_hash, finality_target(b2.hash(), Some(4))); + assert_eq!(error_hash, finality_target(b3.hash(), Some(4))); + assert_eq!(error_hash, finality_target(b4.hash(), Some(4))); + assert_eq!(error_hash, finality_target(c3.hash(), Some(4))); + assert_eq!(error_hash, finality_target(d2.hash(), Some(4))); // search only blocks with number <= 3 assert_eq!(a3.hash(), finality_target(genesis_hash, Some(3))); assert_eq!(a3.hash(), finality_target(a1.hash(), Some(3))); assert_eq!(a3.hash(), finality_target(a2.hash(), Some(3))); assert_eq!(a3.hash(), finality_target(a3.hash(), Some(3))); - assert_eq!(a4.hash(), finality_target(a4.hash(), Some(3))); - assert_eq!(a5.hash(), finality_target(a5.hash(), Some(3))); - assert_eq!(b3.hash(), finality_target(b2.hash(), Some(3))); - assert_eq!(b3.hash(), finality_target(b3.hash(), Some(3))); - assert_eq!(b4.hash(), finality_target(b4.hash(), Some(3))); - assert_eq!(c3.hash(), finality_target(c3.hash(), Some(3))); - assert_eq!(d2.hash(), finality_target(d2.hash(), Some(3))); + assert_eq!(error_hash, finality_target(a4.hash(), Some(3))); + assert_eq!(error_hash, finality_target(a5.hash(), Some(3))); + assert_eq!(error_hash, finality_target(b2.hash(), Some(3))); + assert_eq!(error_hash, finality_target(b3.hash(), Some(3))); + assert_eq!(error_hash, finality_target(b4.hash(), Some(3))); + assert_eq!(error_hash, finality_target(c3.hash(), Some(3))); + assert_eq!(error_hash, finality_target(d2.hash(), Some(3))); // search only blocks with number <= 2 assert_eq!(a2.hash(), finality_target(genesis_hash, Some(2))); assert_eq!(a2.hash(), finality_target(a1.hash(), Some(2))); assert_eq!(a2.hash(), finality_target(a2.hash(), Some(2))); - assert_eq!(a3.hash(), finality_target(a3.hash(), Some(2))); - assert_eq!(a4.hash(), finality_target(a4.hash(), Some(2))); - assert_eq!(a5.hash(), finality_target(a5.hash(), Some(2))); - assert_eq!(b2.hash(), finality_target(b2.hash(), Some(2))); - assert_eq!(b3.hash(), finality_target(b3.hash(), Some(2))); - assert_eq!(b4.hash(), finality_target(b4.hash(), Some(2))); - assert_eq!(c3.hash(), finality_target(c3.hash(), Some(2))); - assert_eq!(d2.hash(), finality_target(d2.hash(), Some(2))); + assert_eq!(error_hash, finality_target(a3.hash(), Some(2))); + assert_eq!(error_hash, finality_target(a4.hash(), Some(2))); + assert_eq!(error_hash, finality_target(a5.hash(), Some(2))); + assert_eq!(error_hash, finality_target(b2.hash(), Some(2))); + assert_eq!(error_hash, finality_target(b3.hash(), Some(2))); + assert_eq!(error_hash, finality_target(b4.hash(), Some(2))); + assert_eq!(error_hash, finality_target(c3.hash(), Some(2))); + assert_eq!(error_hash, finality_target(d2.hash(), Some(2))); // search only blocks with number <= 1 assert_eq!(a1.hash(), finality_target(genesis_hash, Some(1))); assert_eq!(a1.hash(), finality_target(a1.hash(), Some(1))); - assert_eq!(a2.hash(), finality_target(a2.hash(), Some(1))); - assert_eq!(a3.hash(), finality_target(a3.hash(), Some(1))); - assert_eq!(a4.hash(), finality_target(a4.hash(), Some(1))); - assert_eq!(a5.hash(), finality_target(a5.hash(), Some(1))); - - assert_eq!(b2.hash(), finality_target(b2.hash(), Some(1))); - assert_eq!(b3.hash(), finality_target(b3.hash(), Some(1))); - assert_eq!(b4.hash(), finality_target(b4.hash(), Some(1))); - assert_eq!(c3.hash(), finality_target(c3.hash(), Some(1))); - assert_eq!(d2.hash(), finality_target(d2.hash(), Some(1))); + assert_eq!(error_hash, finality_target(a2.hash(), Some(1))); + assert_eq!(error_hash, finality_target(a3.hash(), Some(1))); + assert_eq!(error_hash, finality_target(a4.hash(), Some(1))); + assert_eq!(error_hash, finality_target(a5.hash(), Some(1))); + assert_eq!(error_hash, finality_target(b2.hash(), Some(1))); + assert_eq!(error_hash, finality_target(b3.hash(), Some(1))); + assert_eq!(error_hash, finality_target(b4.hash(), Some(1))); + assert_eq!(error_hash, finality_target(c3.hash(), Some(1))); + assert_eq!(error_hash, finality_target(d2.hash(), Some(1))); // search only blocks with number <= 0 assert_eq!(genesis_hash, finality_target(genesis_hash, Some(0))); - assert_eq!(a1.hash(), finality_target(a1.hash(), Some(0))); - assert_eq!(a2.hash(), finality_target(a2.hash(), Some(0))); - assert_eq!(a3.hash(), finality_target(a3.hash(), Some(0))); - assert_eq!(a4.hash(), finality_target(a4.hash(), Some(0))); - assert_eq!(a5.hash(), finality_target(a5.hash(), Some(0))); - assert_eq!(b2.hash(), finality_target(b2.hash(), Some(0))); - assert_eq!(b3.hash(), finality_target(b3.hash(), Some(0))); - assert_eq!(b4.hash(), finality_target(b4.hash(), Some(0))); - assert_eq!(c3.hash(), finality_target(c3.hash(), Some(0))); - assert_eq!(d2.hash(), finality_target(d2.hash(), Some(0))); + assert_eq!(error_hash, finality_target(a1.hash(), Some(0))); + assert_eq!(error_hash, finality_target(a2.hash(), Some(0))); + assert_eq!(error_hash, finality_target(a3.hash(), Some(0))); + assert_eq!(error_hash, finality_target(a4.hash(), Some(0))); + assert_eq!(error_hash, finality_target(a5.hash(), Some(0))); + assert_eq!(error_hash, finality_target(b2.hash(), Some(0))); + assert_eq!(error_hash, finality_target(b3.hash(), Some(0))); + assert_eq!(error_hash, finality_target(b4.hash(), Some(0))); + assert_eq!(error_hash, finality_target(c3.hash(), Some(0))); + assert_eq!(error_hash, finality_target(d2.hash(), Some(0))); } #[test] -fn best_containing_on_longest_chain_with_max_depth_higher_than_best() { +fn finality_target_on_longest_chain_with_max_depth_higher_than_best() { // block tree: // G -> A1 -> A2 - let (mut client, longest_chain_select) = TestClientBuilder::new().build_with_longest_chain(); + let (mut client, chain_select) = TestClientBuilder::new().build_with_longest_chain(); // G -> A1 let a1 = client.new_block(Default::default()).unwrap().build().unwrap().block; @@ -845,10 +849,93 @@ fn best_containing_on_longest_chain_with_max_depth_higher_than_best() { let genesis_hash = client.chain_info().genesis_hash; - assert_eq!( - a2.hash(), - block_on(longest_chain_select.finality_target(genesis_hash, Some(10))).unwrap(), - ); + assert_eq!(a2.hash(), block_on(chain_select.finality_target(genesis_hash, Some(10))).unwrap(),); +} + +#[test] +fn finality_target_with_best_not_on_longest_chain() { + // block tree: + // G -> A1 -> A2 -> A3 -> A4 -> A5 + // -> B2 -> (B3) -> B4 + // ^best + + let (mut client, chain_select) = TestClientBuilder::new().build_with_longest_chain(); + let genesis_hash = client.chain_info().genesis_hash; + + // G -> A1 + let a1 = client.new_block(Default::default()).unwrap().build().unwrap().block; + block_on(client.import(BlockOrigin::Own, a1.clone())).unwrap(); + + // A1 -> A2 + let a2 = client.new_block(Default::default()).unwrap().build().unwrap().block; + block_on(client.import(BlockOrigin::Own, a2.clone())).unwrap(); + + // A2 -> A3 + let a3 = client.new_block(Default::default()).unwrap().build().unwrap().block; + block_on(client.import(BlockOrigin::Own, a3.clone())).unwrap(); + + // A3 -> A4 + let a4 = client.new_block(Default::default()).unwrap().build().unwrap().block; + block_on(client.import(BlockOrigin::Own, a4.clone())).unwrap(); + + // A3 -> A5 + let a5 = client.new_block(Default::default()).unwrap().build().unwrap().block; + block_on(client.import(BlockOrigin::Own, a5.clone())).unwrap(); + + // A1 -> B2 + let mut builder = client + .new_block_at(&BlockId::Hash(a1.hash()), Default::default(), false) + .unwrap(); + // this push is required as otherwise B2 has the same hash as A2 and won't get imported + builder + .push_transfer(Transfer { + from: AccountKeyring::Alice.into(), + to: AccountKeyring::Ferdie.into(), + amount: 41, + nonce: 0, + }) + .unwrap(); + let b2 = builder.build().unwrap().block; + block_on(client.import(BlockOrigin::Own, b2.clone())).unwrap(); + + assert_eq!(a5.hash(), block_on(chain_select.finality_target(genesis_hash, None)).unwrap()); + assert_eq!(a5.hash(), block_on(chain_select.finality_target(a1.hash(), None)).unwrap()); + assert_eq!(a5.hash(), block_on(chain_select.finality_target(a2.hash(), None)).unwrap()); + assert_eq!(a5.hash(), block_on(chain_select.finality_target(a3.hash(), None)).unwrap()); + assert_eq!(a5.hash(), block_on(chain_select.finality_target(a4.hash(), None)).unwrap()); + assert_eq!(a5.hash(), block_on(chain_select.finality_target(a5.hash(), None)).unwrap()); + + // B2 -> B3 + let b3 = client + .new_block_at(&BlockId::Hash(b2.hash()), Default::default(), false) + .unwrap() + .build() + .unwrap() + .block; + block_on(client.import_as_best(BlockOrigin::Own, b3.clone())).unwrap(); + + // B3 -> B4 + let b4 = client + .new_block_at(&BlockId::Hash(b3.hash()), Default::default(), false) + .unwrap() + .build() + .unwrap() + .block; + let (header, extrinsics) = b4.clone().deconstruct(); + let mut import_params = BlockImportParams::new(BlockOrigin::Own, header); + import_params.body = Some(extrinsics); + import_params.fork_choice = Some(ForkChoiceStrategy::Custom(false)); + block_on(client.import_block(import_params, Default::default())).unwrap(); + + // double check that B3 is still the best... + assert_eq!(client.info().best_hash, b3.hash()); + + assert_eq!(b4.hash(), block_on(chain_select.finality_target(genesis_hash, None)).unwrap()); + assert_eq!(b4.hash(), block_on(chain_select.finality_target(a1.hash(), None)).unwrap()); + assert!(block_on(chain_select.finality_target(a2.hash(), None)).is_err()); + assert_eq!(b4.hash(), block_on(chain_select.finality_target(b2.hash(), None)).unwrap()); + assert_eq!(b4.hash(), block_on(chain_select.finality_target(b3.hash(), None)).unwrap()); + assert_eq!(b4.hash(), block_on(chain_select.finality_target(b4.hash(), None)).unwrap()); } #[test] @@ -995,7 +1082,7 @@ fn finalizing_diverged_block_should_trigger_reorg() { .block; block_on(client.import(BlockOrigin::Own, b2.clone())).unwrap(); - // A2 is the current best since it's the longest chain + // A2 is the current best since it's the (first) longest chain assert_eq!(client.chain_info().best_hash, a2.hash()); // we finalize block B1 which is on a different branch from current best @@ -1012,8 +1099,7 @@ fn finalizing_diverged_block_should_trigger_reorg() { // `SelectChain` should report B2 as best block though assert_eq!(block_on(select_chain.best_chain()).unwrap().hash(), b2.hash()); - // after we build B3 on top of B2 and import it - // it should be the new best block, + // after we build B3 on top of B2 and import it, it should be the new best block let b3 = client .new_block_at(&BlockId::Hash(b2.hash()), Default::default(), false) .unwrap() @@ -1022,6 +1108,9 @@ fn finalizing_diverged_block_should_trigger_reorg() { .block; block_on(client.import(BlockOrigin::Own, b3.clone())).unwrap(); + // `SelectChain` should report B3 as best block though + assert_eq!(block_on(select_chain.best_chain()).unwrap().hash(), b3.hash()); + assert_eq!(client.chain_info().best_hash, b3.hash()); ClientExt::finalize_block(&client, b3.hash(), None).unwrap(); diff --git a/primitives/blockchain/src/backend.rs b/primitives/blockchain/src/backend.rs index ec9c8ac0d5780..7339d4c1a6804 100644 --- a/primitives/blockchain/src/backend.rs +++ b/primitives/blockchain/src/backend.rs @@ -183,96 +183,43 @@ pub trait Backend: /// Return hashes of all blocks that are children of the block with `parent_hash`. fn children(&self, parent_hash: Block::Hash) -> Result>; - /// Get the most recent block hash of the best (longest) chains - /// that contain block with the given `target_hash`. + /// Get the most recent block hash of the longest chain that contains + /// a block with the given `base_hash`. /// /// The search space is always limited to blocks which are in the finalized /// chain or descendents of it. /// - /// If `maybe_max_block_number` is `Some(max_block_number)` - /// the search is limited to block `numbers <= max_block_number`. - /// in other words as if there were no blocks greater `max_block_number`. - /// Returns `Ok(None)` if `target_hash` is not found in search space. - /// TODO: document time complexity of this, see [#1444](https://github.com/paritytech/substrate/issues/1444) - fn best_containing( + /// Returns `Ok(None)` if `base_hash` is not found in search space. + // TODO: document time complexity of this, see [#1444](https://github.com/paritytech/substrate/issues/1444) + fn longest_containing( &self, - target_hash: Block::Hash, - maybe_max_number: Option>, + base_hash: Block::Hash, import_lock: &RwLock<()>, ) -> Result> { - let target_header = { - match self.header(target_hash)? { - Some(x) => x, - // target not in blockchain - None => return Ok(None), - } + let Some(base_header) = self.header(base_hash)? else { + return Ok(None) }; - if let Some(max_number) = maybe_max_number { - // target outside search range - if target_header.number() > &max_number { - return Ok(None) - } - } - let leaves = { // ensure no blocks are imported during this code block. // an import could trigger a reorg which could change the canonical chain. // we depend on the canonical chain staying the same during this code block. let _import_guard = import_lock.read(); - let info = self.info(); - - // this can be `None` if the best chain is shorter than the target header. - let maybe_canon_hash = self.hash(*target_header.number())?; - - if maybe_canon_hash.as_ref() == Some(&target_hash) { - // if a `max_number` is given we try to fetch the block at the - // given depth, if it doesn't exist or `max_number` is not - // provided, we continue to search from all leaves below. - if let Some(max_number) = maybe_max_number { - if let Some(header) = self.hash(max_number)? { - return Ok(Some(header)) - } - } - } else if info.finalized_number >= *target_header.number() { - // header is on a dead fork. + if info.finalized_number > *base_header.number() { + // `base_header` is on a dead fork. return Ok(None) } - self.leaves()? }; // for each chain. longest chain first. shortest last for leaf_hash in leaves { - // start at the leaf let mut current_hash = leaf_hash; - - // if search is not restricted then the leaf is the best - let mut best_hash = leaf_hash; - - // go backwards entering the search space - // waiting until we are <= max_number - if let Some(max_number) = maybe_max_number { - loop { - let current_header = self - .header(current_hash)? - .ok_or_else(|| Error::MissingHeader(current_hash.to_string()))?; - - if current_header.number() <= &max_number { - best_hash = current_header.hash(); - break - } - - current_hash = *current_header.parent_hash(); - } - } - // go backwards through the chain (via parent links) loop { - // until we find target - if current_hash == target_hash { - return Ok(Some(best_hash)) + if current_hash == base_hash { + return Ok(Some(leaf_hash)) } let current_header = self @@ -280,7 +227,7 @@ pub trait Backend: .ok_or_else(|| Error::MissingHeader(current_hash.to_string()))?; // stop search in this chain once we go below the target's block number - if current_header.number() < target_header.number() { + if current_header.number() < base_header.number() { break } @@ -293,9 +240,8 @@ pub trait Backend: // // FIXME #1558 only issue this warning when not on a dead fork warn!( - "Block {:?} exists in chain but not found when following all \ - leaves backwards. Number limit = {:?}", - target_hash, maybe_max_number, + "Block {:?} exists in chain but not found when following all leaves backwards", + base_hash, ); Ok(None) diff --git a/primitives/consensus/common/src/select_chain.rs b/primitives/consensus/common/src/select_chain.rs index f366cd34c51ea..5beab6705046d 100644 --- a/primitives/consensus/common/src/select_chain.rs +++ b/primitives/consensus/common/src/select_chain.rs @@ -43,14 +43,14 @@ pub trait SelectChain: Sync + Send + Clone { /// finalize. async fn best_chain(&self) -> Result<::Header, Error>; - /// Get the best descendent of `target_hash` that we should attempt to - /// finalize next, if any. It is valid to return the given `target_hash` + /// Get the best descendent of `base_hash` that we should attempt to + /// finalize next, if any. It is valid to return the given `base_hash` /// itself if no better descendent exists. async fn finality_target( &self, - target_hash: ::Hash, + base_hash: ::Hash, _maybe_max_number: Option>, ) -> Result<::Hash, Error> { - Ok(target_hash) + Ok(base_hash) } } From 71432c2bd7ee67b79e17199920a0423bd1650d51 Mon Sep 17 00:00:00 2001 From: girazoki Date: Sun, 12 Feb 2023 11:43:03 +0100 Subject: [PATCH 120/162] SetMembers configurable origin (#13159) * SetMembers configurable origin * root origin comment replaced * fmt --- bin/node/runtime/src/lib.rs | 3 +++ frame/alliance/src/mock.rs | 1 + frame/collective/src/lib.rs | 7 +++++-- frame/collective/src/tests.rs | 5 ++++- frame/utility/src/tests.rs | 1 + 5 files changed, 14 insertions(+), 3 deletions(-) diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 4298a6eced430..8f8a7ceef3cfe 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -992,6 +992,7 @@ impl pallet_collective::Config for Runtime { type MaxMembers = CouncilMaxMembers; type DefaultVote = pallet_collective::PrimeDefaultVote; type WeightInfo = pallet_collective::weights::SubstrateWeight; + type SetMembersOrigin = EnsureRoot; } parameter_types! { @@ -1051,6 +1052,7 @@ impl pallet_collective::Config for Runtime { type MaxMembers = TechnicalMaxMembers; type DefaultVote = pallet_collective::PrimeDefaultVote; type WeightInfo = pallet_collective::weights::SubstrateWeight; + type SetMembersOrigin = EnsureRoot; } type EnsureRootOrHalfCouncil = EitherOfDiverse< @@ -1652,6 +1654,7 @@ impl pallet_collective::Config for Runtime { type MaxMembers = AllianceMaxMembers; type DefaultVote = pallet_collective::PrimeDefaultVote; type WeightInfo = pallet_collective::weights::SubstrateWeight; + type SetMembersOrigin = EnsureRoot; } parameter_types! { diff --git a/frame/alliance/src/mock.rs b/frame/alliance/src/mock.rs index e708d29d529fe..0f774dc4853fa 100644 --- a/frame/alliance/src/mock.rs +++ b/frame/alliance/src/mock.rs @@ -104,6 +104,7 @@ impl pallet_collective::Config for Test { type MaxMembers = MaxMembers; type DefaultVote = pallet_collective::PrimeDefaultVote; type WeightInfo = (); + type SetMembersOrigin = EnsureRoot; } parameter_types! { diff --git a/frame/collective/src/lib.rs b/frame/collective/src/lib.rs index 0fe05dbb01ac0..7d625a69a4bf7 100644 --- a/frame/collective/src/lib.rs +++ b/frame/collective/src/lib.rs @@ -215,6 +215,9 @@ pub mod pallet { /// Weight information for extrinsics in this pallet. type WeightInfo: WeightInfo; + + /// Origin allowed to set collective members + type SetMembersOrigin: EnsureOrigin<::RuntimeOrigin>; } #[pallet::genesis_config] @@ -349,7 +352,7 @@ pub mod pallet { /// - `old_count`: The upper bound for the previous number of members in storage. Used for /// weight estimation. /// - /// Requires root origin. + /// The dispatch of this call must be `SetMembersOrigin`. /// /// NOTE: Does not enforce the expected `MaxMembers` limit on the amount of members, but /// the weight estimations rely on it to estimate dispatchable weight. @@ -389,7 +392,7 @@ pub mod pallet { prime: Option, old_count: MemberCount, ) -> DispatchResultWithPostInfo { - ensure_root(origin)?; + T::SetMembersOrigin::ensure_origin(origin)?; if new_members.len() > T::MaxMembers::get() as usize { log::error!( target: LOG_TARGET, diff --git a/frame/collective/src/tests.rs b/frame/collective/src/tests.rs index 5c90de9f91bf7..b7cdeb3383375 100644 --- a/frame/collective/src/tests.rs +++ b/frame/collective/src/tests.rs @@ -24,7 +24,7 @@ use frame_support::{ traits::{ConstU32, ConstU64, GenesisBuild, StorageVersion}, Hashable, }; -use frame_system::{EventRecord, Phase}; +use frame_system::{EnsureRoot, EventRecord, Phase}; use sp_core::H256; use sp_runtime::{ testing::Header, @@ -127,6 +127,7 @@ impl Config for Test { type MaxMembers = MaxMembers; type DefaultVote = PrimeDefaultVote; type WeightInfo = (); + type SetMembersOrigin = EnsureRoot; } impl Config for Test { type RuntimeOrigin = RuntimeOrigin; @@ -137,6 +138,7 @@ impl Config for Test { type MaxMembers = MaxMembers; type DefaultVote = MoreThanMajorityThenPrimeDefaultVote; type WeightInfo = (); + type SetMembersOrigin = EnsureRoot; } impl mock_democracy::Config for Test { type RuntimeEvent = RuntimeEvent; @@ -151,6 +153,7 @@ impl Config for Test { type MaxMembers = MaxMembers; type DefaultVote = PrimeDefaultVote; type WeightInfo = (); + type SetMembersOrigin = EnsureRoot; } pub fn new_test_ext() -> sp_io::TestExternalities { diff --git a/frame/utility/src/tests.rs b/frame/utility/src/tests.rs index f9d6a16c1a0d4..c63ed24c6aafb 100644 --- a/frame/utility/src/tests.rs +++ b/frame/utility/src/tests.rs @@ -217,6 +217,7 @@ impl pallet_collective::Config for Test { type MaxMembers = MaxMembers; type DefaultVote = pallet_collective::PrimeDefaultVote; type WeightInfo = (); + type SetMembersOrigin = frame_system::EnsureRoot; } impl example::Config for Test {} From bfe5a7d8861a1553ddb26e2902f650f4fd273389 Mon Sep 17 00:00:00 2001 From: Ankan Date: Sun, 12 Feb 2023 20:30:03 +0100 Subject: [PATCH 121/162] have a way to disable pages --- frame/staking/src/mock.rs | 4 ++++ frame/staking/src/pallet/mod.rs | 36 +++++++++++++++++++++++++++++++-- frame/staking/src/tests.rs | 19 +++++++++++++++++ 3 files changed, 57 insertions(+), 2 deletions(-) diff --git a/frame/staking/src/mock.rs b/frame/staking/src/mock.rs index 5bd9c46bbdde3..f677cd52bcbe0 100644 --- a/frame/staking/src/mock.rs +++ b/frame/staking/src/mock.rs @@ -819,3 +819,7 @@ pub(crate) fn staking_events_since_last_call() -> Vec> { pub(crate) fn balances(who: &AccountId) -> (Balance, Balance) { (Balances::free_balance(who), Balances::reserved_balance(who)) } + +pub(crate) fn allow_exposure_pages(max_count: u32) { + MaxExposurePageCount::::put(max_count.max(1)); +} diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index 92ec691bbcfc6..4441ac9192ac0 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -482,6 +482,16 @@ pub mod pallet { #[pallet::storage] pub type ExposurePageSize = StorageValue<_, u32, OptionQuery>; + /// Maximum number of exposure pages that can be stored for a single validator in an era. + /// + /// Must be greater than 0. + /// + /// When this is set to 1, the reward payout behaviour is similar to how it used to work before + /// we had paged exposures. + #[pallet::storage] + // TODO(ank4n): Does it need #[pallet::getter(...)] + pub type MaxExposurePageCount = StorageValue<_, PageIndex, OptionQuery>; + /// Paginated exposure of a validator at given era. /// /// This is keyed first by the era index to allow bulk deletion, then the tuple of stash account @@ -650,7 +660,7 @@ pub mod pallet { /// non-paged rewards, and (2) `T::ClaimedRewards` for paged rewards. This function can be /// removed once `$HistoryDepth` eras have passed and none of the older non-paged rewards /// are relevant/claimable. - // TODO: Cleanup tracking issue: #13034 + // Refer tracker issue for cleanup: #13034 pub(crate) fn is_rewards_claimed_temp( era: EraIndex, ledger: &StakingLedger, @@ -742,6 +752,11 @@ pub mod pallet { >::contains_key(&era, validator) } + /// Returns the maximum number of pages of exposure we can store. + fn get_max_exposure_page_count() -> PageIndex { + return >::get().unwrap_or_default().max(1) + } + /// Returns validator commission for this era and page. pub(crate) fn get_validator_commission( era: EraIndex, @@ -777,12 +792,29 @@ pub mod pallet { exposure: Exposure>, ) { >::insert(era, &validator, &exposure); - // FIXME(ankan) Should we sort exposure.others for backward compatibility? let page_size = >::get() .unwrap_or_else(|| T::MaxNominatorRewardedPerValidator::get()) .clamp(1, T::MaxNominatorRewardedPerValidator::get()); + let max_page_count = Self::get_max_exposure_page_count(); + + let nominator_count = exposure.others.len(); + let page_count = nominator_count.saturating_add(page_size as usize - 1)/page_size as usize; + + // clip nominators if it exceeds the maximum page count. + let exposure = if page_count as PageIndex > max_page_count { + // sort before clipping. + let mut exposure_clipped = exposure; + let clipped_max_len = max_page_count * page_size; + + exposure_clipped.others.sort_by(|a, b| b.value.cmp(&a.value)); + exposure_clipped.others.truncate(clipped_max_len as usize); + exposure_clipped + } else { + exposure + }; + let (exposure_overview, exposure_pages) = exposure.into_pages(page_size); >::insert(era, &validator, &exposure_overview); diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index 01fd13b8f7ffe..c1b8ae1012f95 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -3695,6 +3695,9 @@ fn six_session_delay() { #[test] fn test_nominators_are_rewarded_for_all_exposure_page() { ExtBuilder::default().build_and_execute(|| { + // enable multi paged rewards payout + allow_exposure_pages(3); + // 3 pages of exposure let nominator_count = 2 * MaxNominatorRewardedPerValidator::get() + 1; @@ -3743,6 +3746,10 @@ fn test_nominators_are_rewarded_for_all_exposure_page() { fn test_multi_page_payout_stakers_by_page() { // Test that payout_stakers work in general and that it pays the correct amount of reward. ExtBuilder::default().has_stakers(false).build_and_execute(|| { + + // enable multi paged rewards payout + allow_exposure_pages(10); + let balance = 1000; // Track the exposure of the validator and all nominators. let mut total_exposure = balance; @@ -3933,6 +3940,9 @@ fn test_multi_page_payout_stakers_by_page() { fn test_multi_page_payout_stakers_backward_compatible() { // Test that payout_stakers work in general and that it pays the correct amount of reward. ExtBuilder::default().has_stakers(false).build_and_execute(|| { + // enable multi paged rewards payout + allow_exposure_pages(10); + let balance = 1000; // Track the exposure of the validator and all nominators. let mut total_exposure = balance; @@ -4160,6 +4170,9 @@ fn test_multi_page_payout_stakers_backward_compatible() { fn payout_stakers_handles_basic_errors() { // Here we will test payouts handle all errors. ExtBuilder::default().has_stakers(false).build_and_execute(|| { + // enable multi paged rewards payout + allow_exposure_pages(2); + // Consumed weight for all payout_stakers dispatches that fail let err_weight = ::WeightInfo::payout_stakers_alive_staked(0); @@ -4292,6 +4305,9 @@ fn payout_stakers_handles_basic_errors() { #[test] fn test_commission_paid_across_pages() { ExtBuilder::default().has_stakers(false).build_and_execute(|| { + // enable multi paged rewards payout + allow_exposure_pages(4); + let balance = 1; let commission = 50; // Create a validator: @@ -6209,6 +6225,9 @@ fn test_legacy_claimed_rewards_is_checked_at_reward_payout() { #[test] fn test_validator_exposure_is_backward_compatible_with_non_paged_rewards_payout() { ExtBuilder::default().has_stakers(false).build_and_execute(|| { + // enable multi paged rewards payout + allow_exposure_pages(2); + // case 1: exposure exist in clipped. // set page cap to 10 MaxNominatorRewardedPerValidator::set(10); From 02703c754797ad4f1973726eaa9725298921c0af Mon Sep 17 00:00:00 2001 From: Ankan Date: Sun, 12 Feb 2023 20:58:25 +0100 Subject: [PATCH 122/162] fmt --- frame/staking/src/pallet/mod.rs | 3 ++- frame/staking/src/tests.rs | 1 - 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index 4441ac9192ac0..bfbd0f6cf2359 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -800,7 +800,8 @@ pub mod pallet { let max_page_count = Self::get_max_exposure_page_count(); let nominator_count = exposure.others.len(); - let page_count = nominator_count.saturating_add(page_size as usize - 1)/page_size as usize; + let page_count = + nominator_count.saturating_add(page_size as usize - 1) / page_size as usize; // clip nominators if it exceeds the maximum page count. let exposure = if page_count as PageIndex > max_page_count { diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index c1b8ae1012f95..1efd18d3ae035 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -3746,7 +3746,6 @@ fn test_nominators_are_rewarded_for_all_exposure_page() { fn test_multi_page_payout_stakers_by_page() { // Test that payout_stakers work in general and that it pays the correct amount of reward. ExtBuilder::default().has_stakers(false).build_and_execute(|| { - // enable multi paged rewards payout allow_exposure_pages(10); From b79e2319553581b3f33e0bd33a57f8ac7646a657 Mon Sep 17 00:00:00 2001 From: Ankan Date: Sun, 12 Feb 2023 21:21:30 +0100 Subject: [PATCH 123/162] simple rename --- frame/staking/src/mock.rs | 4 ++-- frame/staking/src/tests.rs | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/frame/staking/src/mock.rs b/frame/staking/src/mock.rs index f677cd52bcbe0..27e1d75e71675 100644 --- a/frame/staking/src/mock.rs +++ b/frame/staking/src/mock.rs @@ -820,6 +820,6 @@ pub(crate) fn balances(who: &AccountId) -> (Balance, Balance) { (Balances::free_balance(who), Balances::reserved_balance(who)) } -pub(crate) fn allow_exposure_pages(max_count: u32) { - MaxExposurePageCount::::put(max_count.max(1)); +pub(crate) fn allow_paged_rewards(max_pages: u32) { + MaxExposurePageCount::::put(max_pages.max(1)); } diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index 1efd18d3ae035..ddd2120cd913b 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -3696,7 +3696,7 @@ fn six_session_delay() { fn test_nominators_are_rewarded_for_all_exposure_page() { ExtBuilder::default().build_and_execute(|| { // enable multi paged rewards payout - allow_exposure_pages(3); + allow_paged_rewards(3); // 3 pages of exposure let nominator_count = 2 * MaxNominatorRewardedPerValidator::get() + 1; @@ -3747,7 +3747,7 @@ fn test_multi_page_payout_stakers_by_page() { // Test that payout_stakers work in general and that it pays the correct amount of reward. ExtBuilder::default().has_stakers(false).build_and_execute(|| { // enable multi paged rewards payout - allow_exposure_pages(10); + allow_paged_rewards(10); let balance = 1000; // Track the exposure of the validator and all nominators. @@ -3940,7 +3940,7 @@ fn test_multi_page_payout_stakers_backward_compatible() { // Test that payout_stakers work in general and that it pays the correct amount of reward. ExtBuilder::default().has_stakers(false).build_and_execute(|| { // enable multi paged rewards payout - allow_exposure_pages(10); + allow_paged_rewards(10); let balance = 1000; // Track the exposure of the validator and all nominators. @@ -4170,7 +4170,7 @@ fn payout_stakers_handles_basic_errors() { // Here we will test payouts handle all errors. ExtBuilder::default().has_stakers(false).build_and_execute(|| { // enable multi paged rewards payout - allow_exposure_pages(2); + allow_paged_rewards(2); // Consumed weight for all payout_stakers dispatches that fail let err_weight = ::WeightInfo::payout_stakers_alive_staked(0); @@ -4305,7 +4305,7 @@ fn payout_stakers_handles_basic_errors() { fn test_commission_paid_across_pages() { ExtBuilder::default().has_stakers(false).build_and_execute(|| { // enable multi paged rewards payout - allow_exposure_pages(4); + allow_paged_rewards(4); let balance = 1; let commission = 50; @@ -6225,7 +6225,7 @@ fn test_legacy_claimed_rewards_is_checked_at_reward_payout() { fn test_validator_exposure_is_backward_compatible_with_non_paged_rewards_payout() { ExtBuilder::default().has_stakers(false).build_and_execute(|| { // enable multi paged rewards payout - allow_exposure_pages(2); + allow_paged_rewards(2); // case 1: exposure exist in clipped. // set page cap to 10 From 77ba7dfd8f07fe9ac22da14e17f775eed17649c6 Mon Sep 17 00:00:00 2001 From: Ankan Date: Sun, 12 Feb 2023 21:51:19 +0100 Subject: [PATCH 124/162] test for page size and count --- frame/staking/src/pallet/mod.rs | 1 - frame/staking/src/tests.rs | 75 ++++++++++++++++++++++++++++++++- 2 files changed, 74 insertions(+), 2 deletions(-) diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index bfbd0f6cf2359..d87b6804905fa 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -796,7 +796,6 @@ pub mod pallet { let page_size = >::get() .unwrap_or_else(|| T::MaxNominatorRewardedPerValidator::get()) .clamp(1, T::MaxNominatorRewardedPerValidator::get()); - let max_page_count = Self::get_max_exposure_page_count(); let nominator_count = exposure.others.len(); diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index ddd2120cd913b..8d30b2f7a225c 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -3935,7 +3935,6 @@ fn test_multi_page_payout_stakers_by_page() { } #[test] -//todo fn test_multi_page_payout_stakers_backward_compatible() { // Test that payout_stakers work in general and that it pays the correct amount of reward. ExtBuilder::default().has_stakers(false).build_and_execute(|| { @@ -4165,6 +4164,80 @@ fn test_multi_page_payout_stakers_backward_compatible() { }); } +#[test] +fn test_page_count_and_size() { + // Test that payout_stakers work in general and that it pays the correct amount of reward. + ExtBuilder::default().has_stakers(false).build_and_execute(|| { + let balance = 1000; + // Track the exposure of the validator and all nominators. + // Create a validator: + bond_validator(11, 10, balance); // Default(64) + assert_eq!(Validators::::count(), 1); + + // Create nominators, targeting stash of validators + for i in 0..100 { + let bond_amount = balance + i as Balance; + bond_nominator(1000 + i, 100 + i, bond_amount, vec![11]); + } + + mock::start_active_era(1); + + // Since max exposure page count is 1, we should only have 1 page with clipped and sorted + // nominators. + assert_eq!(EraInfo::::get_page_count(1, &11), 1); + let exposure = EraInfo::::get_validator_exposure(1, &11, 0).unwrap(); + let mut previous_nominator_balance: Balance = u32::MAX as Balance; + exposure.others().iter().for_each(|e| { + // Nominators are sorted by balance in descending order. + assert!(e.value < previous_nominator_balance); + previous_nominator_balance = e.value; + }); + + // the last nominator balance is higher than the last 36 clipped nominators. + assert_eq!(previous_nominator_balance, 1000 + 36); + + // increase max page size + allow_paged_rewards(10); + mock::start_active_era(2); + + assert_eq!(EraInfo::::get_page_count(2, &11), 2); + // first page has 64 nominators + assert_eq!(EraInfo::::get_validator_exposure(2, &11, 0).unwrap().others().len(), 64); + // second page has 36 nominators + assert_eq!(EraInfo::::get_validator_exposure(2, &11, 1).unwrap().others().len(), 36); + + // now lets decrease page size + ExposurePageSize::::put(32); + mock::start_active_era(3); + // now we expect 4 pages. + assert_eq!(EraInfo::::get_page_count(3, &11), 4); + // first 3 pages have 32 nominators each + assert_eq!(EraInfo::::get_validator_exposure(3, &11, 0).unwrap().others().len(), 32); + assert_eq!(EraInfo::::get_validator_exposure(3, &11, 1).unwrap().others().len(), 32); + assert_eq!(EraInfo::::get_validator_exposure(3, &11, 2).unwrap().others().len(), 32); + assert_eq!(EraInfo::::get_validator_exposure(3, &11, 3).unwrap().others().len(), 4); + + // now lets decrease page size even more + ExposurePageSize::::put(9); + mock::start_active_era(4); + // now we expect the max 10 pages with each page having 9 nominators. + assert_eq!(EraInfo::::get_page_count(4, &11), 10); + + // all nominators are sorted by balance in descending order. + let mut previous_nominator_balance: Balance = u32::MAX as Balance; + for page in 0..10 { + let exposure = EraInfo::::get_validator_exposure(4, &11, page).unwrap(); + exposure.others().iter().for_each(|e| { + assert!(e.value < previous_nominator_balance); + previous_nominator_balance = e.value; + }); + } + + // the last nominator balance is higher than the last 10 clipped nominators. + assert_eq!(previous_nominator_balance, 1000 + 10); + }); +} + #[test] fn payout_stakers_handles_basic_errors() { // Here we will test payouts handle all errors. From ff965e2551399df0d6fdcf4c285d7ec2b1b61eaa Mon Sep 17 00:00:00 2001 From: Ankan Date: Sun, 12 Feb 2023 21:58:46 +0100 Subject: [PATCH 125/162] add the old test back --- frame/staking/src/tests.rs | 39 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index 8d30b2f7a225c..1a3a0ae31d5fa 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -3692,6 +3692,45 @@ fn six_session_delay() { }); } +#[test] +fn test_max_nominator_rewarded_per_validator_and_cant_steal_someone_else_reward() { + // with max exposure page count set to 1, clipped exposure logic works exactly as before. + ExtBuilder::default().build_and_execute(|| { + for i in 0..=MaxNominatorRewardedPerValidator::get() { + let stash = 10_000 + i as AccountId; + let controller = 20_000 + i as AccountId; + let balance = 10_000 + i as Balance; + Balances::make_free_balance_be(&stash, balance); + assert_ok!(Staking::bond( + RuntimeOrigin::signed(stash), + controller, + balance, + RewardDestination::Stash + )); + assert_ok!(Staking::nominate(RuntimeOrigin::signed(controller), vec![11])); + } + mock::start_active_era(1); + + Pallet::::reward_by_ids(vec![(11, 1)]); + // compute and ensure the reward amount is greater than zero. + let _ = current_total_payout_for_duration(reward_time_per_era()); + + mock::start_active_era(2); + mock::make_all_reward_payment(1); + + // Assert only nominators from 1 to Max are rewarded + for i in 0..=MaxNominatorRewardedPerValidator::get() { + let stash = 10_000 + i as AccountId; + let balance = 10_000 + i as Balance; + if stash == 10_000 { + assert!(Balances::free_balance(&stash) == balance); + } else { + assert!(Balances::free_balance(&stash) > balance); + } + } + }); +} + #[test] fn test_nominators_are_rewarded_for_all_exposure_page() { ExtBuilder::default().build_and_execute(|| { From 8a608f95ae6e98966b81af9b4a1d4f89f91cc334 Mon Sep 17 00:00:00 2001 From: Ankan Date: Mon, 13 Feb 2023 00:10:23 +0100 Subject: [PATCH 126/162] update changelog --- frame/staking/CHANGELOG.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/frame/staking/CHANGELOG.md b/frame/staking/CHANGELOG.md index 01630c1270be4..1854f2c9094c2 100644 --- a/frame/staking/CHANGELOG.md +++ b/frame/staking/CHANGELOG.md @@ -18,6 +18,8 @@ as a minor version bump. - Unlimited number of nominators can be rewarded. - New storage item `ExposurePageSize` to limit the number of nominators rewarded for a single call for reward payout. +- New storage item `MaxExposurePageCount` to limit the maximum number of exposure pages that can be created. If this +- value is not set, it defaults to 1, resulting in the same behaviour as we have today with clipped exposures. - New storage item `ErasStakersPaged` that keeps upto `ExposurePageSize` individual nominator exposures by era, validator and page. - New storage item `ErasStakersOverview` which complements `ErasStakersPaged` and keeps track of validator's own stake and total backing stake for each era. - New call `payout_stakers_by_page` that allows to payout rewards for a single validator by passing the page explicitly. @@ -31,5 +33,5 @@ as a minor version bump. - `ErasStakersClipped` is deprecated in favor of `ErasStakersPaged`. In 84 eras, `ErasStakersClipped` will be removed. - `StakingLedger.claimed_rewards` is renamed to `StakingLedger.legacy_claimed_rewards` and is deprecated. -### PRs -[#13059](https://github.com/paritytech/substrate/pull/13059) + +[5.0.0]: https://github.com/paritytech/substrate/pull/13059 From 397e5d22eb74c556aa72ce175b0eadbc94f1294d Mon Sep 17 00:00:00 2001 From: Ankan Date: Tue, 14 Feb 2023 23:02:29 +0100 Subject: [PATCH 127/162] remove duplicate test --- client/db/src/lib.rs | 43 ------------------------------------------- 1 file changed, 43 deletions(-) diff --git a/client/db/src/lib.rs b/client/db/src/lib.rs index 935b70e79670d..579cb76d47c2b 100644 --- a/client/db/src/lib.rs +++ b/client/db/src/lib.rs @@ -3559,49 +3559,6 @@ pub(crate) mod tests { assert_eq!(Some(vec![0x3a.into()]), bc.body(block_3a).unwrap()); } - #[test] - fn prune_blocks_on_finalize_and_reorg() { - // 0 - 1b - // \ - 1a - 2a - 3a - // \ - 2b - - let backend = Backend::::new_test_with_tx_storage(BlocksPruning::Some(10), 10); - - let make_block = |index, parent, val: u64| { - insert_block(&backend, index, parent, None, H256::random(), vec![val.into()], None) - .unwrap() - }; - - let block_0 = make_block(0, Default::default(), 0x00); - let block_1a = make_block(1, block_0, 0x1a); - let block_1b = make_block(1, block_0, 0x1b); - let block_2a = make_block(2, block_1a, 0x2a); - let block_2b = make_block(2, block_1a, 0x2b); - let block_3a = make_block(3, block_2a, 0x3a); - - // Make sure 1b is head - let mut op = backend.begin_operation().unwrap(); - backend.begin_state_operation(&mut op, block_0).unwrap(); - op.mark_head(block_1b).unwrap(); - backend.commit_operation(op).unwrap(); - - // Finalize 3a - let mut op = backend.begin_operation().unwrap(); - backend.begin_state_operation(&mut op, block_0).unwrap(); - op.mark_head(block_3a).unwrap(); - op.mark_finalized(block_1a, None).unwrap(); - op.mark_finalized(block_2a, None).unwrap(); - op.mark_finalized(block_3a, None).unwrap(); - backend.commit_operation(op).unwrap(); - - let bc = backend.blockchain(); - assert_eq!(None, bc.body(block_1b).unwrap()); - assert_eq!(None, bc.body(block_2b).unwrap()); - assert_eq!(Some(vec![0x00.into()]), bc.body(block_0).unwrap()); - assert_eq!(Some(vec![0x1a.into()]), bc.body(block_1a).unwrap()); - assert_eq!(Some(vec![0x2a.into()]), bc.body(block_2a).unwrap()); - assert_eq!(Some(vec![0x3a.into()]), bc.body(block_3a).unwrap()); - } #[test] fn indexed_data_block_body() { From 73630b4f0bdc2a8dad1685da2783eaa358d9b579 Mon Sep 17 00:00:00 2001 From: Ankan Date: Wed, 15 Feb 2023 19:09:50 +0100 Subject: [PATCH 128/162] todo tags --- frame/staking/CHANGELOG.md | 1 + frame/staking/src/pallet/mod.rs | 1 + 2 files changed, 2 insertions(+) diff --git a/frame/staking/CHANGELOG.md b/frame/staking/CHANGELOG.md index 1854f2c9094c2..263f5f6acf2d5 100644 --- a/frame/staking/CHANGELOG.md +++ b/frame/staking/CHANGELOG.md @@ -12,6 +12,7 @@ this guarantee: For example adding a new field to an in-storage data structure w changes to frontends to properly display it. However, those changes will still be regarded as a minor version bump. +[//]: # TODO(ank4n) these versions should be same as storage version ## [5.0.0] - UNRELEASED ### Added diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index be557c874dca2..5738c57282aab 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -64,6 +64,7 @@ pub mod pallet { use super::*; /// The current storage version. + /// TODO(ank4n) bump up const STORAGE_VERSION: StorageVersion = StorageVersion::new(13); #[pallet::pallet] From cb59ca7e9af918499e62b4d30e719fc8aad8c043 Mon Sep 17 00:00:00 2001 From: Ankan Date: Wed, 15 Feb 2023 19:25:54 +0100 Subject: [PATCH 129/162] some renames and config vals --- bin/node/runtime/src/lib.rs | 6 +- frame/babe/src/mock.rs | 2 +- frame/fast-unstake/src/mock.rs | 2 +- frame/grandpa/src/mock.rs | 2 +- .../nomination-pools/benchmarking/src/mock.rs | 2 +- .../nomination-pools/test-staking/src/mock.rs | 2 +- frame/offences/benchmarking/src/mock.rs | 2 +- frame/root-offences/src/mock.rs | 2 +- frame/session/benchmarking/src/mock.rs | 2 +- frame/staking/CHANGELOG.md | 2 +- frame/staking/README.md | 2 +- frame/staking/src/benchmarking.rs | 12 +-- frame/staking/src/lib.rs | 4 +- frame/staking/src/mock.rs | 8 +- frame/staking/src/pallet/impls.rs | 2 +- frame/staking/src/pallet/mod.rs | 75 ++++++++----------- frame/staking/src/tests.rs | 18 ++--- 17 files changed, 66 insertions(+), 79 deletions(-) diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 2c7969ebcd6b9..de53bd958b9c4 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -535,7 +535,7 @@ parameter_types! { pub const BondingDuration: sp_staking::EraIndex = 24 * 28; pub const SlashDeferDuration: sp_staking::EraIndex = 24 * 7; // 1/4 the bonding duration. pub const RewardCurve: &'static PiecewiseLinear<'static> = &REWARD_CURVE; - pub const MaxNominatorRewardedPerValidator: u32 = 256; + pub const MaxExposurePageSize: u32 = 256; pub const OffendingValidatorsThreshold: Perbill = Perbill::from_percent(17); pub OffchainRepeat: BlockNumber = 5; pub HistoryDepth: u32 = 84; @@ -568,7 +568,7 @@ impl pallet_staking::Config for Runtime { type SessionInterface = Self; type EraPayout = pallet_staking::ConvertCurve; type NextNewSession = Session; - type MaxNominatorRewardedPerValidator = MaxNominatorRewardedPerValidator; + type MaxExposurePageSize = MaxExposurePageSize; type OffendingValidatorsThreshold = OffendingValidatorsThreshold; type ElectionProvider = ElectionProviderMultiPhase; type GenesisElectionProvider = onchain::OnChainExecution; @@ -591,7 +591,7 @@ impl pallet_fast_unstake::Config for Runtime { type Staking = Staking; type MaxErasToCheckPerBlock = ConstU32<1>; #[cfg(feature = "runtime-benchmarks")] - type MaxBackersPerValidator = MaxNominatorRewardedPerValidator; + type MaxBackersPerValidator = MaxExposurePageSize; type WeightInfo = (); } diff --git a/frame/babe/src/mock.rs b/frame/babe/src/mock.rs index b09dc29f6d60a..698a2bfa623bf 100644 --- a/frame/babe/src/mock.rs +++ b/frame/babe/src/mock.rs @@ -192,7 +192,7 @@ impl pallet_staking::Config for Test { type SessionInterface = Self; type UnixTime = pallet_timestamp::Pallet; type EraPayout = pallet_staking::ConvertCurve; - type MaxNominatorRewardedPerValidator = ConstU32<64>; + type MaxExposurePageSize = ConstU32<64>; type OffendingValidatorsThreshold = OffendingValidatorsThreshold; type NextNewSession = Session; type ElectionProvider = onchain::OnChainExecution; diff --git a/frame/fast-unstake/src/mock.rs b/frame/fast-unstake/src/mock.rs index 38cf41fdebe8b..6e19483b5a365 100644 --- a/frame/fast-unstake/src/mock.rs +++ b/frame/fast-unstake/src/mock.rs @@ -146,7 +146,7 @@ impl pallet_staking::Config for Runtime { type EraPayout = pallet_staking::ConvertCurve; type NextNewSession = (); type HistoryDepth = ConstU32<84>; - type MaxNominatorRewardedPerValidator = ConstU32<64>; + type MaxExposurePageSize = ConstU32<64>; type OffendingValidatorsThreshold = (); type ElectionProvider = MockElection; type GenesisElectionProvider = Self::ElectionProvider; diff --git a/frame/grandpa/src/mock.rs b/frame/grandpa/src/mock.rs index 7d54966a498a6..09641ea3fe9d7 100644 --- a/frame/grandpa/src/mock.rs +++ b/frame/grandpa/src/mock.rs @@ -196,7 +196,7 @@ impl pallet_staking::Config for Test { type SessionInterface = Self; type UnixTime = pallet_timestamp::Pallet; type EraPayout = pallet_staking::ConvertCurve; - type MaxNominatorRewardedPerValidator = ConstU32<64>; + type MaxExposurePageSize = ConstU32<64>; type OffendingValidatorsThreshold = OffendingValidatorsThreshold; type NextNewSession = Session; type ElectionProvider = onchain::OnChainExecution; diff --git a/frame/nomination-pools/benchmarking/src/mock.rs b/frame/nomination-pools/benchmarking/src/mock.rs index 06a66838594c7..2d5dff7715196 100644 --- a/frame/nomination-pools/benchmarking/src/mock.rs +++ b/frame/nomination-pools/benchmarking/src/mock.rs @@ -107,7 +107,7 @@ impl pallet_staking::Config for Runtime { type SessionInterface = (); type EraPayout = pallet_staking::ConvertCurve; type NextNewSession = (); - type MaxNominatorRewardedPerValidator = ConstU32<64>; + type MaxExposurePageSize = ConstU32<64>; type OffendingValidatorsThreshold = (); type ElectionProvider = frame_election_provider_support::NoElection<(AccountId, BlockNumber, Staking, ())>; diff --git a/frame/nomination-pools/test-staking/src/mock.rs b/frame/nomination-pools/test-staking/src/mock.rs index c67aec0134b07..c9cd3dd945902 100644 --- a/frame/nomination-pools/test-staking/src/mock.rs +++ b/frame/nomination-pools/test-staking/src/mock.rs @@ -121,7 +121,7 @@ impl pallet_staking::Config for Runtime { type SessionInterface = (); type EraPayout = pallet_staking::ConvertCurve; type NextNewSession = (); - type MaxNominatorRewardedPerValidator = ConstU32<64>; + type MaxExposurePageSize = ConstU32<64>; type OffendingValidatorsThreshold = (); type ElectionProvider = frame_election_provider_support::NoElection<(AccountId, BlockNumber, Staking, ())>; diff --git a/frame/offences/benchmarking/src/mock.rs b/frame/offences/benchmarking/src/mock.rs index 592e821a81d8c..26138fca5ed45 100644 --- a/frame/offences/benchmarking/src/mock.rs +++ b/frame/offences/benchmarking/src/mock.rs @@ -170,7 +170,7 @@ impl pallet_staking::Config for Test { type SessionInterface = Self; type EraPayout = pallet_staking::ConvertCurve; type NextNewSession = Session; - type MaxNominatorRewardedPerValidator = ConstU32<64>; + type MaxExposurePageSize = ConstU32<64>; type OffendingValidatorsThreshold = (); type ElectionProvider = onchain::OnChainExecution; type GenesisElectionProvider = Self::ElectionProvider; diff --git a/frame/root-offences/src/mock.rs b/frame/root-offences/src/mock.rs index 273fbf614169d..b2934110e9e02 100644 --- a/frame/root-offences/src/mock.rs +++ b/frame/root-offences/src/mock.rs @@ -184,7 +184,7 @@ impl pallet_staking::Config for Test { type SessionInterface = Self; type EraPayout = pallet_staking::ConvertCurve; type NextNewSession = Session; - type MaxNominatorRewardedPerValidator = ConstU32<64>; + type MaxExposurePageSize = ConstU32<64>; type OffendingValidatorsThreshold = OffendingValidatorsThreshold; type ElectionProvider = onchain::OnChainExecution; type GenesisElectionProvider = Self::ElectionProvider; diff --git a/frame/session/benchmarking/src/mock.rs b/frame/session/benchmarking/src/mock.rs index 0699640bc092a..ecb07d31102d9 100644 --- a/frame/session/benchmarking/src/mock.rs +++ b/frame/session/benchmarking/src/mock.rs @@ -172,7 +172,7 @@ impl pallet_staking::Config for Test { type SessionInterface = Self; type EraPayout = pallet_staking::ConvertCurve; type NextNewSession = Session; - type MaxNominatorRewardedPerValidator = ConstU32<64>; + type MaxExposurePageSize = ConstU32<64>; type OffendingValidatorsThreshold = (); type ElectionProvider = onchain::OnChainExecution; type GenesisElectionProvider = Self::ElectionProvider; diff --git a/frame/staking/CHANGELOG.md b/frame/staking/CHANGELOG.md index 263f5f6acf2d5..4345c9f261a28 100644 --- a/frame/staking/CHANGELOG.md +++ b/frame/staking/CHANGELOG.md @@ -28,7 +28,7 @@ as a minor version bump. ### Changed - `payout_stakers` can be called multiple times for the same era if the validator has more than `ExposurePageSize` nominators backing them. -- `MaxNominatorRewardedPerValidator` is renamed to `MaxExposurePageSize`. +- `MaxExposurePageSize` is renamed to `MaxExposurePageSize`. ### Deprecated - `ErasStakersClipped` is deprecated in favor of `ErasStakersPaged`. In 84 eras, `ErasStakersClipped` will be removed. diff --git a/frame/staking/README.md b/frame/staking/README.md index 043dc2088c0c1..d09f777ac8bbf 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 [`HistoryDeth`] using the `payout_stakers` call. Any account can call `payout_stakers`, which pays the reward to the -validator as well as its nominators. Rewards are paged to maximum of [`Config::MaxNominatorRewardedPerValidator`] +validator as well as its nominators. Rewards are paged to maximum of [`Config::MaxExposurePageSize`] nominators per call. Each page of staker payout needs to be called separately to ensure all nominators are paid. This is to limit the i/o cost to mutate storage for each nominator's account. diff --git a/frame/staking/src/benchmarking.rs b/frame/staking/src/benchmarking.rs index 8ff3ba8ad21c2..f0740e7a57c12 100644 --- a/frame/staking/src/benchmarking.rs +++ b/frame/staking/src/benchmarking.rs @@ -546,10 +546,10 @@ benchmarks! { } payout_stakers_dead_controller { - let n in 0 .. T::MaxNominatorRewardedPerValidator::get() as u32; + let n in 0 .. T::MaxExposurePageSize::get() as u32; let (validator, nominators) = create_validator_with_nominators::( n, - T::MaxNominatorRewardedPerValidator::get() as u32, + T::MaxExposurePageSize::get() as u32, true, RewardDestination::Controller, )?; @@ -579,10 +579,10 @@ benchmarks! { } payout_stakers_alive_staked { - let n in 0 .. T::MaxNominatorRewardedPerValidator::get() as u32; + let n in 0 .. T::MaxExposurePageSize::get() as u32; let (validator, nominators) = create_validator_with_nominators::( n, - T::MaxNominatorRewardedPerValidator::get() as u32, + T::MaxExposurePageSize::get() as u32, false, RewardDestination::Staked, )?; @@ -976,7 +976,7 @@ mod tests { let (validator_stash, nominators) = create_validator_with_nominators::( n, - <::MaxNominatorRewardedPerValidator as Get<_>>::get(), + <::MaxExposurePageSize as Get<_>>::get(), false, RewardDestination::Staked, ) @@ -1006,7 +1006,7 @@ mod tests { let (validator_stash, _nominators) = create_validator_with_nominators::( n, - <::MaxNominatorRewardedPerValidator as Get<_>>::get(), + <::MaxExposurePageSize as Get<_>>::get(), false, RewardDestination::Staked, ) diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index 9bb3223c741b0..21122255c05eb 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::MaxExposurePageSize`] //! biggest stakers can claim their reward. This is to limit the i/o cost to mutate storage for each //! nominator's account. //! @@ -228,7 +228,7 @@ //! validator, proportional to the value staked behind the validator (_i.e._ dividing the //! [`own`](Exposure::own) or [`others`](Exposure::others) by [`total`](Exposure::total) in //! [`Exposure`]). Note that payouts are made in pages with each page capped at -//! [`Config::MaxNominatorRewardedPerValidator`] nominators. The distribution of nominators across +//! [`Config::MaxExposurePageSize`] nominators. The distribution of nominators across //! pages are unsorted and depends on the election result provided by [`Config::ElectionProvider`]. //! //! All entities who receive a reward have the option to choose their reward destination through the diff --git a/frame/staking/src/mock.rs b/frame/staking/src/mock.rs index 27e1d75e71675..16f77bafc13e9 100644 --- a/frame/staking/src/mock.rs +++ b/frame/staking/src/mock.rs @@ -230,7 +230,8 @@ parameter_types! { pub static BagThresholds: &'static [sp_npos_elections::VoteWeight] = &THRESHOLDS; pub static MaxNominations: u32 = 16; pub static HistoryDepth: u32 = 80; - pub static MaxNominatorRewardedPerValidator: u32 = 64; + pub static MaxExposurePageSize: u32 = 64; + pub static MaxExposurePageCount: u32 = 1; pub static MaxUnlockingChunks: u32 = 32; pub static RewardOnUnbalanceWasCalled: bool = false; pub static LedgerSlashPerEra: (BalanceOf, BTreeMap>) = (Zero::zero(), BTreeMap::new()); @@ -293,7 +294,8 @@ impl crate::pallet::pallet::Config for Test { type SessionInterface = Self; type EraPayout = ConvertCurve; type NextNewSession = Session; - type MaxNominatorRewardedPerValidator = MaxNominatorRewardedPerValidator; + type MaxExposurePageSize = MaxExposurePageSize; + type MaxExposurePageCount = MaxExposurePageCount; type OffendingValidatorsThreshold = OffendingValidatorsThreshold; type ElectionProvider = onchain::OnChainExecution; type GenesisElectionProvider = Self::ElectionProvider; @@ -821,5 +823,5 @@ pub(crate) fn balances(who: &AccountId) -> (Balance, Balance) { } pub(crate) fn allow_paged_rewards(max_pages: u32) { - MaxExposurePageCount::::put(max_pages.max(1)); + MaxExposurePageCount::set(max_pages.max(1)); } diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index 7e5f4415267b7..5f2c1848a0f8c 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -285,7 +285,7 @@ impl Pallet { } T::Reward::on_unbalanced(total_imbalance); - debug_assert!(nominator_payout_count <= T::MaxNominatorRewardedPerValidator::get()); + debug_assert!(nominator_payout_count <= T::MaxExposurePageSize::get()); Ok(Some(T::WeightInfo::payout_stakers_alive_staked(nominator_payout_count)).into()) } diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index 5738c57282aab..e55ac7b4031f2 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -204,22 +204,26 @@ pub mod pallet { /// The maximum size of each `T::ExposurePage`. /// - /// An `ExposurePage` is bounded to a maximum of `MaxNominatorRewardedPerValidator` + /// An `ExposurePage` is bounded to a maximum of `MaxExposurePageSize` /// nominators. The actual page size is a dynamic value that is determined by the storage /// item `T::ExposurePageSize`. /// /// For older non-paged exposure, a reward payout was restricted to the top - /// `MaxNominatorRewardedPerValidator` nominators. This is to limit the i/o cost for the + /// `MaxExposurePageSize` nominators. This is to limit the i/o cost for the /// nominator payout. /// - /// The name is a bit misleading, because historically we used to reward the top - /// `MaxNominatorRewardedPerValidator` nominators by stake when we did not had paged - /// exposures. In future we should rename this to something like `ExposurePageSize` when we - /// are ready to get rid of `ErasStakersClipped`. - /// Refer issue: #13034 - /// TODO(ank4n): rename this to `MaxExposurePageSize`. + /// Note: `MaxExposurePageSize` is used to bound `ClaimedRewards` and is unsafe to reduce + /// without handling it in a migration. #[pallet::constant] - type MaxNominatorRewardedPerValidator: Get; + type MaxExposurePageSize: Get; + + /// Maximum number of exposure pages that can be stored for a single validator in an era. + /// + /// Must be greater than 0. + /// + /// When this is set to 1, the reward payout behaviour is similar to how it used to work + /// before we had paged exposures. + type MaxExposurePageCount: Get; /// The fraction of the validator set that is safe to be offending. /// After the threshold is reached a new era will be forced. @@ -456,7 +460,7 @@ pub mod pallet { /// New `Exposure`s are stored in a paged manner in `ErasStakersPaged` instead. /// /// This is similar to [`ErasStakers`] but number of nominators exposed is reduced to the - /// `T::MaxNominatorRewardedPerValidator` biggest stakers. + /// `T::MaxExposurePageSize` 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. /// @@ -479,20 +483,10 @@ pub mod pallet { /// The nominator count each `ExposurePage` is capped at. /// - /// This cannot be greater than `T::MaxNominatorRewardedPerValidator`. + /// This cannot be greater than `T::MaxExposurePageSize`. #[pallet::storage] pub type ExposurePageSize = StorageValue<_, u32, OptionQuery>; - /// Maximum number of exposure pages that can be stored for a single validator in an era. - /// - /// Must be greater than 0. - /// - /// When this is set to 1, the reward payout behaviour is similar to how it used to work before - /// we had paged exposures. - #[pallet::storage] - // TODO(ank4n): Does it need #[pallet::getter(...)] - pub type MaxExposurePageCount = StorageValue<_, PageIndex, OptionQuery>; - /// Paginated exposure of a validator at given era. /// /// This is keyed first by the era index to allow bulk deletion, then the tuple of stash account @@ -753,11 +747,6 @@ pub mod pallet { >::contains_key(&era, validator) } - /// Returns the maximum number of pages of exposure we can store. - fn get_max_exposure_page_count() -> PageIndex { - return >::get().unwrap_or_default().max(1) - } - /// Returns validator commission for this era and page. pub(crate) fn get_validator_commission( era: EraIndex, @@ -795,16 +784,16 @@ pub mod pallet { >::insert(era, &validator, &exposure); let page_size = >::get() - .unwrap_or_else(|| T::MaxNominatorRewardedPerValidator::get()) - .clamp(1, T::MaxNominatorRewardedPerValidator::get()); - let max_page_count = Self::get_max_exposure_page_count(); + .unwrap_or_else(|| T::MaxExposurePageSize::get()) + .clamp(1, T::MaxExposurePageSize::get()); + let max_page_count = T::MaxExposurePageCount::get(); let nominator_count = exposure.others.len(); - let page_count = + let required_page_count = nominator_count.saturating_add(page_size as usize - 1) / page_size as usize; // clip nominators if it exceeds the maximum page count. - let exposure = if page_count as PageIndex > max_page_count { + let exposure = if required_page_count as PageIndex > max_page_count { // sort before clipping. let mut exposure_clipped = exposure; let clipped_max_len = max_page_count * page_size; @@ -1741,16 +1730,16 @@ pub mod pallet { /// This pays out the earliest exposure page not claimed for the era. If all pages are /// claimed, it returns an error `InvalidPage`. /// - /// If a validator has more than `T::MaxNominatorRewardedPerValidator` nominators backing + /// If a validator has more than `T::MaxExposurePageSize` nominators backing /// them, then the list of nominators is paged, with each page being capped at - /// `T::MaxNominatorRewardedPerValidator`. If a validator has more than one page of + /// `T::MaxExposurePageSize`. If a validator has more than one page of /// nominators, the call needs to be made for each page separately in order for all the /// nominators backing a validator receive the reward. The nominators are not sorted across /// pages and so it should not be assumed the highest staker would be on the topmost page /// and vice versa. If rewards are not claimed in `${HistoryDepth}` eras, they are lost. /// /// # - /// - Time complexity: at most O(MaxNominatorRewardedPerValidator). + /// - Time complexity: at most O(MaxExposurePageSize). /// - Contains a limited number of reads and writes. /// ----------- /// N is the Number of payouts for the validator (including the validator) @@ -1762,11 +1751,9 @@ pub mod pallet { /// Paying even a dead controller is cheaper weight-wise. We don't do any refunds here. /// # /// ## Complexity - /// - At most O(MaxNominatorRewardedPerValidator). + /// - At most O(MaxExposurePageSize). #[pallet::call_index(18)] - #[pallet::weight(T::WeightInfo::payout_stakers_alive_staked( - T::MaxNominatorRewardedPerValidator::get() - ))] + #[pallet::weight(T::WeightInfo::payout_stakers_alive_staked(T::MaxExposurePageSize::get()))] pub fn payout_stakers( origin: OriginFor, validator_stash: T::AccountId, @@ -2069,21 +2056,21 @@ pub mod pallet { /// - `validator_stash` is the stash account of the validator. /// - `era` may be any era between `[current_era - history_depth; current_era]`. /// - `page` is the page index of nominators to pay out with value between 0 and - /// `num_nominators / T::MaxNominatorRewardedPerValidator`. + /// `num_nominators / T::MaxExposurePageSize`. /// /// The origin of this call must be _Signed_. Any account can call this function, even if /// it is not one of the stakers. /// - /// If a validator has more than `T::MaxNominatorRewardedPerValidator` nominators backing + /// If a validator has more than `T::MaxExposurePageSize` nominators backing /// them, then the list of nominators is paged, with each page being capped at - /// `T::MaxNominatorRewardedPerValidator`. If a validator has more than one page of + /// `T::MaxExposurePageSize`. If a validator has more than one page of /// nominators, the call needs to be made for each page separately in order for all the /// nominators backing a validator receive the reward. The nominators are not sorted across /// pages and so it should not be assumed the highest staker would be on the topmost page /// and vice versa. If rewards are not claimed in `${HistoryDepth}` eras, they are lost. /// /// # - /// - Time complexity: at most O(MaxNominatorRewardedPerValidator). + /// - Time complexity: at most O(MaxExposurePageSize). /// - Contains a limited number of reads and writes. /// ----------- /// N is the Number of payouts for the validator (including the validator) @@ -2095,9 +2082,7 @@ pub mod pallet { /// Paying even a dead controller is cheaper weight-wise. We don't do any refunds here. /// # #[pallet::call_index(26)] - #[pallet::weight(T::WeightInfo::payout_stakers_alive_staked( - T::MaxNominatorRewardedPerValidator::get() - ))] + #[pallet::weight(T::WeightInfo::payout_stakers_alive_staked(T::MaxExposurePageSize::get()))] pub fn payout_stakers_by_page( origin: OriginFor, validator_stash: T::AccountId, diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index 1a3a0ae31d5fa..6460c554ca229 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -2196,7 +2196,7 @@ fn reward_validator_slashing_validator_does_not_overflow() { let exposure = Exposure:: { total: stake, own: stake, others: vec![] }; let (exposure_overview, _) = - exposure.clone().into_pages(MaxNominatorRewardedPerValidator::get()); + exposure.clone().into_pages(MaxExposurePageSize::get()); let reward = EraRewardPoints:: { total: 1, individual: vec![(11, 1)].into_iter().collect(), @@ -3696,7 +3696,7 @@ fn six_session_delay() { fn test_max_nominator_rewarded_per_validator_and_cant_steal_someone_else_reward() { // with max exposure page count set to 1, clipped exposure logic works exactly as before. ExtBuilder::default().build_and_execute(|| { - for i in 0..=MaxNominatorRewardedPerValidator::get() { + for i in 0..=MaxExposurePageSize::get() { let stash = 10_000 + i as AccountId; let controller = 20_000 + i as AccountId; let balance = 10_000 + i as Balance; @@ -3719,7 +3719,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..=MaxExposurePageSize::get() { let stash = 10_000 + i as AccountId; let balance = 10_000 + i as Balance; if stash == 10_000 { @@ -3738,7 +3738,7 @@ fn test_nominators_are_rewarded_for_all_exposure_page() { allow_paged_rewards(3); // 3 pages of exposure - let nominator_count = 2 * MaxNominatorRewardedPerValidator::get() + 1; + let nominator_count = 2 * MaxExposurePageSize::get() + 1; for i in 0..nominator_count { let stash = 10_000 + i as AccountId; @@ -3806,7 +3806,7 @@ fn test_multi_page_payout_stakers_by_page() { mock::start_active_era(1); Staking::reward_by_ids(vec![(11, 1)]); - // Since `MaxNominatorRewardedPerValidator = 64`, there are two pages of validator exposure. + // Since `MaxExposurePageSize = 64`, there are two pages of validator exposure. assert_eq!(EraInfo::::get_page_count(1, &11), 2); // compute and ensure the reward amount is greater than zero. @@ -4000,7 +4000,7 @@ fn test_multi_page_payout_stakers_backward_compatible() { mock::start_active_era(1); Staking::reward_by_ids(vec![(11, 1)]); - // Since `MaxNominatorRewardedPerValidator = 64`, there are two pages of validator exposure. + // Since `MaxExposurePageSize = 64`, there are two pages of validator exposure. assert_eq!(EraInfo::::get_page_count(1, &11), 2); // compute and ensure the reward amount is greater than zero. @@ -4438,7 +4438,7 @@ fn test_commission_paid_across_pages() { mock::start_active_era(1); Staking::reward_by_ids(vec![(11, 1)]); - // Since `MaxNominatorRewardedPerValidator = 64`, there are four pages of validator + // Since `MaxExposurePageSize = 64`, there are four pages of validator // exposure. assert_eq!(EraInfo::::get_page_count(1, &11), 4); @@ -4473,7 +4473,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 = MaxExposurePageSize::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; @@ -6341,7 +6341,7 @@ fn test_validator_exposure_is_backward_compatible_with_non_paged_rewards_payout( // case 1: exposure exist in clipped. // set page cap to 10 - MaxNominatorRewardedPerValidator::set(10); + MaxExposurePageSize::set(10); bond_validator(11, 10, 1000); let mut expected_individual_exposures: Vec> = vec![]; let mut total_exposure: Balance = 0; From a82b0bdbd944efc6c2656fb8fac7145fd529b8d6 Mon Sep 17 00:00:00 2001 From: Ankan Date: Wed, 15 Feb 2023 19:33:33 +0100 Subject: [PATCH 130/162] do not iterate twice --- frame/staking/src/lib.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index 21122255c05eb..a8824d5890169 100644 --- a/frame/staking/src/lib.rs +++ b/frame/staking/src/lib.rs @@ -746,16 +746,15 @@ impl for chunk in individual_chunks { let mut page_total: Balance = Zero::zero(); + let mut others: Vec> = vec![]; for individual in chunk.iter() { page_total = page_total.saturating_add(individual.value); + others.push(IndividualExposure { who: individual.who.clone(), value: individual.value }) } exposure_pages.push(ExposurePage { page_total, - others: chunk - .iter() - .map(|c| IndividualExposure { who: c.who.clone(), value: c.value }) - .collect(), + others, }); } From e8ebbbcd177787ded8527edc8d7951d778688dba Mon Sep 17 00:00:00 2001 From: Ankan Date: Wed, 15 Feb 2023 19:34:51 +0100 Subject: [PATCH 131/162] rename --- frame/staking/src/lib.rs | 4 ++-- frame/staking/src/pallet/impls.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index a8824d5890169..1be6c33bc0f82 100644 --- a/frame/staking/src/lib.rs +++ b/frame/staking/src/lib.rs @@ -845,8 +845,8 @@ impl ExposureExt Balance { + /// Returns total exposure of this validator for the current page + pub fn page_total(&self) -> Balance { self.exposure_page.page_total + self.exposure_overview.own } diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index 5f2c1848a0f8c..1206ecb4c32af 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -240,7 +240,7 @@ impl Pallet { // Now let's calculate how this is split to the validator. let validator_exposure_part = Perbill::from_rational(exposure.own(), exposure.total()); let validator_staking_payout = validator_exposure_part * validator_leftover_payout; - let page_stake_part = Perbill::from_rational(exposure.current_total(), exposure.total()); + let page_stake_part = Perbill::from_rational(exposure.page_total(), exposure.total()); // validator commission is paid out in fraction across pages proportional to the page stake. let validator_commission_payout = page_stake_part * validator_total_commission_payout; From 9a959e49266e1e72f3e170058d8641478370eb91 Mon Sep 17 00:00:00 2001 From: Ankan Date: Wed, 15 Feb 2023 19:36:03 +0100 Subject: [PATCH 132/162] clean up --- frame/staking/src/lib.rs | 7 ------- 1 file changed, 7 deletions(-) diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index 1be6c33bc0f82..557612f165f61 100644 --- a/frame/staking/src/lib.rs +++ b/frame/staking/src/lib.rs @@ -777,16 +777,9 @@ pub struct ExposurePage { #[codec(compact)] pub page_total: Balance, /// The portions of nominators stashes that are exposed. - /// TODO(ank4n): BoundedVec touches lot of code, skip for now. pub others: Vec>, } -impl Default for ExposurePage { - fn default() -> Self { - Self { page_total: Default::default(), others: vec![] } - } -} - /// An overview of stake backing a single validator. /// /// It, in combination with a list of `ExposurePage`s, can be used to reconstruct a full `Exposure` From f712e35c8ee3d89e4b76d50832be8957454348b8 Mon Sep 17 00:00:00 2001 From: Ankan Date: Wed, 15 Feb 2023 20:14:25 +0100 Subject: [PATCH 133/162] pr fixes --- frame/staking/CHANGELOG.md | 52 ++++++++++++++++++++++----------- frame/staking/src/lib.rs | 17 +++-------- frame/staking/src/pallet/mod.rs | 2 +- 3 files changed, 40 insertions(+), 31 deletions(-) diff --git a/frame/staking/CHANGELOG.md b/frame/staking/CHANGELOG.md index 4345c9f261a28..a7f5ce7de8f47 100644 --- a/frame/staking/CHANGELOG.md +++ b/frame/staking/CHANGELOG.md @@ -3,36 +3,54 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), -and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). - -The semantic versioning guarantees cover the interface to the substrate runtime which -includes this pallet as a dependency. This module will also add storage migrations whenever -changes require it. Stability with regard to offchain tooling is explicitly excluded from -this guarantee: For example adding a new field to an in-storage data structure will require -changes to frontends to properly display it. However, those changes will still be regarded +and this project adheres +to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +The semantic versioning guarantees cover the interface to the substrate runtime +which +includes this pallet as a dependency. This module will also add storage +migrations whenever +changes require it. Stability with regard to offchain tooling is explicitly +excluded from +this guarantee: For example adding a new field to an in-storage data structure +will require +changes to frontends to properly display it. However, those changes will still +be regarded as a minor version bump. [//]: # TODO(ank4n) these versions should be same as storage version + ## [5.0.0] - UNRELEASED ### Added - Unlimited number of nominators can be rewarded. -- New storage item `ExposurePageSize` to limit the number of nominators rewarded for a single call for reward payout. -- New storage item `MaxExposurePageCount` to limit the maximum number of exposure pages that can be created. If this -- value is not set, it defaults to 1, resulting in the same behaviour as we have today with clipped exposures. -- New storage item `ErasStakersPaged` that keeps upto `ExposurePageSize` individual nominator exposures by era, validator and page. -- New storage item `ErasStakersOverview` which complements `ErasStakersPaged` and keeps track of validator's own stake and total backing stake for each era. -- New call `payout_stakers_by_page` that allows to payout rewards for a single validator by passing the page explicitly. -- New storage item `ClaimedRewards` that keeps track of claimed reward history of a validator by era and page. +- New storage item `ExposurePageSize` to limit the number of nominators rewarded + for a single call for reward payout. +- New config item `MaxExposurePageCount` to limit the maximum number of exposure + pages that can be created. When set + to 1, we get the same behaviour of top n nominators eligible for reward as + today. +- New storage item `ErasStakersPaged` that keeps up to `ExposurePageSize` + individual nominator exposures by era, validator and page. +- New storage item `ErasStakersOverview` which complements `ErasStakersPaged` + and keeps track of validator's own stake and total backing stake for each era. +- New call `payout_stakers_by_page` that allows to payout rewards for a single + validator by passing the page explicitly. +- New storage item `ClaimedRewards` that keeps track of claimed reward history + of a validator by era and page. ### Changed -- `payout_stakers` can be called multiple times for the same era if the validator has more than `ExposurePageSize` nominators backing them. + +- `payout_stakers` can be called multiple times for the same era if the + validator has more than `ExposurePageSize` nominators backing them. - `MaxExposurePageSize` is renamed to `MaxExposurePageSize`. ### Deprecated -- `ErasStakersClipped` is deprecated in favor of `ErasStakersPaged`. In 84 eras, `ErasStakersClipped` will be removed. -- `StakingLedger.claimed_rewards` is renamed to `StakingLedger.legacy_claimed_rewards` and is deprecated. +- `ErasStakersClipped` is deprecated in favor of `ErasStakersPaged`. In 84 + eras, `ErasStakersClipped` will be removed. +- `StakingLedger.claimed_rewards` is renamed + to `StakingLedger.legacy_claimed_rewards` and is deprecated. [5.0.0]: https://github.com/paritytech/substrate/pull/13059 diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index 557612f165f61..55ecf4bbe3d78 100644 --- a/frame/staking/src/lib.rs +++ b/frame/staking/src/lib.rs @@ -466,6 +466,8 @@ pub struct StakingLedger { pub unlocking: BoundedVec>, T::MaxUnlockingChunks>, /// List of eras for which the stakers behind a validator have claimed rewards. Only updated /// for validators. + /// + /// This is deprecated as of V14 and will be removed in future. pub legacy_claimed_rewards: BoundedVec, } @@ -784,7 +786,7 @@ pub struct ExposurePage { /// /// It, in combination with a list of `ExposurePage`s, can be used to reconstruct a full `Exposure` /// struct. This is useful for cases where we want to query a single page of `Exposure`s. -#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Encode, Decode, RuntimeDebug, TypeInfo)] +#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Encode, Decode, RuntimeDebug, TypeInfo, Default)] pub struct ExposureOverview { /// The total balance backing this validator. #[codec(compact)] @@ -794,21 +796,10 @@ pub struct ExposureOverview { pub own: Balance, /// Number of nominators backing this validator. pub nominator_count: u32, - /// Number of pages of backers. + /// Number of pages of nominators. pub page_count: PageIndex, } -impl Default for ExposureOverview { - fn default() -> Self { - Self { - total: Default::default(), - own: Default::default(), - nominator_count: Default::default(), - page_count: Default::default(), - } - } -} - /// Extended view of Exposure comprising of `ExposureOverview` and a single page of `ExposurePage`. /// /// This is useful where we need to take into account the validator's own stake and total exposure diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index e55ac7b4031f2..ae579780224eb 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -683,7 +683,7 @@ pub mod pallet { validator: &T::AccountId, page: PageIndex, ) -> Option>> { - return match >::get(era, (validator, page)) { + match >::get(era, (validator, page)) { // return clipped exposure if page zero and paged exposure does not exist None if page == 0 => Some(ExposureExt::from_clipped(>::get(era, validator))), From dfe8a989398b72943de88154190ba9286c2b8cae Mon Sep 17 00:00:00 2001 From: Ankan Date: Wed, 15 Feb 2023 20:14:46 +0100 Subject: [PATCH 134/162] fmt --- client/db/src/lib.rs | 1 - frame/staking/src/lib.rs | 14 ++++++++------ frame/staking/src/tests.rs | 3 +-- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/client/db/src/lib.rs b/client/db/src/lib.rs index 579cb76d47c2b..03de383f2c7f4 100644 --- a/client/db/src/lib.rs +++ b/client/db/src/lib.rs @@ -3559,7 +3559,6 @@ pub(crate) mod tests { assert_eq!(Some(vec![0x3a.into()]), bc.body(block_3a).unwrap()); } - #[test] fn indexed_data_block_body() { let backend = Backend::::new_test_with_tx_storage(BlocksPruning::Some(1), 10); diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index 55ecf4bbe3d78..76cbd0656be39 100644 --- a/frame/staking/src/lib.rs +++ b/frame/staking/src/lib.rs @@ -751,13 +751,13 @@ impl let mut others: Vec> = vec![]; for individual in chunk.iter() { page_total = page_total.saturating_add(individual.value); - others.push(IndividualExposure { who: individual.who.clone(), value: individual.value }) + others.push(IndividualExposure { + who: individual.who.clone(), + value: individual.value, + }) } - exposure_pages.push(ExposurePage { - page_total, - others, - }); + exposure_pages.push(ExposurePage { page_total, others }); } ( @@ -786,7 +786,9 @@ pub struct ExposurePage { /// /// It, in combination with a list of `ExposurePage`s, can be used to reconstruct a full `Exposure` /// struct. This is useful for cases where we want to query a single page of `Exposure`s. -#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Encode, Decode, RuntimeDebug, TypeInfo, Default)] +#[derive( + PartialEq, Eq, PartialOrd, Ord, Clone, Encode, Decode, RuntimeDebug, TypeInfo, Default, +)] pub struct ExposureOverview { /// The total balance backing this validator. #[codec(compact)] diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index 6460c554ca229..d81c4576fd9ad 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -2195,8 +2195,7 @@ fn reward_validator_slashing_validator_does_not_overflow() { let _ = Balances::make_free_balance_be(&11, stake); let exposure = Exposure:: { total: stake, own: stake, others: vec![] }; - let (exposure_overview, _) = - exposure.clone().into_pages(MaxExposurePageSize::get()); + let (exposure_overview, _) = exposure.clone().into_pages(MaxExposurePageSize::get()); let reward = EraRewardPoints:: { total: 1, individual: vec![(11, 1)].into_iter().collect(), From e2bf7cfa9d58c00b367d084669f5b3614820ba64 Mon Sep 17 00:00:00 2001 From: Ankan Date: Wed, 15 Feb 2023 20:45:42 +0100 Subject: [PATCH 135/162] make it compile --- bin/node/runtime/src/lib.rs | 1 + frame/babe/src/mock.rs | 1 + frame/fast-unstake/src/mock.rs | 1 + frame/grandpa/src/mock.rs | 1 + frame/nomination-pools/benchmarking/src/mock.rs | 1 + frame/nomination-pools/test-staking/src/mock.rs | 1 + frame/offences/benchmarking/src/mock.rs | 1 + frame/root-offences/src/mock.rs | 1 + frame/session/benchmarking/src/mock.rs | 1 + frame/staking/src/lib.rs | 3 ++- 10 files changed, 11 insertions(+), 1 deletion(-) diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index de53bd958b9c4..16e47fda08acb 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -569,6 +569,7 @@ impl pallet_staking::Config for Runtime { type EraPayout = pallet_staking::ConvertCurve; type NextNewSession = Session; type MaxExposurePageSize = MaxExposurePageSize; + type MaxExposurePageCount = ConstU32<1>; type OffendingValidatorsThreshold = OffendingValidatorsThreshold; type ElectionProvider = ElectionProviderMultiPhase; type GenesisElectionProvider = onchain::OnChainExecution; diff --git a/frame/babe/src/mock.rs b/frame/babe/src/mock.rs index 698a2bfa623bf..043c54620caaa 100644 --- a/frame/babe/src/mock.rs +++ b/frame/babe/src/mock.rs @@ -193,6 +193,7 @@ impl pallet_staking::Config for Test { type UnixTime = pallet_timestamp::Pallet; type EraPayout = pallet_staking::ConvertCurve; type MaxExposurePageSize = ConstU32<64>; + type MaxExposurePageCount = ConstU32<1>; type OffendingValidatorsThreshold = OffendingValidatorsThreshold; type NextNewSession = Session; type ElectionProvider = onchain::OnChainExecution; diff --git a/frame/fast-unstake/src/mock.rs b/frame/fast-unstake/src/mock.rs index 6e19483b5a365..058ec23649ab5 100644 --- a/frame/fast-unstake/src/mock.rs +++ b/frame/fast-unstake/src/mock.rs @@ -147,6 +147,7 @@ impl pallet_staking::Config for Runtime { type NextNewSession = (); type HistoryDepth = ConstU32<84>; type MaxExposurePageSize = ConstU32<64>; + type MaxExposurePageCount = ConstU32<1>; type OffendingValidatorsThreshold = (); type ElectionProvider = MockElection; type GenesisElectionProvider = Self::ElectionProvider; diff --git a/frame/grandpa/src/mock.rs b/frame/grandpa/src/mock.rs index 09641ea3fe9d7..dca60ab63fbae 100644 --- a/frame/grandpa/src/mock.rs +++ b/frame/grandpa/src/mock.rs @@ -197,6 +197,7 @@ impl pallet_staking::Config for Test { type UnixTime = pallet_timestamp::Pallet; type EraPayout = pallet_staking::ConvertCurve; type MaxExposurePageSize = ConstU32<64>; + type MaxExposurePageCount = ConstU32<1>; type OffendingValidatorsThreshold = OffendingValidatorsThreshold; type NextNewSession = Session; type ElectionProvider = onchain::OnChainExecution; diff --git a/frame/nomination-pools/benchmarking/src/mock.rs b/frame/nomination-pools/benchmarking/src/mock.rs index 2d5dff7715196..5a9a032efcd0c 100644 --- a/frame/nomination-pools/benchmarking/src/mock.rs +++ b/frame/nomination-pools/benchmarking/src/mock.rs @@ -107,6 +107,7 @@ impl pallet_staking::Config for Runtime { type SessionInterface = (); type EraPayout = pallet_staking::ConvertCurve; type NextNewSession = (); + type MaxExposurePageCount = ConstU32<1>; type MaxExposurePageSize = ConstU32<64>; type OffendingValidatorsThreshold = (); type ElectionProvider = diff --git a/frame/nomination-pools/test-staking/src/mock.rs b/frame/nomination-pools/test-staking/src/mock.rs index c9cd3dd945902..91c52b2047aee 100644 --- a/frame/nomination-pools/test-staking/src/mock.rs +++ b/frame/nomination-pools/test-staking/src/mock.rs @@ -121,6 +121,7 @@ impl pallet_staking::Config for Runtime { type SessionInterface = (); type EraPayout = pallet_staking::ConvertCurve; type NextNewSession = (); + type MaxExposurePageCount = ConstU32<1>; type MaxExposurePageSize = ConstU32<64>; type OffendingValidatorsThreshold = (); type ElectionProvider = diff --git a/frame/offences/benchmarking/src/mock.rs b/frame/offences/benchmarking/src/mock.rs index 26138fca5ed45..0678faef32822 100644 --- a/frame/offences/benchmarking/src/mock.rs +++ b/frame/offences/benchmarking/src/mock.rs @@ -170,6 +170,7 @@ impl pallet_staking::Config for Test { type SessionInterface = Self; type EraPayout = pallet_staking::ConvertCurve; type NextNewSession = Session; + type MaxExposurePageCount = ConstU32<1>; type MaxExposurePageSize = ConstU32<64>; type OffendingValidatorsThreshold = (); type ElectionProvider = onchain::OnChainExecution; diff --git a/frame/root-offences/src/mock.rs b/frame/root-offences/src/mock.rs index b2934110e9e02..3f8a0b8875da0 100644 --- a/frame/root-offences/src/mock.rs +++ b/frame/root-offences/src/mock.rs @@ -184,6 +184,7 @@ impl pallet_staking::Config for Test { type SessionInterface = Self; type EraPayout = pallet_staking::ConvertCurve; type NextNewSession = Session; + type MaxExposurePageCount = ConstU32<1>; type MaxExposurePageSize = ConstU32<64>; type OffendingValidatorsThreshold = OffendingValidatorsThreshold; type ElectionProvider = onchain::OnChainExecution; diff --git a/frame/session/benchmarking/src/mock.rs b/frame/session/benchmarking/src/mock.rs index ecb07d31102d9..a319b1c755907 100644 --- a/frame/session/benchmarking/src/mock.rs +++ b/frame/session/benchmarking/src/mock.rs @@ -172,6 +172,7 @@ impl pallet_staking::Config for Test { type SessionInterface = Self; type EraPayout = pallet_staking::ConvertCurve; type NextNewSession = Session; + type MaxExposurePageCount = ConstU32<1>; type MaxExposurePageSize = ConstU32<64>; type OffendingValidatorsThreshold = (); type ElectionProvider = onchain::OnChainExecution; diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index 76cbd0656be39..9e6f6f6e78a99 100644 --- a/frame/staking/src/lib.rs +++ b/frame/staking/src/lib.rs @@ -467,7 +467,8 @@ pub struct StakingLedger { /// List of eras for which the stakers behind a validator have claimed rewards. Only updated /// for validators. /// - /// This is deprecated as of V14 and will be removed in future. + /// This is deprecated as of V14 in favor of `T::ClaimedRewards` and will be removed in future. + /// Refer issue: #13034 pub legacy_claimed_rewards: BoundedVec, } From d79d897d2d72dc483baed6d399f60fa8ff1ea12e Mon Sep 17 00:00:00 2001 From: Ankan Date: Sun, 19 Feb 2023 20:29:19 +0100 Subject: [PATCH 136/162] keep only config item for MaxExposurePageSize --- frame/staking/CHANGELOG.md | 13 ++++++------- frame/staking/src/pallet/mod.rs | 19 +++++-------------- frame/staking/src/tests.rs | 4 ++-- 3 files changed, 13 insertions(+), 23 deletions(-) diff --git a/frame/staking/CHANGELOG.md b/frame/staking/CHANGELOG.md index a7f5ce7de8f47..77d7cdd73a01b 100644 --- a/frame/staking/CHANGELOG.md +++ b/frame/staking/CHANGELOG.md @@ -25,13 +25,12 @@ as a minor version bump. ### Added - Unlimited number of nominators can be rewarded. -- New storage item `ExposurePageSize` to limit the number of nominators rewarded for a single call for reward payout. -- New config item `MaxExposurePageCount` to limit the maximum number of exposure - pages that can be created. When set - to 1, we get the same behaviour of top n nominators eligible for reward as +- New config item `MaxExposurePageCount` to weakly bound the maximum number of + exposure pages that can exist. When set to 1, we get the same behaviour of top + n nominators eligible for reward as today. -- New storage item `ErasStakersPaged` that keeps up to `ExposurePageSize` +- New storage item `ErasStakersPaged` that keeps up to `MaxExposurePageSize` individual nominator exposures by era, validator and page. - New storage item `ErasStakersOverview` which complements `ErasStakersPaged` and keeps track of validator's own stake and total backing stake for each era. @@ -43,8 +42,8 @@ as a minor version bump. ### Changed - `payout_stakers` can be called multiple times for the same era if the - validator has more than `ExposurePageSize` nominators backing them. -- `MaxExposurePageSize` is renamed to `MaxExposurePageSize`. + validator has more than `MaxExposurePageSize` nominators backing them. +- `MaxNominatorRewardedPerValidator` is renamed to `MaxExposurePageSize`. ### Deprecated diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index ae579780224eb..634c1685436c0 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -58,6 +58,7 @@ pub(crate) const SPECULATIVE_NUM_SPANS: u32 = 32; #[frame_support::pallet] pub mod pallet { use frame_election_provider_support::ElectionDataProvider; + use frame_support::traits::DefensiveMax; use crate::{BenchmarkingConfig, ExposureExt, ExposureOverview}; @@ -204,9 +205,8 @@ pub mod pallet { /// The maximum size of each `T::ExposurePage`. /// - /// An `ExposurePage` is bounded to a maximum of `MaxExposurePageSize` - /// nominators. The actual page size is a dynamic value that is determined by the storage - /// item `T::ExposurePageSize`. + /// An `ExposurePage` is weakly bounded to a maximum of `MaxExposurePageSize` + /// nominators. /// /// For older non-paged exposure, a reward payout was restricted to the top /// `MaxExposurePageSize` nominators. This is to limit the i/o cost for the @@ -480,13 +480,7 @@ pub mod pallet { Exposure>, ValueQuery, >; - - /// The nominator count each `ExposurePage` is capped at. - /// - /// This cannot be greater than `T::MaxExposurePageSize`. - #[pallet::storage] - pub type ExposurePageSize = StorageValue<_, u32, OptionQuery>; - + /// Paginated exposure of a validator at given era. /// /// This is keyed first by the era index to allow bulk deletion, then the tuple of stash account @@ -783,9 +777,7 @@ pub mod pallet { ) { >::insert(era, &validator, &exposure); - let page_size = >::get() - .unwrap_or_else(|| T::MaxExposurePageSize::get()) - .clamp(1, T::MaxExposurePageSize::get()); + let page_size = T::MaxExposurePageSize::get().defensive_max(1); let max_page_count = T::MaxExposurePageCount::get(); let nominator_count = exposure.others.len(); @@ -1722,7 +1714,6 @@ pub mod pallet { /// /// - `validator_stash` is the stash account of the validator. /// - `era` may be any era between `[current_era - history_depth; current_era]`. - /// `num_nominators / T::ExposurePageSize`. /// /// The origin of this call must be _Signed_. Any account can call this function, even if /// it is not one of the stakers. diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index d81c4576fd9ad..a3e444685089e 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -4245,7 +4245,7 @@ fn test_page_count_and_size() { assert_eq!(EraInfo::::get_validator_exposure(2, &11, 1).unwrap().others().len(), 36); // now lets decrease page size - ExposurePageSize::::put(32); + MaxExposurePageSize::set(32); mock::start_active_era(3); // now we expect 4 pages. assert_eq!(EraInfo::::get_page_count(3, &11), 4); @@ -4256,7 +4256,7 @@ fn test_page_count_and_size() { assert_eq!(EraInfo::::get_validator_exposure(3, &11, 3).unwrap().others().len(), 4); // now lets decrease page size even more - ExposurePageSize::::put(9); + MaxExposurePageSize::set(9); mock::start_active_era(4); // now we expect the max 10 pages with each page having 9 nominators. assert_eq!(EraInfo::::get_page_count(4, &11), 10); From 5a1f446740730762511cbc75c0f38769feb719b3 Mon Sep 17 00:00:00 2001 From: Ankan Date: Sun, 19 Feb 2023 21:03:19 +0100 Subject: [PATCH 137/162] safe maths --- frame/staking/src/pallet/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index 634c1685436c0..1420e9319d94c 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -480,7 +480,7 @@ pub mod pallet { Exposure>, ValueQuery, >; - + /// Paginated exposure of a validator at given era. /// /// This is keyed first by the era index to allow bulk deletion, then the tuple of stash account @@ -788,7 +788,7 @@ pub mod pallet { let exposure = if required_page_count as PageIndex > max_page_count { // sort before clipping. let mut exposure_clipped = exposure; - let clipped_max_len = max_page_count * page_size; + let clipped_max_len = max_page_count.saturating_mul(page_size); exposure_clipped.others.sort_by(|a, b| b.value.cmp(&a.value)); exposure_clipped.others.truncate(clipped_max_len as usize); From 08d60ff379ac0ec0f50dc5d4ce4cf9fe86f613e3 Mon Sep 17 00:00:00 2001 From: Ankan Date: Sun, 19 Feb 2023 21:07:29 +0100 Subject: [PATCH 138/162] pr comment --- frame/staking/src/pallet/mod.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index 1420e9319d94c..9125e1624f479 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -781,8 +781,9 @@ pub mod pallet { let max_page_count = T::MaxExposurePageCount::get(); let nominator_count = exposure.others.len(); - let required_page_count = - nominator_count.saturating_add(page_size as usize - 1) / page_size as usize; + let required_page_count = nominator_count + .defensive_saturating_add(page_size as usize - 1) / + page_size as usize; // clip nominators if it exceeds the maximum page count. let exposure = if required_page_count as PageIndex > max_page_count { From b92943976cb4eb9dd6eefc49c3e408e52055f252 Mon Sep 17 00:00:00 2001 From: Ankan Date: Mon, 20 Feb 2023 00:08:01 +0100 Subject: [PATCH 139/162] simplify next claimable page --- frame/staking/src/pallet/mod.rs | 34 +++++++++++++-------------------- frame/staking/src/tests.rs | 8 ++++---- 2 files changed, 17 insertions(+), 25 deletions(-) diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index 9125e1624f479..28fa9848773cc 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -58,7 +58,7 @@ pub(crate) const SPECULATIVE_NUM_SPANS: u32 = 32; #[frame_support::pallet] pub mod pallet { use frame_election_provider_support::ElectionDataProvider; - use frame_support::traits::DefensiveMax; + use frame_support::{defensive, traits::DefensiveMax}; use crate::{BenchmarkingConfig, ExposureExt, ExposureOverview}; @@ -665,7 +665,7 @@ pub mod pallet { /// This is only used for paged rewards. Once older non-paged rewards are no longer /// relevant, `is_rewards_claimed_temp` can be removed and this function can be made public. fn is_rewards_claimed(era: EraIndex, validator: &T::AccountId, page: PageIndex) -> bool { - ClaimedRewards::::get(era, validator).binary_search(&page).is_ok() + ClaimedRewards::::get(era, validator).contains(&page) } /// Get exposure info for a validator at a given era and page. @@ -722,18 +722,10 @@ pub mod pallet { // Find next claimable page of paged exposure. let page_count = Self::get_page_count(era, validator); + let all_claimable_pages: Vec = (0..page_count).collect(); let claimed_pages = ClaimedRewards::::get(era, validator); - let claimed_page_count = claimed_pages.len() as PageIndex; - // find the first page that is not claimed. - for page in 0..claimed_page_count as PageIndex { - debug_assert!(page <= claimed_pages[page as usize]); - if page < claimed_pages[page as usize] { - return Some(page) - } - } - // all pages are claimed - return if claimed_page_count < page_count { Some(claimed_page_count) } else { None } + all_claimable_pages.into_iter().filter(|p| !claimed_pages.contains(p)).next() } /// Checks if exposure is paged or not. @@ -756,17 +748,17 @@ pub mod pallet { page: PageIndex, ) { let mut claimed_pages = ClaimedRewards::::get(era, validator); - let search = claimed_pages.binary_search(&page); - // this should never be called if the reward has already been claimed - debug_assert!(search.is_err()); - match search { - Err(index) => { - claimed_pages.insert(index, page); - ClaimedRewards::::insert(era, validator, claimed_pages); - }, - _ => {}, + // this should never be called if the reward has already been claimed + if claimed_pages.contains(&page) { + defensive!("Trying to set an already claimed reward"); + // nevertheless don't do anything since the page already exist in claimed rewards. + return } + + // add page to claimed entries + claimed_pages.push(page); + ClaimedRewards::::insert(era, validator, claimed_pages); } /// Store exposure for elected validators at start of an era. diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index a3e444685089e..b6d70c162bc8d 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -4159,7 +4159,7 @@ fn test_multi_page_payout_stakers_backward_compatible() { // verify page 0 is claimed even when explicit page is not passed assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, last_reward_era,)); - assert_eq!(Staking::claimed_rewards(last_reward_era, &11), vec![0, 1]); + assert_eq!(Staking::claimed_rewards(last_reward_era, &11), vec![1, 0]); // cannot claim any more pages assert_noop!( @@ -4186,7 +4186,7 @@ fn test_multi_page_payout_stakers_backward_compatible() { assert_eq!(Staking::claimed_rewards(test_era, &11), vec![2]); assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, test_era)); - assert_eq!(Staking::claimed_rewards(test_era, &11), vec![0, 2]); + assert_eq!(Staking::claimed_rewards(test_era, &11), vec![2, 0]); // cannot claim page 2 again assert_noop!( @@ -4195,10 +4195,10 @@ fn test_multi_page_payout_stakers_backward_compatible() { ); assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, test_era)); - assert_eq!(Staking::claimed_rewards(test_era, &11), vec![0, 1, 2]); + assert_eq!(Staking::claimed_rewards(test_era, &11), vec![2, 0, 1]); assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, test_era)); - assert_eq!(Staking::claimed_rewards(test_era, &11), vec![0, 1, 2, 3]); + assert_eq!(Staking::claimed_rewards(test_era, &11), vec![2, 0, 1, 3]); }); } From 7df30f6518a7b8cc9978b802cb67c43c2506d70b Mon Sep 17 00:00:00 2001 From: Ankan Date: Mon, 20 Feb 2023 00:14:46 +0100 Subject: [PATCH 140/162] fix build --- frame/beefy/src/mock.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/frame/beefy/src/mock.rs b/frame/beefy/src/mock.rs index 8d8b831950d8e..38edabbdd78a7 100644 --- a/frame/beefy/src/mock.rs +++ b/frame/beefy/src/mock.rs @@ -219,7 +219,8 @@ impl pallet_staking::Config for Test { type SessionInterface = Self; type UnixTime = pallet_timestamp::Pallet; type EraPayout = pallet_staking::ConvertCurve; - type MaxNominatorRewardedPerValidator = ConstU32<64>; + type MaxExposurePageSize = ConstU32<64>; + type MaxExposurePageCount = ConstU32<1>; type OffendingValidatorsThreshold = OffendingValidatorsThreshold; type NextNewSession = Session; type ElectionProvider = onchain::OnChainExecution; From 4a415e70d112c51fd7f2e0c8f4a02bb3c3ca4d1b Mon Sep 17 00:00:00 2001 From: Ankan Date: Mon, 20 Feb 2023 00:35:39 +0100 Subject: [PATCH 141/162] pr comments --- frame/staking/CHANGELOG.md | 3 +-- frame/staking/src/lib.rs | 2 +- frame/staking/src/pallet/mod.rs | 2 ++ 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/frame/staking/CHANGELOG.md b/frame/staking/CHANGELOG.md index 77d7cdd73a01b..8f39fe86c9937 100644 --- a/frame/staking/CHANGELOG.md +++ b/frame/staking/CHANGELOG.md @@ -28,8 +28,7 @@ as a minor version bump. for a single call for reward payout. - New config item `MaxExposurePageCount` to weakly bound the maximum number of exposure pages that can exist. When set to 1, we get the same behaviour of top - n nominators eligible for reward as - today. + n nominators eligible for reward as previously with non paged exposures. - New storage item `ErasStakersPaged` that keeps up to `MaxExposurePageSize` individual nominator exposures by era, validator and page. - New storage item `ErasStakersOverview` which complements `ErasStakersPaged` diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index 9e6f6f6e78a99..d71a9eb68ef02 100644 --- a/frame/staking/src/lib.rs +++ b/frame/staking/src/lib.rs @@ -806,7 +806,7 @@ pub struct ExposureOverview { /// Extended view of Exposure comprising of `ExposureOverview` and a single page of `ExposurePage`. /// /// This is useful where we need to take into account the validator's own stake and total exposure -/// in consideration in addition to the individual nominators backing them. +/// in consideration, in addition to the individual nominators backing them. #[derive(Encode, Decode, RuntimeDebug, TypeInfo, PartialEq, Eq)] struct ExposureExt { exposure_overview: ExposureOverview, diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index 28fa9848773cc..ce3c50543018a 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -701,6 +701,7 @@ pub mod pallet { /// /// This will always return at minimum one count of exposure to be backward compatible to /// non-paged reward payouts. + // FIXME: No need to return minimum of one page after cleanup: #13034 pub(crate) fn get_page_count(era: EraIndex, validator: &T::AccountId) -> PageIndex { >::get(&era, validator).page_count.max(1) } @@ -742,6 +743,7 @@ pub mod pallet { } /// Creates an entry to track validator reward has been claimed for a given era and page. + /// Noop if already claimed. pub(crate) fn set_rewards_as_claimed( era: EraIndex, validator: &T::AccountId, From 8544412b011cfe94ab238ab8a02b6d2401ec26f7 Mon Sep 17 00:00:00 2001 From: Ankan Date: Mon, 20 Feb 2023 01:05:14 +0100 Subject: [PATCH 142/162] clippy suggestion --- frame/staking/src/pallet/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index ce3c50543018a..c526afd9e97e7 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -726,7 +726,7 @@ pub mod pallet { let all_claimable_pages: Vec = (0..page_count).collect(); let claimed_pages = ClaimedRewards::::get(era, validator); - all_claimable_pages.into_iter().filter(|p| !claimed_pages.contains(p)).next() + all_claimable_pages.into_iter().find(|p| !claimed_pages.contains(p)) } /// Checks if exposure is paged or not. From 0ce2bbd65246060c15a47640e52f7da15baa28af Mon Sep 17 00:00:00 2001 From: Ankan Date: Mon, 20 Feb 2023 21:48:07 +0100 Subject: [PATCH 143/162] write a new eras stakers --- frame/babe/src/tests.rs | 8 +- frame/beefy/src/tests.rs | 12 +-- frame/grandpa/src/tests.rs | 12 +-- frame/root-offences/src/lib.rs | 2 +- frame/staking/src/lib.rs | 6 ++ frame/staking/src/mock.rs | 2 +- frame/staking/src/pallet/impls.rs | 22 +++-- frame/staking/src/pallet/mod.rs | 43 ++++++--- frame/staking/src/tests.rs | 144 +++++++++++++++--------------- 9 files changed, 142 insertions(+), 109 deletions(-) diff --git a/frame/babe/src/tests.rs b/frame/babe/src/tests.rs index 938269a6cfa62..10226f1498e9e 100644 --- a/frame/babe/src/tests.rs +++ b/frame/babe/src/tests.rs @@ -437,7 +437,7 @@ fn report_equivocation_current_session_works() { assert_eq!(Staking::slashable_balance_of(validator), 10_000); assert_eq!( - Staking::eras_stakers(1, validator), + Staking::eras_stakers(1, &validator), pallet_staking::Exposure { total: 10_000, own: 10_000, others: vec![] }, ); } @@ -478,7 +478,7 @@ fn report_equivocation_current_session_works() { assert_eq!(Balances::total_balance(&offending_validator_id), 10_000_000 - 10_000); assert_eq!(Staking::slashable_balance_of(&offending_validator_id), 0); assert_eq!( - Staking::eras_stakers(2, offending_validator_id), + Staking::eras_stakers(2, &offending_validator_id), pallet_staking::Exposure { total: 0, own: 0, others: vec![] }, ); @@ -491,7 +491,7 @@ fn report_equivocation_current_session_works() { assert_eq!(Balances::total_balance(validator), 10_000_000); assert_eq!(Staking::slashable_balance_of(validator), 10_000); assert_eq!( - Staking::eras_stakers(2, validator), + Staking::eras_stakers(2, &validator), pallet_staking::Exposure { total: 10_000, own: 10_000, others: vec![] }, ); } @@ -550,7 +550,7 @@ fn report_equivocation_old_session_works() { assert_eq!(Balances::total_balance(&offending_validator_id), 10_000_000 - 10_000); assert_eq!(Staking::slashable_balance_of(&offending_validator_id), 0); assert_eq!( - Staking::eras_stakers(3, offending_validator_id), + Staking::eras_stakers(3, &offending_validator_id), pallet_staking::Exposure { total: 0, own: 0, others: vec![] }, ); }) diff --git a/frame/beefy/src/tests.rs b/frame/beefy/src/tests.rs index a92f90b6107bc..98a7f143abdc0 100644 --- a/frame/beefy/src/tests.rs +++ b/frame/beefy/src/tests.rs @@ -244,7 +244,7 @@ fn report_equivocation_current_set_works() { assert_eq!(Staking::slashable_balance_of(validator), 10_000); assert_eq!( - Staking::eras_stakers(1, validator), + Staking::eras_stakers(1, &validator), pallet_staking::Exposure { total: 10_000, own: 10_000, others: vec![] }, ); } @@ -282,7 +282,7 @@ fn report_equivocation_current_set_works() { assert_eq!(Balances::total_balance(&equivocation_validator_id), 10_000_000 - 10_000); assert_eq!(Staking::slashable_balance_of(&equivocation_validator_id), 0); assert_eq!( - Staking::eras_stakers(2, equivocation_validator_id), + Staking::eras_stakers(2, &equivocation_validator_id), pallet_staking::Exposure { total: 0, own: 0, others: vec![] }, ); @@ -296,7 +296,7 @@ fn report_equivocation_current_set_works() { assert_eq!(Staking::slashable_balance_of(validator), 10_000); assert_eq!( - Staking::eras_stakers(2, validator), + Staking::eras_stakers(2, &validator), pallet_staking::Exposure { total: 10_000, own: 10_000, others: vec![] }, ); } @@ -332,7 +332,7 @@ fn report_equivocation_old_set_works() { assert_eq!(Staking::slashable_balance_of(validator), 10_000); assert_eq!( - Staking::eras_stakers(2, validator), + Staking::eras_stakers(2, &validator), pallet_staking::Exposure { total: 10_000, own: 10_000, others: vec![] }, ); } @@ -366,7 +366,7 @@ fn report_equivocation_old_set_works() { assert_eq!(Balances::total_balance(&equivocation_validator_id), 10_000_000 - 10_000); assert_eq!(Staking::slashable_balance_of(&equivocation_validator_id), 0); assert_eq!( - Staking::eras_stakers(3, equivocation_validator_id), + Staking::eras_stakers(3, &equivocation_validator_id), pallet_staking::Exposure { total: 0, own: 0, others: vec![] }, ); @@ -380,7 +380,7 @@ fn report_equivocation_old_set_works() { assert_eq!(Staking::slashable_balance_of(validator), 10_000); assert_eq!( - Staking::eras_stakers(3, validator), + Staking::eras_stakers(3, &validator), pallet_staking::Exposure { total: 10_000, own: 10_000, others: vec![] }, ); } diff --git a/frame/grandpa/src/tests.rs b/frame/grandpa/src/tests.rs index e090dcebb60bf..32518c9915d93 100644 --- a/frame/grandpa/src/tests.rs +++ b/frame/grandpa/src/tests.rs @@ -334,7 +334,7 @@ fn report_equivocation_current_set_works() { assert_eq!(Staking::slashable_balance_of(validator), 10_000); assert_eq!( - Staking::eras_stakers(1, validator), + Staking::eras_stakers(1, &validator), pallet_staking::Exposure { total: 10_000, own: 10_000, others: vec![] }, ); } @@ -372,7 +372,7 @@ fn report_equivocation_current_set_works() { assert_eq!(Balances::total_balance(&equivocation_validator_id), 10_000_000 - 10_000); assert_eq!(Staking::slashable_balance_of(&equivocation_validator_id), 0); assert_eq!( - Staking::eras_stakers(2, equivocation_validator_id), + Staking::eras_stakers(2, &equivocation_validator_id), pallet_staking::Exposure { total: 0, own: 0, others: vec![] }, ); @@ -386,7 +386,7 @@ fn report_equivocation_current_set_works() { assert_eq!(Staking::slashable_balance_of(validator), 10_000); assert_eq!( - Staking::eras_stakers(2, validator), + Staking::eras_stakers(2, &validator), pallet_staking::Exposure { total: 10_000, own: 10_000, others: vec![] }, ); } @@ -418,7 +418,7 @@ fn report_equivocation_old_set_works() { assert_eq!(Staking::slashable_balance_of(validator), 10_000); assert_eq!( - Staking::eras_stakers(2, validator), + Staking::eras_stakers(2, &validator), pallet_staking::Exposure { total: 10_000, own: 10_000, others: vec![] }, ); } @@ -451,7 +451,7 @@ fn report_equivocation_old_set_works() { assert_eq!(Staking::slashable_balance_of(&equivocation_validator_id), 0); assert_eq!( - Staking::eras_stakers(3, equivocation_validator_id), + Staking::eras_stakers(3, &equivocation_validator_id), pallet_staking::Exposure { total: 0, own: 0, others: vec![] }, ); @@ -465,7 +465,7 @@ fn report_equivocation_old_set_works() { assert_eq!(Staking::slashable_balance_of(validator), 10_000); assert_eq!( - Staking::eras_stakers(3, validator), + Staking::eras_stakers(3, &validator), pallet_staking::Exposure { total: 10_000, own: 10_000, others: vec![] }, ); } diff --git a/frame/root-offences/src/lib.rs b/frame/root-offences/src/lib.rs index ed039f46becc8..c892fd07e2bb5 100644 --- a/frame/root-offences/src/lib.rs +++ b/frame/root-offences/src/lib.rs @@ -112,7 +112,7 @@ pub mod pallet { .clone() .into_iter() .map(|(o, _)| OffenceDetails:: { - offender: (o.clone(), Staking::::eras_stakers(now, o)), + offender: (o.clone(), Staking::::eras_stakers(now, &o)), reporters: vec![], }) .collect()) diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index d71a9eb68ef02..8368d4c38db67 100644 --- a/frame/staking/src/lib.rs +++ b/frame/staking/src/lib.rs @@ -783,6 +783,12 @@ pub struct ExposurePage { pub others: Vec>, } +impl Default for ExposurePage { + fn default() -> Self { + ExposurePage { page_total: Default::default(), others: vec![] } + } +} + /// An overview of stake backing a single validator. /// /// It, in combination with a list of `ExposurePage`s, can be used to reconstruct a full `Exposure` diff --git a/frame/staking/src/mock.rs b/frame/staking/src/mock.rs index 16f77bafc13e9..165b2e1eecdde 100644 --- a/frame/staking/src/mock.rs +++ b/frame/staking/src/mock.rs @@ -742,7 +742,7 @@ pub(crate) fn on_offence_now( pub(crate) fn add_slash(who: &AccountId) { on_offence_now( &[OffenceDetails { - offender: (*who, Staking::eras_stakers(active_era(), *who)), + offender: (*who, Staking::eras_stakers(active_era(), who)), reporters: vec![], }], &[Perbill::from_percent(10)], diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index 1206ecb4c32af..d3ea2d4f5f1c3 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -42,11 +42,7 @@ use sp_staking::{ }; use sp_std::prelude::*; -use crate::{ - log, slashing, weights::WeightInfo, ActiveEraInfo, BalanceOf, EraPayout, Exposure, ExposureOf, - Forcing, IndividualExposure, MaxWinnersOf, Nominations, PositiveImbalanceOf, RewardDestination, - SessionInterface, StakingLedger, ValidatorPrefs, -}; +use crate::{log, slashing, weights::WeightInfo, ActiveEraInfo, BalanceOf, EraPayout, Exposure, ExposureOf, Forcing, IndividualExposure, MaxWinnersOf, Nominations, PositiveImbalanceOf, RewardDestination, SessionInterface, StakingLedger, ValidatorPrefs}; use super::{pallet::*, STAKING_ID}; @@ -995,6 +991,22 @@ impl Pallet { DispatchClass::Mandatory, ); } + + pub fn eras_stakers(era: EraIndex, account: &T::AccountId) -> Exposure> { + let overview = EraInfo::::get_validator_overview(era, &account).unwrap_or_default(); + if overview.page_count == 0 { + return Exposure { total: overview.total, own: overview.own, others: vec![] }; + } + + let mut others = Vec::with_capacity(overview.nominator_count as usize); + for page in 0..overview.page_count { + let nominators = EraInfo::::get_nominators_page(era, &account, page); + // TODO(ank4n) fix to defensive unwrap + others.append(&mut nominators.unwrap().others); + } + + Exposure { total: overview.total, own: overview.own, others } + } } impl ElectionDataProvider for Pallet { diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index c526afd9e97e7..33728953f3fe7 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -418,7 +418,7 @@ pub mod pallet { /// Is it removed after `HISTORY_DEPTH` eras. /// If stakers hasn't been set or has been removed then empty exposure is returned. #[pallet::storage] - #[pallet::getter(fn eras_stakers)] + // #[pallet::getter(fn eras_stakers)] #[pallet::unbounded] pub type ErasStakers = StorageDoubleMap< _, @@ -451,7 +451,7 @@ pub mod pallet { Twox64Concat, T::AccountId, ExposureOverview>, - ValueQuery, + OptionQuery, >; /// Clipped Exposure of validator at era. @@ -677,33 +677,50 @@ pub mod pallet { validator: &T::AccountId, page: PageIndex, ) -> Option>> { - match >::get(era, (validator, page)) { + match >::get(&era, validator) { // return clipped exposure if page zero and paged exposure does not exist None if page == 0 => Some(ExposureExt::from_clipped(>::get(era, validator))), // return paged exposure if it exists - Some(exposure_page) => { - let overview = >::get(&era, validator); - // own stake is included only once in the first page. + Some(overview) => { + let exposure_page = + >::get(era, (validator, page)).unwrap_or_default(); let own = if page == 0 { overview.own } else { Zero::zero() }; - - Some(ExposureExt { - exposure_overview: ExposureOverview { own, ..overview }, - exposure_page, - }) - }, + Some(ExposureExt { exposure_overview: ExposureOverview { own, ..overview }, exposure_page }) + } _ => None, } } + pub(crate) fn get_validator_overview( + era: EraIndex, + validator: &T::AccountId, + ) -> Option>> { + >::get(&era, validator) + } + + pub(crate) fn get_nominators_page( + era: EraIndex, + validator: &T::AccountId, + page: PageIndex, + ) -> Option>> { + >::get(era, (validator, page)) + } + /// Returns the number of pages of exposure a validator has for the given era. /// /// This will always return at minimum one count of exposure to be backward compatible to /// non-paged reward payouts. // FIXME: No need to return minimum of one page after cleanup: #13034 pub(crate) fn get_page_count(era: EraIndex, validator: &T::AccountId) -> PageIndex { - >::get(&era, validator).page_count.max(1) + if let Some(overview) = >::get(&era, validator) { + // Paged exposure + overview.page_count.max(1) + } else { + // Non-paged exposure + 1 + } } /// Returns the next page that can be claimed or `None` if nothing to claim. diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index b6d70c162bc8d..dc9cdd912cd98 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -195,7 +195,7 @@ fn basic_setup_works() { assert_eq!(Staking::nominators(101).unwrap().targets, vec![11, 21]); assert_eq!( - Staking::eras_stakers(active_era(), 11), + Staking::eras_stakers(active_era(), &11), Exposure { total: 1125, own: 1000, @@ -203,7 +203,7 @@ fn basic_setup_works() { }, ); assert_eq!( - Staking::eras_stakers(active_era(), 21), + Staking::eras_stakers(active_era(), &21), Exposure { total: 1375, own: 1000, @@ -619,7 +619,7 @@ fn nominating_and_rewards_should_work() { assert_eq!(ErasStakers::::iter_prefix_values(active_era()).count(), 2); assert_eq!( - Staking::eras_stakers(active_era(), 11), + Staking::eras_stakers(active_era(), &11), Exposure { total: 1000 + 800, own: 1000, @@ -630,7 +630,7 @@ fn nominating_and_rewards_should_work() { }, ); assert_eq!( - Staking::eras_stakers(active_era(), 21), + Staking::eras_stakers(active_era(), &21), Exposure { total: 1000 + 1200, own: 1000, @@ -690,7 +690,7 @@ fn nominators_also_get_slashed_pro_rata() { ExtBuilder::default().build_and_execute(|| { mock::start_active_era(1); let slash_percent = Perbill::from_percent(5); - let initial_exposure = Staking::eras_stakers(active_era(), 11); + let initial_exposure = Staking::eras_stakers(active_era(), &11); // 101 is a nominator for 11 assert_eq!(initial_exposure.others.first().unwrap().who, 101); @@ -958,7 +958,7 @@ fn cannot_transfer_staked_balance() { // Confirm account 11 has some free balance assert_eq!(Balances::free_balance(11), 1000); // Confirm account 11 (via controller 10) is totally staked - assert_eq!(Staking::eras_stakers(active_era(), 11).total, 1000); + assert_eq!(Staking::eras_stakers(active_era(), &11).total, 1000); // Confirm account 11 cannot transfer as a result assert_noop!( Balances::transfer(RuntimeOrigin::signed(11), 20, 1), @@ -983,7 +983,7 @@ fn cannot_transfer_staked_balance_2() { // Confirm account 21 has some free balance assert_eq!(Balances::free_balance(21), 2000); // Confirm account 21 (via controller 20) is totally staked - assert_eq!(Staking::eras_stakers(active_era(), 21).total, 1000); + assert_eq!(Staking::eras_stakers(active_era(), &21).total, 1000); // Confirm account 21 can transfer at most 1000 assert_noop!( Balances::transfer(RuntimeOrigin::signed(21), 20, 1001), @@ -1002,7 +1002,7 @@ fn cannot_reserve_staked_balance() { // Confirm account 11 has some free balance assert_eq!(Balances::free_balance(11), 1000); // Confirm account 11 (via controller 10) is totally staked - assert_eq!(Staking::eras_stakers(active_era(), 11).own, 1000); + assert_eq!(Staking::eras_stakers(active_era(), &11).own, 1000); // Confirm account 11 cannot reserve as a result assert_noop!(Balances::reserve(&11, 1), BalancesError::::LiquidityRestrictions); @@ -1150,7 +1150,7 @@ fn validator_payment_prefs_work() { // Compute total payout now for whole duration as other parameter won't change let total_payout_1 = current_total_payout_for_duration(reward_time_per_era()); - let exposure_1 = Staking::eras_stakers(active_era(), 11); + let exposure_1 = Staking::eras_stakers(active_era(), &11); Pallet::::reward_by_ids(vec![(11, 1)]); mock::start_active_era(2); @@ -1256,7 +1256,7 @@ fn bond_extra_and_withdraw_unbonded_works() { }) ); assert_eq!( - Staking::eras_stakers(active_era(), 11), + Staking::eras_stakers(active_era(), &11), Exposure { total: 1000, own: 1000, others: vec![] } ); @@ -1275,7 +1275,7 @@ fn bond_extra_and_withdraw_unbonded_works() { ); // Exposure is a snapshot! only updated after the next era update. assert_ne!( - Staking::eras_stakers(active_era(), 11), + Staking::eras_stakers(active_era(), &11), Exposure { total: 1000 + 100, own: 1000 + 100, others: vec![] } ); @@ -1296,7 +1296,7 @@ fn bond_extra_and_withdraw_unbonded_works() { ); // Exposure is now updated. assert_eq!( - Staking::eras_stakers(active_era(), 11), + Staking::eras_stakers(active_era(), &11), Exposure { total: 1000 + 100, own: 1000 + 100, others: vec![] } ); @@ -1728,8 +1728,8 @@ fn reward_to_stake_works() { // Confirm account 10 and 20 are validators assert!(>::contains_key(&11) && >::contains_key(&21)); - assert_eq!(Staking::eras_stakers(active_era(), 11).total, 1000); - assert_eq!(Staking::eras_stakers(active_era(), 21).total, 2000); + assert_eq!(Staking::eras_stakers(active_era(), &11).total, 1000); + assert_eq!(Staking::eras_stakers(active_era(), &21).total, 2000); // Give the man some money. let _ = Balances::make_free_balance_be(&10, 1000); @@ -1757,8 +1757,8 @@ fn reward_to_stake_works() { mock::start_active_era(1); mock::make_all_reward_payment(0); - assert_eq!(Staking::eras_stakers(active_era(), 11).total, 1000); - assert_eq!(Staking::eras_stakers(active_era(), 21).total, 69); + assert_eq!(Staking::eras_stakers(active_era(), &11).total, 1000); + assert_eq!(Staking::eras_stakers(active_era(), &21).total, 69); let _11_balance = Balances::free_balance(&11); assert_eq!(_11_balance, 1000 + total_payout_0 / 2); @@ -1767,8 +1767,8 @@ fn reward_to_stake_works() { mock::start_active_era(2); // -- new infos - assert_eq!(Staking::eras_stakers(active_era(), 11).total, 1000 + total_payout_0 / 2); - assert_eq!(Staking::eras_stakers(active_era(), 21).total, 69 + total_payout_0 / 2); + assert_eq!(Staking::eras_stakers(active_era(), &11).total, 1000 + total_payout_0 / 2); + assert_eq!(Staking::eras_stakers(active_era(), &21).total, 69 + total_payout_0 / 2); }); } @@ -1904,8 +1904,8 @@ fn wrong_vote_is_moot() { assert_eq_uvec!(validator_controllers(), vec![20, 10]); // our new voter is taken into account - assert!(Staking::eras_stakers(active_era(), 11).others.iter().any(|i| i.who == 61)); - assert!(Staking::eras_stakers(active_era(), 21).others.iter().any(|i| i.who == 61)); + assert!(Staking::eras_stakers(active_era(), &11).others.iter().any(|i| i.who == 61)); + assert!(Staking::eras_stakers(active_era(), &21).others.iter().any(|i| i.who == 61)); }); } @@ -2004,7 +2004,7 @@ fn bond_with_little_staked_value_bounded() { // 2 is elected. assert_eq_uvec!(validator_controllers(), vec![20, 10, 2]); - assert_eq!(Staking::eras_stakers(active_era(), 2).total, 0); + assert_eq!(Staking::eras_stakers(active_era(), &2).total, 0); // Old ones are rewarded. assert_eq_error_rate!( @@ -2022,7 +2022,7 @@ fn bond_with_little_staked_value_bounded() { mock::make_all_reward_payment(1); assert_eq_uvec!(validator_controllers(), vec![20, 10, 2]); - assert_eq!(Staking::eras_stakers(active_era(), 2).total, 0); + assert_eq!(Staking::eras_stakers(active_era(), &2).total, 0); // 2 is now rewarded. assert_eq_error_rate!( @@ -2177,8 +2177,8 @@ fn phragmen_should_not_overflow() { assert_eq_uvec!(validator_controllers(), vec![4, 2]); // We can safely convert back to values within [u64, u128]. - assert!(Staking::eras_stakers(active_era(), 3).total > Votes::max_value() as Balance); - assert!(Staking::eras_stakers(active_era(), 5).total > Votes::max_value() as Balance); + assert!(Staking::eras_stakers(active_era(), &3).total > Votes::max_value() as Balance); + assert!(Staking::eras_stakers(active_era(), &5).total > Votes::max_value() as Balance); }) } @@ -2195,7 +2195,6 @@ fn reward_validator_slashing_validator_does_not_overflow() { let _ = Balances::make_free_balance_be(&11, stake); let exposure = Exposure:: { total: stake, own: stake, others: vec![] }; - let (exposure_overview, _) = exposure.clone().into_pages(MaxExposurePageSize::get()); let reward = EraRewardPoints:: { total: 1, individual: vec![(11, 1)].into_iter().collect(), @@ -2203,8 +2202,7 @@ fn reward_validator_slashing_validator_does_not_overflow() { // Check reward ErasRewardPoints::::insert(0, reward); - ErasStakers::::insert(0, 11, &exposure); - ErasStakersOverview::::insert(0, 11, exposure_overview); + EraInfo::::set_validator_exposure(0, &11, exposure); ErasValidatorReward::::insert(0, stake); assert_ok!(Staking::payout_stakers_by_page(RuntimeOrigin::signed(1337), 11, 0, 0)); assert_eq!(Balances::total_balance(&11), stake * 2); @@ -2217,9 +2215,9 @@ fn reward_validator_slashing_validator_does_not_overflow() { Staking::bond(RuntimeOrigin::signed(2), 20000, stake - 1, RewardDestination::default()) .unwrap(); // Override exposure of 11 - ErasStakers::::insert( + EraInfo::::set_validator_exposure( 0, - 11, + &11, Exposure { total: stake, own: 1, @@ -2230,7 +2228,7 @@ fn reward_validator_slashing_validator_does_not_overflow() { // Check slashing on_offence_now( &[OffenceDetails { - offender: (11, Staking::eras_stakers(active_era(), 11)), + offender: (11, Staking::eras_stakers(active_era(), &11)), reporters: vec![], }], &[Perbill::from_percent(100)], @@ -2329,7 +2327,7 @@ fn offence_forces_new_era() { ExtBuilder::default().build_and_execute(|| { on_offence_now( &[OffenceDetails { - offender: (11, Staking::eras_stakers(active_era(), 11)), + offender: (11, Staking::eras_stakers(active_era(), &11)), reporters: vec![], }], &[Perbill::from_percent(5)], @@ -2347,7 +2345,7 @@ fn offence_ensures_new_era_without_clobbering() { on_offence_now( &[OffenceDetails { - offender: (11, Staking::eras_stakers(active_era(), 11)), + offender: (11, Staking::eras_stakers(active_era(), &11)), reporters: vec![], }], &[Perbill::from_percent(5)], @@ -2365,7 +2363,7 @@ fn offence_deselects_validator_even_when_slash_is_zero() { on_offence_now( &[OffenceDetails { - offender: (11, Staking::eras_stakers(active_era(), 11)), + offender: (11, Staking::eras_stakers(active_era(), &11)), reporters: vec![], }], &[Perbill::from_percent(0)], @@ -2386,7 +2384,7 @@ fn slashing_performed_according_exposure() { // This test checks that slashing is performed according the exposure (or more precisely, // historical exposure), not the current balance. ExtBuilder::default().build_and_execute(|| { - assert_eq!(Staking::eras_stakers(active_era(), 11).own, 1000); + assert_eq!(Staking::eras_stakers(active_era(), &11).own, 1000); // Handle an offence with a historical exposure. on_offence_now( @@ -2412,7 +2410,7 @@ fn slash_in_old_span_does_not_deselect() { on_offence_now( &[OffenceDetails { - offender: (11, Staking::eras_stakers(active_era(), 11)), + offender: (11, Staking::eras_stakers(active_era(), &11)), reporters: vec![], }], &[Perbill::from_percent(0)], @@ -2435,7 +2433,7 @@ fn slash_in_old_span_does_not_deselect() { on_offence_in_era( &[OffenceDetails { - offender: (11, Staking::eras_stakers(active_era(), 11)), + offender: (11, Staking::eras_stakers(active_era(), &11)), reporters: vec![], }], &[Perbill::from_percent(0)], @@ -2451,7 +2449,7 @@ fn slash_in_old_span_does_not_deselect() { on_offence_in_era( &[OffenceDetails { - offender: (11, Staking::eras_stakers(active_era(), 11)), + offender: (11, Staking::eras_stakers(active_era(), &11)), reporters: vec![], }], // NOTE: A 100% slash here would clean up the account, causing de-registration. @@ -2478,11 +2476,11 @@ fn reporters_receive_their_slice() { // The reporters' reward is calculated from the total exposure. let initial_balance = 1125; - assert_eq!(Staking::eras_stakers(active_era(), 11).total, initial_balance); + assert_eq!(Staking::eras_stakers(active_era(), &11).total, initial_balance); on_offence_now( &[OffenceDetails { - offender: (11, Staking::eras_stakers(active_era(), 11)), + offender: (11, Staking::eras_stakers(active_era(), &11)), reporters: vec![1, 2], }], &[Perbill::from_percent(50)], @@ -2505,11 +2503,11 @@ fn subsequent_reports_in_same_span_pay_out_less() { // The reporters' reward is calculated from the total exposure. let initial_balance = 1125; - assert_eq!(Staking::eras_stakers(active_era(), 11).total, initial_balance); + assert_eq!(Staking::eras_stakers(active_era(), &11).total, initial_balance); on_offence_now( &[OffenceDetails { - offender: (11, Staking::eras_stakers(active_era(), 11)), + offender: (11, Staking::eras_stakers(active_era(), &11)), reporters: vec![1], }], &[Perbill::from_percent(20)], @@ -2522,7 +2520,7 @@ fn subsequent_reports_in_same_span_pay_out_less() { on_offence_now( &[OffenceDetails { - offender: (11, Staking::eras_stakers(active_era(), 11)), + offender: (11, Staking::eras_stakers(active_era(), &11)), reporters: vec![1], }], &[Perbill::from_percent(50)], @@ -2544,7 +2542,7 @@ fn invulnerables_are_not_slashed() { assert_eq!(Balances::free_balance(11), 1000); assert_eq!(Balances::free_balance(21), 2000); - let exposure = Staking::eras_stakers(active_era(), 21); + let exposure = Staking::eras_stakers(active_era(), &21); let initial_balance = Staking::slashable_balance_of(&21); let nominator_balances: Vec<_> = @@ -2553,11 +2551,11 @@ fn invulnerables_are_not_slashed() { on_offence_now( &[ OffenceDetails { - offender: (11, Staking::eras_stakers(active_era(), 11)), + offender: (11, Staking::eras_stakers(active_era(), &11)), reporters: vec![], }, OffenceDetails { - offender: (21, Staking::eras_stakers(active_era(), 21)), + offender: (21, Staking::eras_stakers(active_era(), &21)), reporters: vec![], }, ], @@ -2587,7 +2585,7 @@ fn dont_slash_if_fraction_is_zero() { on_offence_now( &[OffenceDetails { - offender: (11, Staking::eras_stakers(active_era(), 11)), + offender: (11, Staking::eras_stakers(active_era(), &11)), reporters: vec![], }], &[Perbill::from_percent(0)], @@ -2608,7 +2606,7 @@ fn only_slash_for_max_in_era() { on_offence_now( &[OffenceDetails { - offender: (11, Staking::eras_stakers(active_era(), 11)), + offender: (11, Staking::eras_stakers(active_era(), &11)), reporters: vec![], }], &[Perbill::from_percent(50)], @@ -2620,7 +2618,7 @@ fn only_slash_for_max_in_era() { on_offence_now( &[OffenceDetails { - offender: (11, Staking::eras_stakers(active_era(), 11)), + offender: (11, Staking::eras_stakers(active_era(), &11)), reporters: vec![], }], &[Perbill::from_percent(25)], @@ -2631,7 +2629,7 @@ fn only_slash_for_max_in_era() { on_offence_now( &[OffenceDetails { - offender: (11, Staking::eras_stakers(active_era(), 11)), + offender: (11, Staking::eras_stakers(active_era(), &11)), reporters: vec![], }], &[Perbill::from_percent(60)], @@ -2653,7 +2651,7 @@ fn garbage_collection_after_slashing() { on_offence_now( &[OffenceDetails { - offender: (11, Staking::eras_stakers(active_era(), 11)), + offender: (11, Staking::eras_stakers(active_era(), &11)), reporters: vec![], }], &[Perbill::from_percent(10)], @@ -2665,7 +2663,7 @@ fn garbage_collection_after_slashing() { on_offence_now( &[OffenceDetails { - offender: (11, Staking::eras_stakers(active_era(), 11)), + offender: (11, Staking::eras_stakers(active_era(), &11)), reporters: vec![], }], &[Perbill::from_percent(100)], @@ -2702,12 +2700,12 @@ fn garbage_collection_on_window_pruning() { assert_eq!(Balances::free_balance(11), 1000); let now = active_era(); - let exposure = Staking::eras_stakers(now, 11); + let exposure = Staking::eras_stakers(now, &11); assert_eq!(Balances::free_balance(101), 2000); 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: vec![] }], &[Perbill::from_percent(10)], ); @@ -2742,14 +2740,14 @@ fn slashing_nominators_by_span_max() { assert_eq!(Balances::free_balance(101), 2000); assert_eq!(Staking::slashable_balance_of(&21), 1000); - let exposure_11 = Staking::eras_stakers(active_era(), 11); - let exposure_21 = Staking::eras_stakers(active_era(), 21); + let exposure_11 = Staking::eras_stakers(active_era(), &11); + let exposure_21 = Staking::eras_stakers(active_era(), &21); let nominated_value_11 = exposure_11.others.iter().find(|o| o.who == 101).unwrap().value; let nominated_value_21 = exposure_21.others.iter().find(|o| o.who == 101).unwrap().value; on_offence_in_era( &[OffenceDetails { - offender: (11, Staking::eras_stakers(active_era(), 11)), + offender: (11, Staking::eras_stakers(active_era(), &11)), reporters: vec![], }], &[Perbill::from_percent(10)], @@ -2776,7 +2774,7 @@ fn slashing_nominators_by_span_max() { // second slash: higher era, higher value, same span. on_offence_in_era( &[OffenceDetails { - offender: (21, Staking::eras_stakers(active_era(), 21)), + offender: (21, Staking::eras_stakers(active_era(), &21)), reporters: vec![], }], &[Perbill::from_percent(30)], @@ -2798,7 +2796,7 @@ fn slashing_nominators_by_span_max() { // in-era value, but lower slash value than slash 2. on_offence_in_era( &[OffenceDetails { - offender: (11, Staking::eras_stakers(active_era(), 11)), + offender: (11, Staking::eras_stakers(active_era(), &11)), reporters: vec![], }], &[Perbill::from_percent(20)], @@ -2833,7 +2831,7 @@ fn slashes_are_summed_across_spans() { on_offence_now( &[OffenceDetails { - offender: (21, Staking::eras_stakers(active_era(), 21)), + offender: (21, Staking::eras_stakers(active_era(), &21)), reporters: vec![], }], &[Perbill::from_percent(10)], @@ -2856,7 +2854,7 @@ fn slashes_are_summed_across_spans() { on_offence_now( &[OffenceDetails { - offender: (21, Staking::eras_stakers(active_era(), 21)), + offender: (21, Staking::eras_stakers(active_era(), &21)), reporters: vec![], }], &[Perbill::from_percent(10)], @@ -2880,7 +2878,7 @@ fn deferred_slashes_are_deferred() { assert_eq!(Balances::free_balance(11), 1000); - let exposure = Staking::eras_stakers(active_era(), 11); + let exposure = Staking::eras_stakers(active_era(), &11); assert_eq!(Balances::free_balance(101), 2000); let nominated_value = exposure.others.iter().find(|o| o.who == 101).unwrap().value; @@ -2888,7 +2886,7 @@ fn deferred_slashes_are_deferred() { on_offence_now( &[OffenceDetails { - offender: (11, Staking::eras_stakers(active_era(), 11)), + offender: (11, Staking::eras_stakers(active_era(), &11)), reporters: vec![], }], &[Perbill::from_percent(10)], @@ -2939,7 +2937,7 @@ fn retroactive_deferred_slashes_two_eras_before() { assert_eq!(BondingDuration::get(), 3); mock::start_active_era(1); - let exposure_11_at_era1 = Staking::eras_stakers(active_era(), 11); + let exposure_11_at_era1 = Staking::eras_stakers(active_era(), &11); mock::start_active_era(3); @@ -2975,7 +2973,7 @@ fn retroactive_deferred_slashes_one_before() { assert_eq!(BondingDuration::get(), 3); mock::start_active_era(1); - let exposure_11_at_era1 = Staking::eras_stakers(active_era(), 11); + let exposure_11_at_era1 = Staking::eras_stakers(active_era(), &11); // unbond at slash era. mock::start_active_era(2); @@ -3023,12 +3021,12 @@ fn staker_cannot_bail_deferred_slash() { assert_eq!(Balances::free_balance(11), 1000); assert_eq!(Balances::free_balance(101), 2000); - let exposure = Staking::eras_stakers(active_era(), 11); + let exposure = Staking::eras_stakers(active_era(), &11); let nominated_value = exposure.others.iter().find(|o| o.who == 101).unwrap().value; on_offence_now( &[OffenceDetails { - offender: (11, Staking::eras_stakers(active_era(), 11)), + offender: (11, Staking::eras_stakers(active_era(), &11)), reporters: vec![], }], &[Perbill::from_percent(10)], @@ -3097,7 +3095,7 @@ fn remove_deferred() { assert_eq!(Balances::free_balance(11), 1000); - let exposure = Staking::eras_stakers(active_era(), 11); + let exposure = Staking::eras_stakers(active_era(), &11); assert_eq!(Balances::free_balance(101), 2000); let nominated_value = exposure.others.iter().find(|o| o.who == 101).unwrap().value; @@ -3173,7 +3171,7 @@ fn remove_multi_deferred() { assert_eq!(Balances::free_balance(11), 1000); - let exposure = Staking::eras_stakers(active_era(), 11); + let exposure = Staking::eras_stakers(active_era(), &11); assert_eq!(Balances::free_balance(101), 2000); on_offence_now( @@ -3183,7 +3181,7 @@ fn remove_multi_deferred() { on_offence_now( &[OffenceDetails { - offender: (21, Staking::eras_stakers(active_era(), 21)), + offender: (21, Staking::eras_stakers(active_era(), &21)), reporters: vec![], }], &[Perbill::from_percent(10)], @@ -3613,7 +3611,7 @@ fn zero_slash_keeps_nominators() { assert_eq!(Balances::free_balance(11), 1000); - let exposure = Staking::eras_stakers(active_era(), 11); + let exposure = Staking::eras_stakers(active_era(), &11); assert_eq!(Balances::free_balance(101), 2000); on_offence_now( @@ -4661,7 +4659,7 @@ fn offences_weight_calculated_correctly() { >, > = (1..10) .map(|i| OffenceDetails { - offender: (i, Staking::eras_stakers(active_era(), i)), + offender: (i, Staking::eras_stakers(active_era(), &i)), reporters: vec![], }) .collect(); @@ -4677,7 +4675,7 @@ fn offences_weight_calculated_correctly() { // On Offence with one offenders, Applied let one_offender = [OffenceDetails { - offender: (11, Staking::eras_stakers(active_era(), 11)), + offender: (11, Staking::eras_stakers(active_era(), &11)), reporters: vec![1], }]; @@ -6457,7 +6455,7 @@ mod staking_interface { ExtBuilder::default().build_and_execute(|| { on_offence_now( &[OffenceDetails { - offender: (11, Staking::eras_stakers(active_era(), 11)), + offender: (11, Staking::eras_stakers(active_era(), &11)), reporters: vec![], }], &[Perbill::from_percent(100)], From ed8c993383fafae2b58281dbb8bf7bf62e996aed Mon Sep 17 00:00:00 2001 From: Ankan Date: Mon, 20 Feb 2023 22:23:24 +0100 Subject: [PATCH 144/162] clean up page_count --- frame/staking/src/pallet/mod.rs | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index 33728953f3fe7..5c7c454040126 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -687,8 +687,11 @@ pub mod pallet { let exposure_page = >::get(era, (validator, page)).unwrap_or_default(); let own = if page == 0 { overview.own } else { Zero::zero() }; - Some(ExposureExt { exposure_overview: ExposureOverview { own, ..overview }, exposure_page }) - } + Some(ExposureExt { + exposure_overview: ExposureOverview { own, ..overview }, + exposure_page, + }) + }, _ => None, } } @@ -712,15 +715,19 @@ pub mod pallet { /// /// This will always return at minimum one count of exposure to be backward compatible to /// non-paged reward payouts. - // FIXME: No need to return minimum of one page after cleanup: #13034 pub(crate) fn get_page_count(era: EraIndex, validator: &T::AccountId) -> PageIndex { - if let Some(overview) = >::get(&era, validator) { - // Paged exposure - overview.page_count.max(1) - } else { - // Non-paged exposure - 1 - } + >::get(&era, validator) + .map(|overview| { + if overview.page_count == 0 && overview.own > Zero::zero() { + // this means the validator has their own stake but no nominators + 1 + } else { + overview.page_count + } + }) + // FIXME: Returns minimum of one page for backward compatibility with non paged + // exposure. Can be removed when we clean up issue #13034. + .unwrap_or(1) } /// Returns the next page that can be claimed or `None` if nothing to claim. From 263440387c5b0aca464f6ba02ea8fc204756879e Mon Sep 17 00:00:00 2001 From: Ankan Date: Mon, 20 Feb 2023 22:35:38 +0100 Subject: [PATCH 145/162] more readable validator exposure calculation --- frame/staking/src/pallet/mod.rs | 41 ++++++++++++++++++++------------- 1 file changed, 25 insertions(+), 16 deletions(-) diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index 5c7c454040126..05ece2db0692f 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -677,23 +677,32 @@ pub mod pallet { validator: &T::AccountId, page: PageIndex, ) -> Option>> { - match >::get(&era, validator) { - // return clipped exposure if page zero and paged exposure does not exist - None if page == 0 => - Some(ExposureExt::from_clipped(>::get(era, validator))), - - // return paged exposure if it exists - Some(overview) => { - let exposure_page = - >::get(era, (validator, page)).unwrap_or_default(); - let own = if page == 0 { overview.own } else { Zero::zero() }; - Some(ExposureExt { - exposure_overview: ExposureOverview { own, ..overview }, - exposure_page, - }) - }, - _ => None, + let overview = >::get(&era, validator); + + // return clipped exposure if page zero and paged exposure does not exist + // exists for backward compatibility and can be removed as part of #13034 + if overview.is_none() && page == 0 { + return Some(ExposureExt::from_clipped(>::get(era, validator))) + } + + // no exposure for this validator + if overview.is_none() { + return None } + + let overview = overview.unwrap(); + + // validator stake is added only in page zero + let validator_stake = if page == 0 { overview.own } else { Zero::zero() }; + + let exposure_page = + >::get(era, (validator, page)).unwrap_or_default(); + + // build the exposure + Some(ExposureExt { + exposure_overview: ExposureOverview { own: validator_stake, ..overview }, + exposure_page, + }) } pub(crate) fn get_validator_overview( From 5f5abad8c110e49569c8149f4a658d65de54e443 Mon Sep 17 00:00:00 2001 From: Ankan Date: Mon, 20 Feb 2023 22:35:58 +0100 Subject: [PATCH 146/162] fmt --- frame/staking/src/pallet/impls.rs | 13 ++++++++++--- frame/staking/src/tests.rs | 5 ++++- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index d3ea2d4f5f1c3..7fbb4a5528695 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -42,7 +42,11 @@ use sp_staking::{ }; use sp_std::prelude::*; -use crate::{log, slashing, weights::WeightInfo, ActiveEraInfo, BalanceOf, EraPayout, Exposure, ExposureOf, Forcing, IndividualExposure, MaxWinnersOf, Nominations, PositiveImbalanceOf, RewardDestination, SessionInterface, StakingLedger, ValidatorPrefs}; +use crate::{ + log, slashing, weights::WeightInfo, ActiveEraInfo, BalanceOf, EraPayout, Exposure, ExposureOf, + Forcing, IndividualExposure, MaxWinnersOf, Nominations, PositiveImbalanceOf, RewardDestination, + SessionInterface, StakingLedger, ValidatorPrefs, +}; use super::{pallet::*, STAKING_ID}; @@ -992,10 +996,13 @@ impl Pallet { ); } - pub fn eras_stakers(era: EraIndex, account: &T::AccountId) -> Exposure> { + pub fn eras_stakers( + era: EraIndex, + account: &T::AccountId, + ) -> Exposure> { let overview = EraInfo::::get_validator_overview(era, &account).unwrap_or_default(); if overview.page_count == 0 { - return Exposure { total: overview.total, own: overview.own, others: vec![] }; + return Exposure { total: overview.total, own: overview.own, others: vec![] } } let mut others = Vec::with_capacity(overview.nominator_count as usize); diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index dc9cdd912cd98..79ff87fd12145 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -2705,7 +2705,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: vec![], + }], &[Perbill::from_percent(10)], ); From 9ad77cb02ca3c312cd7f17631a090cb50f87d0b8 Mon Sep 17 00:00:00 2001 From: Ankan Date: Mon, 20 Feb 2023 22:52:22 +0100 Subject: [PATCH 147/162] do not use ErasStakers anymore --- frame/staking/src/pallet/mod.rs | 2 +- frame/staking/src/tests.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index 05ece2db0692f..cf7f426360d5b 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -802,7 +802,7 @@ pub mod pallet { validator: &T::AccountId, exposure: Exposure>, ) { - >::insert(era, &validator, &exposure); + // >::insert(era, &validator, &exposure); let page_size = T::MaxExposurePageSize::get().defensive_max(1); let max_page_count = T::MaxExposurePageCount::get(); diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index 79ff87fd12145..95cc264d9df3d 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -617,7 +617,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); - assert_eq!(ErasStakers::::iter_prefix_values(active_era()).count(), 2); + assert_eq!(ErasStakersPaged::::iter_prefix_values(active_era()).count(), 2); assert_eq!( Staking::eras_stakers(active_era(), &11), Exposure { From 7dfb3e8d7a21e0d350fb818795ee84c5d9640376 Mon Sep 17 00:00:00 2001 From: Ankan Date: Mon, 20 Feb 2023 23:14:26 +0100 Subject: [PATCH 148/162] defensive unwrap for appending nominator pages to eras stakers --- frame/staking/src/pallet/impls.rs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index 7fbb4a5528695..26faf41963907 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -1000,7 +1000,14 @@ impl Pallet { era: EraIndex, account: &T::AccountId, ) -> Exposure> { - let overview = EraInfo::::get_validator_overview(era, &account).unwrap_or_default(); + let overview = EraInfo::::get_validator_overview(era, &account); + + if overview.is_none() { + return ErasStakers::::get(era, account); + } + + let overview = overview.unwrap(); + if overview.page_count == 0 { return Exposure { total: overview.total, own: overview.own, others: vec![] } } @@ -1008,8 +1015,7 @@ impl Pallet { let mut others = Vec::with_capacity(overview.nominator_count as usize); for page in 0..overview.page_count { let nominators = EraInfo::::get_nominators_page(era, &account, page); - // TODO(ank4n) fix to defensive unwrap - others.append(&mut nominators.unwrap().others); + others.append(&mut nominators.map(|n| n.others).defensive_unwrap_or_default()); } Exposure { total: overview.total, own: overview.own, others } From fd2f6fbec709bf0fdf1895cec50c8abaec5c6704 Mon Sep 17 00:00:00 2001 From: Ankan Date: Mon, 20 Feb 2023 23:18:13 +0100 Subject: [PATCH 149/162] better fn naming --- frame/staking/src/pallet/impls.rs | 2 +- frame/staking/src/pallet/mod.rs | 9 +++++---- frame/staking/src/tests.rs | 16 ++++++++-------- 3 files changed, 14 insertions(+), 13 deletions(-) diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index 26faf41963907..995ef211e496e 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -189,7 +189,7 @@ impl Pallet { .retain(|&x| x >= current_era.saturating_sub(history_depth)); >::insert(&controller, &ledger); - if EraInfo::::is_rewards_claimed_temp(era, &ledger, &ledger.stash, page) { + if EraInfo::::is_rewards_claimed_with_legacy_fallback(era, &ledger, &ledger.stash, page) { return Err(Error::::AlreadyClaimed .with_weight(T::WeightInfo::payout_stakers_alive_staked(0))) } else { diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index cf7f426360d5b..e3ac281384cb2 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -650,7 +650,7 @@ pub mod pallet { /// removed once `$HistoryDepth` eras have passed and none of the older non-paged rewards /// are relevant/claimable. // Refer tracker issue for cleanup: #13034 - pub(crate) fn is_rewards_claimed_temp( + pub(crate) fn is_rewards_claimed_with_legacy_fallback( era: EraIndex, ledger: &StakingLedger, validator: &T::AccountId, @@ -663,7 +663,8 @@ pub mod pallet { /// Check if the rewards for the given era and page index have been claimed. /// /// This is only used for paged rewards. Once older non-paged rewards are no longer - /// relevant, `is_rewards_claimed_temp` can be removed and this function can be made public. + /// relevant, `is_rewards_claimed_with_legacy_fallback` can be removed and this function can + /// be made public. fn is_rewards_claimed(era: EraIndex, validator: &T::AccountId, page: PageIndex) -> bool { ClaimedRewards::::get(era, validator).contains(&page) } @@ -734,8 +735,8 @@ pub mod pallet { overview.page_count } }) - // FIXME: Returns minimum of one page for backward compatibility with non paged - // exposure. Can be removed when we clean up issue #13034. + // Returns minimum of one page for backward compatibility with non paged exposure. + // FIXME: Can be cleaned up with issue #13034. .unwrap_or(1) } diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index 95cc264d9df3d..6703b05114eaa 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -3873,7 +3873,7 @@ fn test_multi_page_payout_stakers_by_page() { // verify rewards are tracked to prevent double claims for page in 0..EraInfo::::get_page_count(1, &11) { assert_eq!( - EraInfo::::is_rewards_claimed_temp(1, ledger.as_ref().unwrap(), &11, page), + EraInfo::::is_rewards_claimed_with_legacy_fallback(1, ledger.as_ref().unwrap(), &11, page), true ); } @@ -3898,7 +3898,7 @@ fn test_multi_page_payout_stakers_by_page() { // verify we track rewards for each era and page for page in 0..EraInfo::::get_page_count(i - 1, &11) { assert_eq!( - EraInfo::::is_rewards_claimed_temp( + EraInfo::::is_rewards_claimed_with_legacy_fallback( i - 1, Staking::ledger(&10).as_ref().unwrap(), &11, @@ -4078,7 +4078,7 @@ fn test_multi_page_payout_stakers_backward_compatible() { // verify rewards are tracked to prevent double claims for page in 0..EraInfo::::get_page_count(1, &11) { assert_eq!( - EraInfo::::is_rewards_claimed_temp(1, ledger.as_ref().unwrap(), &11, page), + EraInfo::::is_rewards_claimed_with_legacy_fallback(1, ledger.as_ref().unwrap(), &11, page), true ); } @@ -4103,7 +4103,7 @@ fn test_multi_page_payout_stakers_backward_compatible() { // verify we track rewards for each era and page for page in 0..EraInfo::::get_page_count(i - 1, &11) { assert_eq!( - EraInfo::::is_rewards_claimed_temp( + EraInfo::::is_rewards_claimed_with_legacy_fallback( i - 1, Staking::ledger(&10).as_ref().unwrap(), &11, @@ -6260,7 +6260,7 @@ fn test_legacy_claimed_rewards_is_checked_at_reward_payout() { //verify rewards are not claimed assert_eq!( - EraInfo::::is_rewards_claimed_temp( + EraInfo::::is_rewards_claimed_with_legacy_fallback( 1, Staking::ledger(10).as_ref().unwrap(), &11, @@ -6269,7 +6269,7 @@ fn test_legacy_claimed_rewards_is_checked_at_reward_payout() { false ); assert_eq!( - EraInfo::::is_rewards_claimed_temp( + EraInfo::::is_rewards_claimed_with_legacy_fallback( 2, Staking::ledger(10).as_ref().unwrap(), &11, @@ -6297,7 +6297,7 @@ fn test_legacy_claimed_rewards_is_checked_at_reward_payout() { .with_weight(::WeightInfo::payout_stakers_alive_staked(0)), ); assert_eq!( - EraInfo::::is_rewards_claimed_temp( + EraInfo::::is_rewards_claimed_with_legacy_fallback( 1, Staking::ledger(10).as_ref().unwrap(), &11, @@ -6309,7 +6309,7 @@ fn test_legacy_claimed_rewards_is_checked_at_reward_payout() { // verify rewards for era 2 can be claimed assert_ok!(Staking::payout_stakers_by_page(RuntimeOrigin::signed(1337), 11, 2, 0)); assert_eq!( - EraInfo::::is_rewards_claimed_temp( + EraInfo::::is_rewards_claimed_with_legacy_fallback( 2, Staking::ledger(10).as_ref().unwrap(), &11, From 45ad6e144c7ec1f99f338d17cb8018dea02ed968 Mon Sep 17 00:00:00 2001 From: Ankan Date: Mon, 20 Feb 2023 23:18:40 +0100 Subject: [PATCH 150/162] fmt --- frame/staking/src/pallet/impls.rs | 5 +++-- frame/staking/src/tests.rs | 14 ++++++++++++-- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index 995ef211e496e..273515dff2ce4 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -189,7 +189,8 @@ impl Pallet { .retain(|&x| x >= current_era.saturating_sub(history_depth)); >::insert(&controller, &ledger); - if EraInfo::::is_rewards_claimed_with_legacy_fallback(era, &ledger, &ledger.stash, page) { + if EraInfo::::is_rewards_claimed_with_legacy_fallback(era, &ledger, &ledger.stash, page) + { return Err(Error::::AlreadyClaimed .with_weight(T::WeightInfo::payout_stakers_alive_staked(0))) } else { @@ -1003,7 +1004,7 @@ impl Pallet { let overview = EraInfo::::get_validator_overview(era, &account); if overview.is_none() { - return ErasStakers::::get(era, account); + return ErasStakers::::get(era, account) } let overview = overview.unwrap(); diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index 6703b05114eaa..1ee844db8b9b5 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -3873,7 +3873,12 @@ fn test_multi_page_payout_stakers_by_page() { // verify rewards are tracked to prevent double claims for page in 0..EraInfo::::get_page_count(1, &11) { assert_eq!( - EraInfo::::is_rewards_claimed_with_legacy_fallback(1, ledger.as_ref().unwrap(), &11, page), + EraInfo::::is_rewards_claimed_with_legacy_fallback( + 1, + ledger.as_ref().unwrap(), + &11, + page + ), true ); } @@ -4078,7 +4083,12 @@ fn test_multi_page_payout_stakers_backward_compatible() { // verify rewards are tracked to prevent double claims for page in 0..EraInfo::::get_page_count(1, &11) { assert_eq!( - EraInfo::::is_rewards_claimed_with_legacy_fallback(1, ledger.as_ref().unwrap(), &11, page), + EraInfo::::is_rewards_claimed_with_legacy_fallback( + 1, + ledger.as_ref().unwrap(), + &11, + page + ), true ); } From d49de8bc56c05d5ea452ec2670769714aa375839 Mon Sep 17 00:00:00 2001 From: Ankan Date: Mon, 20 Feb 2023 23:30:20 +0100 Subject: [PATCH 151/162] move logic to combine all exposure into EraInfo --- frame/staking/src/pallet/impls.rs | 25 ++++++----------------- frame/staking/src/pallet/mod.rs | 34 +++++++++++++++++++++---------- 2 files changed, 29 insertions(+), 30 deletions(-) diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index 273515dff2ce4..aa6ed954d094e 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -997,29 +997,16 @@ impl Pallet { ); } + /// Returns full exposure of a validator for a given era. + /// + /// History note: This used to be a getter for old storage item `ErasStakers` deprecated in v14. + /// Since this function is used in the codebase at various places, we kept it as a custom getter + /// that takes care of getting the full exposure of the validator in a backward compatible way. pub fn eras_stakers( era: EraIndex, account: &T::AccountId, ) -> Exposure> { - let overview = EraInfo::::get_validator_overview(era, &account); - - if overview.is_none() { - return ErasStakers::::get(era, account) - } - - let overview = overview.unwrap(); - - if overview.page_count == 0 { - return Exposure { total: overview.total, own: overview.own, others: vec![] } - } - - let mut others = Vec::with_capacity(overview.nominator_count as usize); - for page in 0..overview.page_count { - let nominators = EraInfo::::get_nominators_page(era, &account, page); - others.append(&mut nominators.map(|n| n.others).defensive_unwrap_or_default()); - } - - Exposure { total: overview.total, own: overview.own, others } + EraInfo::::get_non_paged_validator_exposure(era, &account) } } diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index e3ac281384cb2..5e9ea0a49259d 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -417,8 +417,9 @@ pub mod pallet { /// /// Is it removed after `HISTORY_DEPTH` eras. /// If stakers hasn't been set or has been removed then empty exposure is returned. + /// + /// Note: Deprecated since v14. Use `EraInfo` instead to work with exposures. #[pallet::storage] - // #[pallet::getter(fn eras_stakers)] #[pallet::unbounded] pub type ErasStakers = StorageDoubleMap< _, @@ -706,19 +707,30 @@ pub mod pallet { }) } - pub(crate) fn get_validator_overview( + /// Get complete exposure of the validator at a given era. + pub(crate) fn get_non_paged_validator_exposure( era: EraIndex, validator: &T::AccountId, - ) -> Option>> { - >::get(&era, validator) - } + ) -> Exposure> { + let overview = >::get(&era, validator); - pub(crate) fn get_nominators_page( - era: EraIndex, - validator: &T::AccountId, - page: PageIndex, - ) -> Option>> { - >::get(era, (validator, page)) + if overview.is_none() { + return ErasStakers::::get(era, validator) + } + + let overview = overview.unwrap(); + + if overview.page_count == 0 { + return Exposure { total: overview.total, own: overview.own, others: vec![] } + } + + let mut others = Vec::with_capacity(overview.nominator_count as usize); + for page in 0..overview.page_count { + let nominators = >::get(era, (validator, page)); + others.append(&mut nominators.map(|n| n.others).defensive_unwrap_or_default()); + } + + Exposure { total: overview.total, own: overview.own, others } } /// Returns the number of pages of exposure a validator has for the given era. From c67e8bd69f470d57424f16869cf237ac33db7049 Mon Sep 17 00:00:00 2001 From: Ankan Date: Mon, 20 Feb 2023 23:39:33 +0100 Subject: [PATCH 152/162] remove useless getters --- frame/staking/src/lib.rs | 20 +++++++++++++++----- frame/staking/src/pallet/mod.rs | 9 ++++----- 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index 8368d4c38db67..3b69bd3439836 100644 --- a/frame/staking/src/lib.rs +++ b/frame/staking/src/lib.rs @@ -734,7 +734,7 @@ impl Default for Exposure +impl Exposure { /// Splits an `Exposure` into `ExposureOverview` and multiple chunks of `IndividualExposure` @@ -794,9 +794,19 @@ impl Default for ExposurePage { /// It, in combination with a list of `ExposurePage`s, can be used to reconstruct a full `Exposure` /// struct. This is useful for cases where we want to query a single page of `Exposure`s. #[derive( - PartialEq, Eq, PartialOrd, Ord, Clone, Encode, Decode, RuntimeDebug, TypeInfo, Default, + PartialEq, + Eq, + PartialOrd, + Ord, + Clone, + Encode, + Decode, + RuntimeDebug, + TypeInfo, + Default, + MaxEncodedLen, )] -pub struct ExposureOverview { +pub struct ExposureOverview { /// The total balance backing this validator. #[codec(compact)] pub total: Balance, @@ -814,12 +824,12 @@ pub struct ExposureOverview { /// This is useful where we need to take into account the validator's own stake and total exposure /// in consideration, in addition to the individual nominators backing them. #[derive(Encode, Decode, RuntimeDebug, TypeInfo, PartialEq, Eq)] -struct ExposureExt { +struct ExposureExt { exposure_overview: ExposureOverview, exposure_page: ExposurePage, } -impl ExposureExt { +impl ExposureExt { /// Create a new instance of `ExposureExt` from legacy clipped exposures. pub fn from_clipped(exposure: Exposure) -> Self { Self { diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index 5e9ea0a49259d..92f0b519167f1 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -443,8 +443,6 @@ pub mod pallet { /// Is it removed after `HISTORY_DEPTH` eras. /// If stakers hasn't been set or has been removed then empty overview is returned. #[pallet::storage] - #[pallet::getter(fn eras_stakers_overview)] - #[pallet::unbounded] pub type ErasStakersOverview = StorageDoubleMap< _, Twox64Concat, @@ -469,6 +467,8 @@ pub mod pallet { /// /// It is removed after `HISTORY_DEPTH` eras. /// If stakers hasn't been set or has been removed then empty exposure is returned. + /// + /// Note: Deprecated since v14. Use `EraInfo` instead to work with exposures. #[pallet::storage] #[pallet::unbounded] #[pallet::getter(fn eras_stakers_clipped)] @@ -489,8 +489,9 @@ pub mod pallet { /// /// This uses DoubleMap instead of NMap to efficiently clear this after `HISTORY_DEPTH` eras. /// If stakers hasn't been set or has been removed then empty exposure is returned. + /// + /// TODO(ank4n): Use NMAP and make sure it can be cleared by 1st key. #[pallet::storage] - #[pallet::getter(fn eras_stakers_paged)] #[pallet::unbounded] pub type ErasStakersPaged = StorageDoubleMap< _, @@ -815,8 +816,6 @@ pub mod pallet { validator: &T::AccountId, exposure: Exposure>, ) { - // >::insert(era, &validator, &exposure); - let page_size = T::MaxExposurePageSize::get().defensive_max(1); let max_page_count = T::MaxExposurePageCount::get(); From 06627f0e7d855adde142c5514fca36b4e0ed4ed0 Mon Sep 17 00:00:00 2001 From: Ankan Date: Mon, 20 Feb 2023 23:40:23 +0100 Subject: [PATCH 153/162] bounded ExposureOverview --- frame/staking/src/lib.rs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index 3b69bd3439836..0ffa7c636f12b 100644 --- a/frame/staking/src/lib.rs +++ b/frame/staking/src/lib.rs @@ -734,8 +734,10 @@ impl Default for Exposure - Exposure +impl< + AccountId: Clone, + Balance: HasCompact + AtLeast32BitUnsigned + Copy + codec::MaxEncodedLen, + > Exposure { /// Splits an `Exposure` into `ExposureOverview` and multiple chunks of `IndividualExposure` /// with each chunk having maximum of `page_size` elements. @@ -829,7 +831,9 @@ struct ExposureExt { exposure_page: ExposurePage, } -impl ExposureExt { +impl + ExposureExt +{ /// Create a new instance of `ExposureExt` from legacy clipped exposures. pub fn from_clipped(exposure: Exposure) -> Self { Self { From 89820f9910d2535b85b675d900afda00fc2d4a6f Mon Sep 17 00:00:00 2001 From: Ankan Date: Mon, 20 Feb 2023 23:50:28 +0100 Subject: [PATCH 154/162] remove unused fn --- frame/staking/src/lib.rs | 6 ------ frame/staking/src/tests.rs | 2 +- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index 0ffa7c636f12b..373c2c6489658 100644 --- a/frame/staking/src/lib.rs +++ b/frame/staking/src/lib.rs @@ -866,12 +866,6 @@ impl &Vec> { &self.exposure_page.others } - - /// Returns the number of pages of nominators stashes that are exposed. - #[allow(dead_code)] - pub fn page_count(&self) -> PageIndex { - self.exposure_overview.page_count - } } /// A pending slash record. The value of the slash has been computed but not applied yet, diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index 1ee844db8b9b5..099f437f8df32 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -6421,7 +6421,7 @@ fn test_validator_exposure_is_backward_compatible_with_non_paged_rewards_payout( let actual_exposure = EraInfo::::get_validator_exposure(1, &11, 0).unwrap(); assert_eq!(actual_exposure.others(), &clipped_exposure); assert_eq!(actual_exposure.own(), 1000); - assert_eq!(actual_exposure.page_count(), 1); + assert_eq!(actual_exposure.exposure_overview.page_count, 1); // for pages other than 0, clipped storage returns empty exposure assert_eq!(EraInfo::::get_validator_exposure(1, &11, 1), None); From 66c8fe14e5225b8f7acad1ec4d43f578f9e7ecf0 Mon Sep 17 00:00:00 2001 From: Ankan Date: Wed, 22 Feb 2023 11:34:22 +0100 Subject: [PATCH 155/162] ErasStakers backward compatible test --- frame/staking/src/tests.rs | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index 099f437f8df32..9c27f803fa87f 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -497,7 +497,7 @@ fn less_than_needed_candidates_works() { // But the exposure is updated in a simple way. No external votes exists. // This is purely self-vote. - assert!(ErasStakers::::iter_prefix_values(active_era()) + assert!(ErasStakersPaged::::iter_prefix_values(active_era()) .all(|exposure| exposure.others.is_empty())); }); } @@ -1736,7 +1736,7 @@ 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![] }); + EraInfo::::set_validator_exposure(0, &21, Exposure { total: 69, own: 69, others: vec![] }); >::insert( &20, StakingLedger { @@ -6403,11 +6403,13 @@ fn test_validator_exposure_is_backward_compatible_with_non_paged_rewards_payout( ); assert_eq!(EraInfo::::get_page_count(1, &11), 2); - // case 2: exposure exist in clipped storage. + // case 2: exposure exist in ErasStakers and ErasStakersClipped (legacy). // delete paged storage and add exposure to clipped storage >::remove(1, (11, 0)); >::remove(1, (11, 1)); >::remove(1, 11); + + >::insert(1, 11, Exposure { total: total_exposure, own: 1000, others: expected_individual_exposures.clone() }); let mut clipped_exposure = expected_individual_exposures.clone(); clipped_exposure.sort_by(|a, b| b.who.cmp(&a.who)); clipped_exposure.truncate(10); @@ -6418,10 +6420,15 @@ fn test_validator_exposure_is_backward_compatible_with_non_paged_rewards_payout( ); // verify `EraInfo` returns exposure from clipped storage - let actual_exposure = EraInfo::::get_validator_exposure(1, &11, 0).unwrap(); - assert_eq!(actual_exposure.others(), &clipped_exposure); - assert_eq!(actual_exposure.own(), 1000); - assert_eq!(actual_exposure.exposure_overview.page_count, 1); + let actual_exposure_paged = EraInfo::::get_validator_exposure(1, &11, 0).unwrap(); + assert_eq!(actual_exposure_paged.others(), &clipped_exposure); + assert_eq!(actual_exposure_paged.own(), 1000); + assert_eq!(actual_exposure_paged.exposure_overview.page_count, 1); + + let actual_exposure_full = EraInfo::::get_non_paged_validator_exposure(1, &11); + assert_eq!(actual_exposure_full.others, expected_individual_exposures); + assert_eq!(actual_exposure_full.own, 1000); + assert_eq!(actual_exposure_full.total, total_exposure); // for pages other than 0, clipped storage returns empty exposure assert_eq!(EraInfo::::get_validator_exposure(1, &11, 1), None); From b5fa46e9c541372d6d3835b46c73e3fc332fefa8 Mon Sep 17 00:00:00 2001 From: Ankan Date: Wed, 22 Feb 2023 11:34:46 +0100 Subject: [PATCH 156/162] fmt --- frame/staking/src/tests.rs | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index 9c27f803fa87f..4df8266ee4fae 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -1736,7 +1736,11 @@ fn reward_to_stake_works() { let _ = Balances::make_free_balance_be(&20, 1000); // Bypass logic and change current exposure - EraInfo::::set_validator_exposure(0, &21, Exposure { total: 69, own: 69, others: vec![] }); + EraInfo::::set_validator_exposure( + 0, + &21, + Exposure { total: 69, own: 69, others: vec![] }, + ); >::insert( &20, StakingLedger { @@ -6409,7 +6413,15 @@ fn test_validator_exposure_is_backward_compatible_with_non_paged_rewards_payout( >::remove(1, (11, 1)); >::remove(1, 11); - >::insert(1, 11, Exposure { total: total_exposure, own: 1000, others: expected_individual_exposures.clone() }); + >::insert( + 1, + 11, + Exposure { + total: total_exposure, + own: 1000, + others: expected_individual_exposures.clone(), + }, + ); let mut clipped_exposure = expected_individual_exposures.clone(); clipped_exposure.sort_by(|a, b| b.who.cmp(&a.who)); clipped_exposure.truncate(10); From 12ed262ebab1d5918aaaa7a0b7152b993807e397 Mon Sep 17 00:00:00 2001 From: Ankan Date: Wed, 22 Feb 2023 12:22:31 +0100 Subject: [PATCH 157/162] update changelog --- frame/staking/CHANGELOG.md | 57 +++++++++------------------------ frame/staking/src/migrations.rs | 41 ++++++++++++++++++++++++ frame/staking/src/pallet/mod.rs | 4 +-- 3 files changed, 58 insertions(+), 44 deletions(-) diff --git a/frame/staking/CHANGELOG.md b/frame/staking/CHANGELOG.md index 8f39fe86c9937..41b1e9ab7184c 100644 --- a/frame/staking/CHANGELOG.md +++ b/frame/staking/CHANGELOG.md @@ -2,53 +2,26 @@ All notable changes to this project will be documented in this file. -The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), -and this project adheres -to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). - -The semantic versioning guarantees cover the interface to the substrate runtime -which -includes this pallet as a dependency. This module will also add storage -migrations whenever -changes require it. Stability with regard to offchain tooling is explicitly -excluded from -this guarantee: For example adding a new field to an in-storage data structure -will require -changes to frontends to properly display it. However, those changes will still -be regarded -as a minor version bump. - -[//]: # TODO(ank4n) these versions should be same as storage version - -## [5.0.0] - UNRELEASED +The format is loosely based +on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). We maintain a +single integer version number for staking pallet to keep track of all storage +migrations. + +## [14] - UNRELEASED ### Added -- Unlimited number of nominators can be rewarded. - for a single call for reward payout. -- New config item `MaxExposurePageCount` to weakly bound the maximum number of - exposure pages that can exist. When set to 1, we get the same behaviour of top - n nominators eligible for reward as previously with non paged exposures. -- New storage item `ErasStakersPaged` that keeps up to `MaxExposurePageSize` +- New item `ErasStakersPaged` that keeps up to `MaxExposurePageSize` individual nominator exposures by era, validator and page. -- New storage item `ErasStakersOverview` which complements `ErasStakersPaged` - and keeps track of validator's own stake and total backing stake for each era. -- New call `payout_stakers_by_page` that allows to payout rewards for a single - validator by passing the page explicitly. -- New storage item `ClaimedRewards` that keeps track of claimed reward history - of a validator by era and page. - -### Changed - -- `payout_stakers` can be called multiple times for the same era if the - validator has more than `MaxExposurePageSize` nominators backing them. -- `MaxNominatorRewardedPerValidator` is renamed to `MaxExposurePageSize`. +- New item `ErasStakersOverview` complementary to `ErasStakersPaged` which keeps + state of own and total stake of the validator across pages. +- New item `ClaimedRewards` to support paged rewards payout. ### Deprecated -- `ErasStakersClipped` is deprecated in favor of `ErasStakersPaged`. In 84 - eras, `ErasStakersClipped` will be removed. -- `StakingLedger.claimed_rewards` is renamed - to `StakingLedger.legacy_claimed_rewards` and is deprecated. +- `ErasStakersClipped` is deprecated and may be removed after 84 eras. +- `ErasStakers` is deprecated and may be removed after 84 eras. +- Field `claimed_rewards` in item `Ledger` is renamed + to `legacy_claimed_rewards` and may be removed after 84 eras. -[5.0.0]: https://github.com/paritytech/substrate/pull/13059 +[14]: https://github.com/paritytech/substrate/pull/13059 diff --git a/frame/staking/src/migrations.rs b/frame/staking/src/migrations.rs index a8d360c098137..39f7766b1a327 100644 --- a/frame/staking/src/migrations.rs +++ b/frame/staking/src/migrations.rs @@ -52,6 +52,47 @@ impl Default for ObsoleteReleases { #[storage_alias] type StorageVersion = StorageValue, ObsoleteReleases, ValueQuery>; +pub mod v14 { + use super::*; + + pub struct MigrateToV14(sp_std::marker::PhantomData); + impl OnRuntimeUpgrade for MigrateToV14 { + fn on_runtime_upgrade() -> Weight { + let current = Pallet::::current_storage_version(); + let on_chain = Pallet::::on_chain_storage_version(); + + if current == 14 && on_chain == 13 { + current.put::>(); + + log!(info, "v14 applied successfully."); + T::DbWeight::get().reads_writes(1, 1) + } else { + log!(warn, "v14 not applied."); + T::DbWeight::get().reads(1) + } + } + + #[cfg(feature = "try-runtime")] + fn pre_upgrade() -> Result, &'static str> { + frame_support::ensure!( + Pallet::::on_chain_storage_version() == 13, + "Required v13 before upgrading to v14." + ); + + Ok(Default::default()) + } + + #[cfg(feature = "try-runtime")] + fn post_upgrade(_state: Vec) -> Result<(), &'static str> { + frame_support::ensure!( + Pallet::::on_chain_storage_version() == 14, + "v14 not applied" + ); + Ok(()) + } + } +} + pub mod v13 { use super::*; diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index 92f0b519167f1..0921385e7dde2 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -65,8 +65,7 @@ pub mod pallet { use super::*; /// The current storage version. - /// TODO(ank4n) bump up - const STORAGE_VERSION: StorageVersion = StorageVersion::new(13); + const STORAGE_VERSION: StorageVersion = StorageVersion::new(14); #[pallet::pallet] #[pallet::generate_store(pub(crate) trait Store)] @@ -223,6 +222,7 @@ pub mod pallet { /// /// When this is set to 1, the reward payout behaviour is similar to how it used to work /// before we had paged exposures. + #[pallet::constant] type MaxExposurePageCount: Get; /// The fraction of the validator set that is safe to be offending. From 14bc8b3e9730a5956638f8661d3b3cc1b165aaf5 Mon Sep 17 00:00:00 2001 From: Ankan Date: Wed, 22 Feb 2023 13:31:48 +0100 Subject: [PATCH 158/162] Use NMap for ErasStakersPaged --- frame/staking/src/pallet/impls.rs | 2 +- frame/staking/src/pallet/mod.rs | 26 ++++++++++++-------------- frame/staking/src/tests.rs | 19 +++++++++---------- 3 files changed, 22 insertions(+), 25 deletions(-) diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index aa6ed954d094e..f6366e91ccd2f 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -696,7 +696,7 @@ impl Pallet { #[allow(deprecated)] >::remove_prefix(era_index, None); #[allow(deprecated)] - >::remove_prefix(era_index, None); + >::remove_prefix((era_index,), None); #[allow(deprecated)] >::remove_prefix(era_index, None); diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index 0921385e7dde2..194411f530d3c 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -484,21 +484,19 @@ pub mod pallet { /// Paginated exposure of a validator at given era. /// - /// This is keyed first by the era index to allow bulk deletion, then the tuple of stash account - /// and page. + /// This is keyed first by the era index to allow bulk deletion, then stash account and finally + /// the page. /// - /// This uses DoubleMap instead of NMap to efficiently clear this after `HISTORY_DEPTH` eras. - /// If stakers hasn't been set or has been removed then empty exposure is returned. - /// - /// TODO(ank4n): Use NMAP and make sure it can be cleared by 1st key. + /// This is cleared after `HISTORY_DEPTH` eras. #[pallet::storage] #[pallet::unbounded] - pub type ErasStakersPaged = StorageDoubleMap< + pub type ErasStakersPaged = StorageNMap< _, - Twox64Concat, - EraIndex, - Twox64Concat, - (T::AccountId, PageIndex), + ( + NMapKey, + NMapKey, + NMapKey, + ), ExposurePage>, OptionQuery, >; @@ -699,7 +697,7 @@ pub mod pallet { let validator_stake = if page == 0 { overview.own } else { Zero::zero() }; let exposure_page = - >::get(era, (validator, page)).unwrap_or_default(); + >::get((era, validator, page)).unwrap_or_default(); // build the exposure Some(ExposureExt { @@ -727,7 +725,7 @@ pub mod pallet { let mut others = Vec::with_capacity(overview.nominator_count as usize); for page in 0..overview.page_count { - let nominators = >::get(era, (validator, page)); + let nominators = >::get((era, validator, page)); others.append(&mut nominators.map(|n| n.others).defensive_unwrap_or_default()); } @@ -841,7 +839,7 @@ pub mod pallet { >::insert(era, &validator, &exposure_overview); exposure_pages.iter().enumerate().for_each(|(page, paged_exposure)| { - >::insert(era, (&validator, page as u32), &paged_exposure); + >::insert((era, &validator, page as u32), &paged_exposure); }); } diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index 4df8266ee4fae..364c7b1c2420d 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -497,7 +497,7 @@ fn less_than_needed_candidates_works() { // But the exposure is updated in a simple way. No external votes exists. // This is purely self-vote. - assert!(ErasStakersPaged::::iter_prefix_values(active_era()) + assert!(ErasStakersPaged::::iter_prefix_values((active_era(),)) .all(|exposure| exposure.others.is_empty())); }); } @@ -617,7 +617,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); - assert_eq!(ErasStakersPaged::::iter_prefix_values(active_era()).count(), 2); + assert_eq!(ErasStakersPaged::::iter_prefix_values((active_era(),)).count(), 2); assert_eq!( Staking::eras_stakers(active_era(), &11), Exposure { @@ -6234,8 +6234,7 @@ fn should_retain_era_info_only_upto_history_depth() { ClaimedRewards::::insert(era, &validator_stash, vec![0, 1, 2]); for page in 0..3 { ErasStakersPaged::::insert( - era, - (&validator_stash, page), + (era, &validator_stash, page), ExposurePage { page_total: 100, others: vec![] }, ); } @@ -6247,14 +6246,14 @@ fn should_retain_era_info_only_upto_history_depth() { // 1 claimed_rewards entry for each era assert_eq!(ClaimedRewards::::iter_prefix(i as EraIndex).count(), 1); // 3 entries (pages) for each era - assert_eq!(ErasStakersPaged::::iter_prefix(i as EraIndex).count(), 3); + assert_eq!(ErasStakersPaged::::iter_prefix((i as EraIndex,)).count(), 3); // when clear era info Pallet::::clear_era_information(i as EraIndex); // then all era entries are cleared assert_eq!(ClaimedRewards::::iter_prefix(i as EraIndex).count(), 0); - assert_eq!(ErasStakersPaged::::iter_prefix(i as EraIndex).count(), 0); + assert_eq!(ErasStakersPaged::::iter_prefix((i as EraIndex,)).count(), 0); } }); } @@ -6384,8 +6383,8 @@ fn test_validator_exposure_is_backward_compatible_with_non_paged_rewards_payout( mock::start_active_era(2); // verify exposure for era 1 is stored in paged storage, that each exposure is stored in // one and only one page, and no exposure is repeated. - let actual_exposure_page_0 = ErasStakersPaged::::get(1, (11, 0)).unwrap(); - let actual_exposure_page_1 = ErasStakersPaged::::get(1, (11, 1)).unwrap(); + let actual_exposure_page_0 = ErasStakersPaged::::get((1, 11, 0)).unwrap(); + let actual_exposure_page_1 = ErasStakersPaged::::get((1, 11, 1)).unwrap(); expected_individual_exposures.iter().for_each(|exposure| { assert!( actual_exposure_page_0.others.contains(exposure) || @@ -6409,8 +6408,8 @@ fn test_validator_exposure_is_backward_compatible_with_non_paged_rewards_payout( // case 2: exposure exist in ErasStakers and ErasStakersClipped (legacy). // delete paged storage and add exposure to clipped storage - >::remove(1, (11, 0)); - >::remove(1, (11, 1)); + >::remove((1, 11, 0)); + >::remove((1, 11, 1)); >::remove(1, 11); >::insert( From 6ac7961c7c5db8fd9367f894153d8b74164e7357 Mon Sep 17 00:00:00 2001 From: Ankan Date: Wed, 22 Feb 2023 16:42:06 +0100 Subject: [PATCH 159/162] doc update --- frame/staking/src/lib.rs | 19 +++++++++++----- frame/staking/src/migrations.rs | 4 ++-- frame/staking/src/pallet/mod.rs | 39 ++++++++++++++++++--------------- 3 files changed, 36 insertions(+), 26 deletions(-) diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index 373c2c6489658..5db4cec67db47 100644 --- a/frame/staking/src/lib.rs +++ b/frame/staking/src/lib.rs @@ -112,11 +112,17 @@ //! The **reward and slashing** procedure is the core of the Staking pallet, attempting to _embrace //! 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::MaxExposurePageSize`] -//! biggest stakers can claim their reward. This is to limit the i/o cost to mutate storage for each -//! nominator's account. +//! Rewards must be claimed for each era before it gets too old by +//! [`HistoryDepth`](`Config::HistoryDepth`) 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::MaxExposurePageSize`] nominator rewards can be claimed in a single call. When the +//! number of nominators exceeds [`Config::MaxExposurePageSize`], then the nominators are stored in +//! multiple pages of [`Config::MaxExposurePageSize`] each with upto maximum of +//! [`Config::MaxExposurePageCount`] pages. To pay out all nominators, `payout_stakers` must be +//! called once for each available page. In a scenario where number of nominators N exceed M where M +//! = [`Config::MaxExposurePageSize`] * [`Config::MaxExposurePageCount`], only top M nominators by +//! stake balance are paid out. The rest of the nominators are not paid out. Paging exists to limit +//! the i/o cost to mutate storage for each nominator's account. //! //! Slashing can occur at any point in time, once misbehavior is reported. Once slashing is //! determined, a value is deducted from the balance of the validator and all the nominators who @@ -229,7 +235,8 @@ //! [`own`](Exposure::own) or [`others`](Exposure::others) by [`total`](Exposure::total) in //! [`Exposure`]). Note that payouts are made in pages with each page capped at //! [`Config::MaxExposurePageSize`] nominators. The distribution of nominators across -//! pages are unsorted and depends on the election result provided by [`Config::ElectionProvider`]. +//! pages may be unsorted. The total commission is paid out proportionally across pages based on the +//! total stake of the page. //! //! All entities who receive a reward have the option to choose their reward destination through the //! [`Payee`] storage item (see diff --git a/frame/staking/src/migrations.rs b/frame/staking/src/migrations.rs index 39f7766b1a327..7829a6ddde5be 100644 --- a/frame/staking/src/migrations.rs +++ b/frame/staking/src/migrations.rs @@ -148,9 +148,9 @@ pub mod v12 { #[storage_alias] type HistoryDepth = StorageValue, u32, ValueQuery>; - /// Clean up `HistoryDepth` from storage. + /// Clean up `T::HistoryDepth` from storage. /// - /// We will be depending on the configurable value of `HistoryDepth` post + /// We will be depending on the configurable value of `T::HistoryDepth` post /// this release. pub struct MigrateToV12(sp_std::marker::PhantomData); impl OnRuntimeUpgrade for MigrateToV12 { diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index 194411f530d3c..e92f00deb7692 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -139,7 +139,8 @@ pub mod pallet { /// Following information is kept for eras in `[current_era - /// HistoryDepth, current_era]`: `ErasStakers`, `ErasStakersClipped`, /// `ErasValidatorPrefs`, `ErasValidatorReward`, `ErasRewardPoints`, - /// `ErasTotalStake`, `ErasStartSessionIndex`, `ClaimedRewards`. + /// `ErasTotalStake`, `ErasStartSessionIndex`, `ClaimedRewards`, `ErasStakersPaged`, + /// `ErasStakersOverview`. /// /// Must be more than the number of eras delayed by session. /// I.e. active era must always be in history. I.e. `active_era > @@ -403,7 +404,7 @@ pub mod pallet { #[pallet::getter(fn active_era)] pub type ActiveEra = StorageValue<_, ActiveEraInfo>; - /// The session index at which the era start for the last `HISTORY_DEPTH` eras. + /// The session index at which the era start for the last [`Config::HistoryDepth`] eras. /// /// Note: This tracks the starting session (i.e. session index when era start being active) /// for the eras in `[CurrentEra - HISTORY_DEPTH, CurrentEra]`. @@ -415,7 +416,7 @@ pub mod pallet { /// /// This is keyed first by the era index to allow bulk deletion and then the stash account. /// - /// Is it removed after `HISTORY_DEPTH` eras. + /// Is it removed after [`Config::HistoryDepth`] eras. /// If stakers hasn't been set or has been removed then empty exposure is returned. /// /// Note: Deprecated since v14. Use `EraInfo` instead to work with exposures. @@ -440,7 +441,7 @@ pub mod pallet { /// /// This is keyed first by the era index to allow bulk deletion and then the stash account. /// - /// Is it removed after `HISTORY_DEPTH` eras. + /// Is it removed after [`Config::HistoryDepth`] eras. /// If stakers hasn't been set or has been removed then empty overview is returned. #[pallet::storage] pub type ErasStakersOverview = StorageDoubleMap< @@ -465,7 +466,7 @@ pub mod pallet { /// /// This is keyed fist by the era index to allow bulk deletion and then the stash account. /// - /// It is removed after `HISTORY_DEPTH` eras. + /// It is removed after [`Config::HistoryDepth`] eras. /// If stakers hasn't been set or has been removed then empty exposure is returned. /// /// Note: Deprecated since v14. Use `EraInfo` instead to work with exposures. @@ -487,7 +488,7 @@ pub mod pallet { /// This is keyed first by the era index to allow bulk deletion, then stash account and finally /// the page. /// - /// This is cleared after `HISTORY_DEPTH` eras. + /// This is cleared after [`Config::HistoryDepth`] eras. #[pallet::storage] #[pallet::unbounded] pub type ErasStakersPaged = StorageNMap< @@ -506,7 +507,7 @@ pub mod pallet { /// This is keyed by era and validator stash which maps to the set of page indexes which have /// been claimed. /// - /// It is removed after `HISTORY_DEPTH` eras. + /// It is removed after [`Config::HistoryDepth`] eras. #[pallet::storage] #[pallet::getter(fn claimed_rewards)] #[pallet::unbounded] @@ -524,7 +525,7 @@ pub mod pallet { /// /// This is keyed first by the era index to allow bulk deletion and then the stash account. /// - /// Is it removed after `HISTORY_DEPTH` eras. + /// Is it removed after [`Config::HistoryDepth`] eras. // If prefs hasn't been set or has been removed then 0 commission is returned. #[pallet::storage] #[pallet::getter(fn eras_validator_prefs)] @@ -538,14 +539,14 @@ pub mod pallet { ValueQuery, >; - /// The total validator era payout for the last `HISTORY_DEPTH` eras. + /// The total validator era payout for the last [`Config::HistoryDepth`] eras. /// /// Eras that haven't finished yet or has been removed doesn't have reward. #[pallet::storage] #[pallet::getter(fn eras_validator_reward)] pub type ErasValidatorReward = StorageMap<_, Twox64Concat, EraIndex, BalanceOf>; - /// Rewards for the last `HISTORY_DEPTH` eras. + /// Rewards for the last [`Config::HistoryDepth`] eras. /// If reward hasn't been set or has been removed then 0 reward is returned. #[pallet::storage] #[pallet::unbounded] @@ -553,7 +554,7 @@ pub mod pallet { pub type ErasRewardPoints = StorageMap<_, Twox64Concat, EraIndex, EraRewardPoints, ValueQuery>; - /// The total amount staked for the last `HISTORY_DEPTH` eras. + /// The total amount staked for the last [`Config::HistoryDepth`] eras. /// If total hasn't been set or has been removed then 0 stake is returned. #[pallet::storage] #[pallet::getter(fn eras_total_stake)] @@ -647,7 +648,7 @@ pub mod pallet { impl EraInfo { /// Temporary function which looks at both (1) passed param `T::StakingLedger` for legacy /// non-paged rewards, and (2) `T::ClaimedRewards` for paged rewards. This function can be - /// removed once `$HistoryDepth` eras have passed and none of the older non-paged rewards + /// removed once `T::HistoryDepth` eras have passed and none of the older non-paged rewards /// are relevant/claimable. // Refer tracker issue for cleanup: #13034 pub(crate) fn is_rewards_claimed_with_legacy_fallback( @@ -1759,13 +1760,14 @@ pub mod pallet { /// This pays out the earliest exposure page not claimed for the era. If all pages are /// claimed, it returns an error `InvalidPage`. /// - /// If a validator has more than `T::MaxExposurePageSize` nominators backing + /// If a validator has more than [`Config::MaxExposurePageSize`] nominators backing /// them, then the list of nominators is paged, with each page being capped at - /// `T::MaxExposurePageSize`. If a validator has more than one page of + /// [`Config::MaxExposurePageSize`]. If a validator has more than one page of /// nominators, the call needs to be made for each page separately in order for all the /// nominators backing a validator receive the reward. The nominators are not sorted across /// pages and so it should not be assumed the highest staker would be on the topmost page - /// and vice versa. If rewards are not claimed in `${HistoryDepth}` eras, they are lost. + /// and vice versa. If rewards are not claimed in [`Config::HistoryDepth`] eras, they are + /// lost. /// /// # /// - Time complexity: at most O(MaxExposurePageSize). @@ -2090,13 +2092,14 @@ pub mod pallet { /// The origin of this call must be _Signed_. Any account can call this function, even if /// it is not one of the stakers. /// - /// If a validator has more than `T::MaxExposurePageSize` nominators backing + /// If a validator has more than [`Config::MaxExposurePageSize`] nominators backing /// them, then the list of nominators is paged, with each page being capped at - /// `T::MaxExposurePageSize`. If a validator has more than one page of + /// [`Config::MaxExposurePageSize`.] If a validator has more than one page of /// nominators, the call needs to be made for each page separately in order for all the /// nominators backing a validator receive the reward. The nominators are not sorted across /// pages and so it should not be assumed the highest staker would be on the topmost page - /// and vice versa. If rewards are not claimed in `${HistoryDepth}` eras, they are lost. + /// and vice versa. If rewards are not claimed in [`Config::HistoryDepth`] eras, they are + /// lost. /// /// # /// - Time complexity: at most O(MaxExposurePageSize). From b5190b5a675a0dc5ffc780e50a8cd710fa691bc1 Mon Sep 17 00:00:00 2001 From: command-bot <> Date: Wed, 22 Feb 2023 18:56:57 +0000 Subject: [PATCH 160/162] ".git/.scripts/commands/bench/bench.sh" pallet dev pallet_staking --- frame/staking/src/weights.rs | 2000 ++++++++++++++++++++++------------ 1 file changed, 1315 insertions(+), 685 deletions(-) diff --git a/frame/staking/src/weights.rs b/frame/staking/src/weights.rs index fd2f0b7d1ca7c..7752ce019c240 100644 --- a/frame/staking/src/weights.rs +++ b/frame/staking/src/weights.rs @@ -18,12 +18,13 @@ //! Autogenerated weights for pallet_staking //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-01-23, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! DATE: 2023-02-22, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner-ehxwxxsd-project-145-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// /home/benchbot/cargo_target_dir/production/substrate +// target/production/substrate // benchmark // pallet // --steps=50 @@ -32,7 +33,7 @@ // --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --json-file=/var/lib/gitlab-runner/builds/zyw4fam_/0/parity/mirrors/substrate/.git/.artifacts/bench.json +// --json-file=/builds/parity/mirrors/substrate/.git/.artifacts/bench.json // --pallet=pallet_staking // --chain=dev // --header=./HEADER-APACHE2 @@ -83,851 +84,1480 @@ pub trait WeightInfo { /// Weights for pallet_staking using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - // Storage: Staking Bonded (r:1 w:1) - // Storage: Staking Ledger (r:1 w:1) - // Storage: Balances Locks (r:1 w:1) - // Storage: Staking Payee (r:0 w:1) + /// Storage: Staking Bonded (r:1 w:1) + /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) + /// Storage: Staking Ledger (r:1 w:1) + /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Staking Payee (r:0 w:1) + /// Proof: Staking Payee (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) fn bond() -> Weight { - // Minimum execution time: 51_815 nanoseconds. - Weight::from_ref_time(52_367_000) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(4)) - } - // Storage: Staking Bonded (r:1 w:0) - // Storage: Staking Ledger (r:1 w:1) - // Storage: Balances Locks (r:1 w:1) - // Storage: VoterList ListNodes (r:3 w:3) - // Storage: VoterList ListBags (r:2 w:2) + // Proof Size summary in bytes: + // Measured: `1074` + // Estimated: `9887` + // Minimum execution time: 42_791 nanoseconds. + Weight::from_ref_time(43_964_000) + .saturating_add(Weight::from_proof_size(9887)) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(4_u64)) + } + /// Storage: Staking Bonded (r:1 w:0) + /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) + /// Storage: Staking Ledger (r:1 w:1) + /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: VoterList ListNodes (r:3 w:3) + /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) + /// Storage: VoterList ListBags (r:2 w:2) + /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) fn bond_extra() -> Weight { - // Minimum execution time: 91_792 nanoseconds. - Weight::from_ref_time(92_729_000) - .saturating_add(T::DbWeight::get().reads(8)) - .saturating_add(T::DbWeight::get().writes(7)) - } - // Storage: Staking Ledger (r:1 w:1) - // Storage: Staking Nominators (r:1 w:0) - // Storage: Staking MinNominatorBond (r:1 w:0) - // Storage: Staking CurrentEra (r:1 w:0) - // Storage: Balances Locks (r:1 w:1) - // Storage: System Account (r:1 w:1) - // Storage: VoterList ListNodes (r:3 w:3) - // Storage: Staking Bonded (r:1 w:0) - // Storage: VoterList ListBags (r:2 w:2) + // Proof Size summary in bytes: + // Measured: `2214` + // Estimated: `22888` + // Minimum execution time: 87_712 nanoseconds. + Weight::from_ref_time(90_269_000) + .saturating_add(Weight::from_proof_size(22888)) + .saturating_add(T::DbWeight::get().reads(8_u64)) + .saturating_add(T::DbWeight::get().writes(7_u64)) + } + /// Storage: Staking Ledger (r:1 w:1) + /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) + /// Storage: Staking Nominators (r:1 w:0) + /// Proof: Staking Nominators (max_values: None, max_size: Some(558), added: 3033, mode: MaxEncodedLen) + /// Storage: Staking MinNominatorBond (r:1 w:0) + /// Proof: Staking MinNominatorBond (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) + /// Storage: Staking CurrentEra (r:1 w:0) + /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: VoterList ListNodes (r:3 w:3) + /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) + /// Storage: Staking Bonded (r:1 w:0) + /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) + /// Storage: VoterList ListBags (r:2 w:2) + /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) fn unbond() -> Weight { - // Minimum execution time: 97_647 nanoseconds. - Weight::from_ref_time(98_731_000) - .saturating_add(T::DbWeight::get().reads(12)) - .saturating_add(T::DbWeight::get().writes(8)) - } - // Storage: Staking Ledger (r:1 w:1) - // Storage: Staking CurrentEra (r:1 w:0) - // Storage: Balances Locks (r:1 w:1) - // Storage: System Account (r:1 w:1) + // Proof Size summary in bytes: + // Measured: `2419` + // Estimated: `29534` + // Minimum execution time: 95_748 nanoseconds. + Weight::from_ref_time(98_423_000) + .saturating_add(Weight::from_proof_size(29534)) + .saturating_add(T::DbWeight::get().reads(12_u64)) + .saturating_add(T::DbWeight::get().writes(8_u64)) + } + /// Storage: Staking Ledger (r:1 w:1) + /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) + /// Storage: Staking CurrentEra (r:1 w:0) + /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// The range of component `s` is `[0, 100]`. fn withdraw_unbonded_update(s: u32, ) -> Weight { - // Minimum execution time: 44_744 nanoseconds. - Weight::from_ref_time(45_658_968) - // Standard Error: 692 - .saturating_add(Weight::from_ref_time(65_958).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(3)) - } - // Storage: Staking Ledger (r:1 w:1) - // Storage: Staking CurrentEra (r:1 w:0) - // Storage: Staking Bonded (r:1 w:1) - // Storage: Staking SlashingSpans (r:1 w:0) - // Storage: Staking Validators (r:1 w:0) - // Storage: Staking Nominators (r:1 w:1) - // Storage: Staking CounterForNominators (r:1 w:1) - // Storage: VoterList ListNodes (r:2 w:2) - // Storage: VoterList ListBags (r:1 w:1) - // Storage: VoterList CounterForListNodes (r:1 w:1) - // Storage: System Account (r:1 w:1) - // Storage: Balances Locks (r:1 w:1) - // Storage: Staking Payee (r:0 w:1) - // Storage: Staking SpanSlash (r:0 w:2) + // Proof Size summary in bytes: + // Measured: `1080` + // Estimated: `10442` + // Minimum execution time: 34_556 nanoseconds. + Weight::from_ref_time(36_352_208) + .saturating_add(Weight::from_proof_size(10442)) + // Standard Error: 975 + .saturating_add(Weight::from_ref_time(42_685).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: Staking Ledger (r:1 w:1) + /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) + /// Storage: Staking CurrentEra (r:1 w:0) + /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking Bonded (r:1 w:1) + /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) + /// Storage: Staking SlashingSpans (r:1 w:1) + /// Proof Skipped: Staking SlashingSpans (max_values: None, max_size: None, mode: Measured) + /// Storage: Staking Validators (r:1 w:0) + /// Proof: Staking Validators (max_values: None, max_size: Some(45), added: 2520, mode: MaxEncodedLen) + /// Storage: Staking Nominators (r:1 w:1) + /// Proof: Staking Nominators (max_values: None, max_size: Some(558), added: 3033, mode: MaxEncodedLen) + /// Storage: Staking CounterForNominators (r:1 w:1) + /// Proof: Staking CounterForNominators (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: VoterList ListNodes (r:2 w:2) + /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) + /// Storage: VoterList ListBags (r:1 w:1) + /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) + /// Storage: VoterList CounterForListNodes (r:1 w:1) + /// Proof: VoterList CounterForListNodes (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Staking Payee (r:0 w:1) + /// Proof: Staking Payee (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) + /// Storage: Staking SpanSlash (r:0 w:100) + /// Proof: Staking SpanSlash (max_values: None, max_size: Some(76), added: 2551, mode: MaxEncodedLen) /// The range of component `s` is `[0, 100]`. fn withdraw_unbonded_kill(s: u32, ) -> Weight { - // Minimum execution time: 86_013 nanoseconds. - Weight::from_ref_time(91_544_236) - // Standard Error: 2_273 - .saturating_add(Weight::from_ref_time(1_073_291).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(13)) - .saturating_add(T::DbWeight::get().writes(12)) + // Proof Size summary in bytes: + // Measured: `2388 + s * (4 ±0)` + // Estimated: `32205 + s * (4 ±0)` + // Minimum execution time: 82_858 nanoseconds. + Weight::from_ref_time(90_123_003) + .saturating_add(Weight::from_proof_size(32205)) + // Standard Error: 3_084 + .saturating_add(Weight::from_ref_time(1_363_655).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(13_u64)) + .saturating_add(T::DbWeight::get().writes(12_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) + .saturating_add(Weight::from_proof_size(4).saturating_mul(s.into())) } - // Storage: Staking Ledger (r:1 w:0) - // Storage: Staking MinValidatorBond (r:1 w:0) - // Storage: Staking MinCommission (r:1 w:0) - // Storage: Staking Validators (r:1 w:1) - // Storage: Staking MaxValidatorsCount (r:1 w:0) - // Storage: Staking Nominators (r:1 w:0) - // Storage: Staking Bonded (r:1 w:0) - // Storage: VoterList ListNodes (r:1 w:1) - // Storage: VoterList ListBags (r:1 w:1) - // Storage: VoterList CounterForListNodes (r:1 w:1) - // Storage: Staking CounterForValidators (r:1 w:1) + /// Storage: Staking Ledger (r:1 w:0) + /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) + /// Storage: Staking MinValidatorBond (r:1 w:0) + /// Proof: Staking MinValidatorBond (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) + /// Storage: Staking MinCommission (r:1 w:0) + /// Proof: Staking MinCommission (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking Validators (r:1 w:1) + /// Proof: Staking Validators (max_values: None, max_size: Some(45), added: 2520, mode: MaxEncodedLen) + /// Storage: Staking MaxValidatorsCount (r:1 w:0) + /// Proof: Staking MaxValidatorsCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking Nominators (r:1 w:0) + /// Proof: Staking Nominators (max_values: None, max_size: Some(558), added: 3033, mode: MaxEncodedLen) + /// Storage: Staking Bonded (r:1 w:0) + /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) + /// Storage: VoterList ListNodes (r:1 w:1) + /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) + /// Storage: VoterList ListBags (r:1 w:1) + /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) + /// Storage: VoterList CounterForListNodes (r:1 w:1) + /// Proof: VoterList CounterForListNodes (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking CounterForValidators (r:1 w:1) + /// Proof: Staking CounterForValidators (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) fn validate() -> Weight { - // Minimum execution time: 66_579 nanoseconds. - Weight::from_ref_time(67_026_000) - .saturating_add(T::DbWeight::get().reads(11)) - .saturating_add(T::DbWeight::get().writes(5)) + // Proof Size summary in bytes: + // Measured: `1404` + // Estimated: `19359` + // Minimum execution time: 57_223 nanoseconds. + Weight::from_ref_time(59_188_000) + .saturating_add(Weight::from_proof_size(19359)) + .saturating_add(T::DbWeight::get().reads(11_u64)) + .saturating_add(T::DbWeight::get().writes(5_u64)) } - // Storage: Staking Ledger (r:1 w:0) - // Storage: Staking Nominators (r:1 w:1) + /// Storage: Staking Ledger (r:1 w:0) + /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) + /// Storage: Staking Nominators (r:128 w:128) + /// Proof: Staking Nominators (max_values: None, max_size: Some(558), added: 3033, mode: MaxEncodedLen) /// The range of component `k` is `[1, 128]`. fn kick(k: u32, ) -> Weight { - // Minimum execution time: 40_716 nanoseconds. - Weight::from_ref_time(43_678_932) - // Standard Error: 15_099 - .saturating_add(Weight::from_ref_time(6_814_991).saturating_mul(k.into())) - .saturating_add(T::DbWeight::get().reads(1)) + // Proof Size summary in bytes: + // Measured: `1287 + k * (601 ±0)` + // Estimated: `3566 + k * (3033 ±0)` + // Minimum execution time: 30_970 nanoseconds. + Weight::from_ref_time(32_205_531) + .saturating_add(Weight::from_proof_size(3566)) + // Standard Error: 12_307 + .saturating_add(Weight::from_ref_time(8_599_234).saturating_mul(k.into())) + .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(k.into()))) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(k.into()))) + .saturating_add(Weight::from_proof_size(3033).saturating_mul(k.into())) } - // Storage: Staking Ledger (r:1 w:0) - // Storage: Staking MinNominatorBond (r:1 w:0) - // Storage: Staking Nominators (r:1 w:1) - // Storage: Staking MaxNominatorsCount (r:1 w:0) - // Storage: Staking Validators (r:2 w:0) - // Storage: Staking CurrentEra (r:1 w:0) - // Storage: Staking Bonded (r:1 w:0) - // Storage: VoterList ListNodes (r:2 w:2) - // Storage: VoterList ListBags (r:1 w:1) - // Storage: VoterList CounterForListNodes (r:1 w:1) - // Storage: Staking CounterForNominators (r:1 w:1) + /// Storage: Staking Ledger (r:1 w:0) + /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) + /// Storage: Staking MinNominatorBond (r:1 w:0) + /// Proof: Staking MinNominatorBond (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) + /// Storage: Staking Nominators (r:1 w:1) + /// Proof: Staking Nominators (max_values: None, max_size: Some(558), added: 3033, mode: MaxEncodedLen) + /// Storage: Staking MaxNominatorsCount (r:1 w:0) + /// Proof: Staking MaxNominatorsCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking Validators (r:17 w:0) + /// Proof: Staking Validators (max_values: None, max_size: Some(45), added: 2520, mode: MaxEncodedLen) + /// Storage: Staking CurrentEra (r:1 w:0) + /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking Bonded (r:1 w:0) + /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) + /// Storage: VoterList ListNodes (r:2 w:2) + /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) + /// Storage: VoterList ListBags (r:1 w:1) + /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) + /// Storage: VoterList CounterForListNodes (r:1 w:1) + /// Proof: VoterList CounterForListNodes (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking CounterForNominators (r:1 w:1) + /// Proof: Staking CounterForNominators (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) /// The range of component `n` is `[1, 16]`. fn nominate(n: u32, ) -> Weight { - // Minimum execution time: 71_258 nanoseconds. - Weight::from_ref_time(70_901_125) - // Standard Error: 6_183 - .saturating_add(Weight::from_ref_time(2_777_341).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(12)) + // Proof Size summary in bytes: + // Measured: `1942 + n * (105 ±0)` + // Estimated: `21988 + n * (2520 ±0)` + // Minimum execution time: 69_223 nanoseconds. + Weight::from_ref_time(68_719_145) + .saturating_add(Weight::from_proof_size(21988)) + // Standard Error: 19_229 + .saturating_add(Weight::from_ref_time(4_075_338).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(12_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) - .saturating_add(T::DbWeight::get().writes(6)) - } - // Storage: Staking Ledger (r:1 w:0) - // Storage: Staking Validators (r:1 w:0) - // Storage: Staking Nominators (r:1 w:1) - // Storage: Staking CounterForNominators (r:1 w:1) - // Storage: VoterList ListNodes (r:2 w:2) - // Storage: VoterList ListBags (r:1 w:1) - // Storage: VoterList CounterForListNodes (r:1 w:1) + .saturating_add(T::DbWeight::get().writes(6_u64)) + .saturating_add(Weight::from_proof_size(2520).saturating_mul(n.into())) + } + /// Storage: Staking Ledger (r:1 w:0) + /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) + /// Storage: Staking Validators (r:1 w:0) + /// Proof: Staking Validators (max_values: None, max_size: Some(45), added: 2520, mode: MaxEncodedLen) + /// Storage: Staking Nominators (r:1 w:1) + /// Proof: Staking Nominators (max_values: None, max_size: Some(558), added: 3033, mode: MaxEncodedLen) + /// Storage: Staking CounterForNominators (r:1 w:1) + /// Proof: Staking CounterForNominators (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: VoterList ListNodes (r:2 w:2) + /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) + /// Storage: VoterList ListBags (r:1 w:1) + /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) + /// Storage: VoterList CounterForListNodes (r:1 w:1) + /// Proof: VoterList CounterForListNodes (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) fn chill() -> Weight { - // Minimum execution time: 66_052 nanoseconds. - Weight::from_ref_time(66_480_000) - .saturating_add(T::DbWeight::get().reads(8)) - .saturating_add(T::DbWeight::get().writes(6)) + // Proof Size summary in bytes: + // Measured: `1778` + // Estimated: `17932` + // Minimum execution time: 58_126 nanoseconds. + Weight::from_ref_time(59_792_000) + .saturating_add(Weight::from_proof_size(17932)) + .saturating_add(T::DbWeight::get().reads(8_u64)) + .saturating_add(T::DbWeight::get().writes(6_u64)) } - // Storage: Staking Ledger (r:1 w:0) - // Storage: Staking Payee (r:0 w:1) + /// Storage: Staking Ledger (r:1 w:0) + /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) + /// Storage: Staking Payee (r:0 w:1) + /// Proof: Staking Payee (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) fn set_payee() -> Weight { - // Minimum execution time: 18_008 nanoseconds. - Weight::from_ref_time(18_360_000) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) + // Proof Size summary in bytes: + // Measured: `835` + // Estimated: `3566` + // Minimum execution time: 13_555 nanoseconds. + Weight::from_ref_time(14_016_000) + .saturating_add(Weight::from_proof_size(3566)) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) } - // Storage: Staking Bonded (r:1 w:1) - // Storage: Staking Ledger (r:2 w:2) + /// Storage: Staking Bonded (r:1 w:1) + /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) + /// Storage: Staking Ledger (r:2 w:2) + /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) fn set_controller() -> Weight { - // Minimum execution time: 25_979 nanoseconds. - Weight::from_ref_time(26_350_000) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(3)) + // Proof Size summary in bytes: + // Measured: `934` + // Estimated: `9679` + // Minimum execution time: 21_301 nanoseconds. + Weight::from_ref_time(22_586_000) + .saturating_add(Weight::from_proof_size(9679)) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) } - // Storage: Staking ValidatorCount (r:0 w:1) + /// Storage: Staking ValidatorCount (r:0 w:1) + /// Proof: Staking ValidatorCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) fn set_validator_count() -> Weight { - // Minimum execution time: 5_009 nanoseconds. - Weight::from_ref_time(5_248_000) - .saturating_add(T::DbWeight::get().writes(1)) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 2_830 nanoseconds. + Weight::from_ref_time(2_957_000) + .saturating_add(Weight::from_proof_size(0)) + .saturating_add(T::DbWeight::get().writes(1_u64)) } - // Storage: Staking ForceEra (r:0 w:1) + /// Storage: Staking ForceEra (r:0 w:1) + /// Proof: Staking ForceEra (max_values: Some(1), max_size: Some(1), added: 496, mode: MaxEncodedLen) fn force_no_eras() -> Weight { - // Minimum execution time: 19_493 nanoseconds. - Weight::from_ref_time(19_888_000) - .saturating_add(T::DbWeight::get().writes(1)) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 10_600 nanoseconds. + Weight::from_ref_time(11_114_000) + .saturating_add(Weight::from_proof_size(0)) + .saturating_add(T::DbWeight::get().writes(1_u64)) } - // Storage: Staking ForceEra (r:0 w:1) + /// Storage: Staking ForceEra (r:0 w:1) + /// Proof: Staking ForceEra (max_values: Some(1), max_size: Some(1), added: 496, mode: MaxEncodedLen) fn force_new_era() -> Weight { - // Minimum execution time: 19_425 nanoseconds. - Weight::from_ref_time(19_991_000) - .saturating_add(T::DbWeight::get().writes(1)) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 10_432 nanoseconds. + Weight::from_ref_time(10_984_000) + .saturating_add(Weight::from_proof_size(0)) + .saturating_add(T::DbWeight::get().writes(1_u64)) } - // Storage: Staking ForceEra (r:0 w:1) + /// Storage: Staking ForceEra (r:0 w:1) + /// Proof: Staking ForceEra (max_values: Some(1), max_size: Some(1), added: 496, mode: MaxEncodedLen) fn force_new_era_always() -> Weight { - // Minimum execution time: 19_690 nanoseconds. - Weight::from_ref_time(20_010_000) - .saturating_add(T::DbWeight::get().writes(1)) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 10_565 nanoseconds. + Weight::from_ref_time(11_139_000) + .saturating_add(Weight::from_proof_size(0)) + .saturating_add(T::DbWeight::get().writes(1_u64)) } - // Storage: Staking Invulnerables (r:0 w:1) + /// Storage: Staking Invulnerables (r:0 w:1) + /// Proof Skipped: Staking Invulnerables (max_values: Some(1), max_size: None, mode: Measured) /// The range of component `v` is `[0, 1000]`. fn set_invulnerables(v: u32, ) -> Weight { - // Minimum execution time: 5_375 nanoseconds. - Weight::from_ref_time(6_217_068) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 2_988 nanoseconds. + Weight::from_ref_time(3_521_842) + .saturating_add(Weight::from_proof_size(0)) // Standard Error: 43 - .saturating_add(Weight::from_ref_time(9_885).saturating_mul(v.into())) - .saturating_add(T::DbWeight::get().writes(1)) - } - // Storage: Staking Bonded (r:1 w:1) - // Storage: Staking SlashingSpans (r:1 w:0) - // Storage: Staking Validators (r:1 w:0) - // Storage: Staking Nominators (r:1 w:1) - // Storage: Staking CounterForNominators (r:1 w:1) - // Storage: VoterList ListNodes (r:2 w:2) - // Storage: VoterList ListBags (r:1 w:1) - // Storage: VoterList CounterForListNodes (r:1 w:1) - // Storage: System Account (r:1 w:1) - // Storage: Balances Locks (r:1 w:1) - // Storage: Staking Ledger (r:0 w:1) - // Storage: Staking Payee (r:0 w:1) - // Storage: Staking SpanSlash (r:0 w:2) + .saturating_add(Weight::from_ref_time(9_580).saturating_mul(v.into())) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: Staking Bonded (r:1 w:1) + /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) + /// Storage: Staking SlashingSpans (r:1 w:1) + /// Proof Skipped: Staking SlashingSpans (max_values: None, max_size: None, mode: Measured) + /// Storage: Staking Validators (r:1 w:0) + /// Proof: Staking Validators (max_values: None, max_size: Some(45), added: 2520, mode: MaxEncodedLen) + /// Storage: Staking Nominators (r:1 w:1) + /// Proof: Staking Nominators (max_values: None, max_size: Some(558), added: 3033, mode: MaxEncodedLen) + /// Storage: Staking CounterForNominators (r:1 w:1) + /// Proof: Staking CounterForNominators (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: VoterList ListNodes (r:2 w:2) + /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) + /// Storage: VoterList ListBags (r:1 w:1) + /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) + /// Storage: VoterList CounterForListNodes (r:1 w:1) + /// Proof: VoterList CounterForListNodes (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Staking Ledger (r:0 w:1) + /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) + /// Storage: Staking Payee (r:0 w:1) + /// Proof: Staking Payee (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) + /// Storage: Staking SpanSlash (r:0 w:100) + /// Proof: Staking SpanSlash (max_values: None, max_size: Some(76), added: 2551, mode: MaxEncodedLen) /// The range of component `s` is `[0, 100]`. fn force_unstake(s: u32, ) -> Weight { - // Minimum execution time: 79_630 nanoseconds. - Weight::from_ref_time(85_354_738) - // Standard Error: 2_555 - .saturating_add(Weight::from_ref_time(1_086_827).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(11)) - .saturating_add(T::DbWeight::get().writes(12)) + // Proof Size summary in bytes: + // Measured: `2118 + s * (4 ±0)` + // Estimated: `27870 + s * (4 ±0)` + // Minimum execution time: 75_086 nanoseconds. + Weight::from_ref_time(82_863_879) + .saturating_add(Weight::from_proof_size(27870)) + // Standard Error: 3_873 + .saturating_add(Weight::from_ref_time(1_339_680).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(11_u64)) + .saturating_add(T::DbWeight::get().writes(12_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) + .saturating_add(Weight::from_proof_size(4).saturating_mul(s.into())) } - // Storage: Staking UnappliedSlashes (r:1 w:1) + /// Storage: Staking UnappliedSlashes (r:1 w:1) + /// Proof Skipped: Staking UnappliedSlashes (max_values: None, max_size: None, mode: Measured) /// The range of component `s` is `[1, 1000]`. fn cancel_deferred_slash(s: u32, ) -> Weight { - // Minimum execution time: 92_209 nanoseconds. - Weight::from_ref_time(901_022_610) - // Standard Error: 59_320 - .saturating_add(Weight::from_ref_time(4_943_518).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - // Storage: Staking CurrentEra (r:1 w:0) - // Storage: Staking ErasStakersOverview (r:1 w:0) - // Storage: Staking ErasValidatorReward (r:1 w:0) - // Storage: Staking Bonded (r:1 w:0) - // Storage: Staking Ledger (r:1 w:1) - // Storage: Staking ClaimedRewards (r:1 w:1) - // Storage: Staking ErasStakersPaged (r:1 w:0) - // Storage: Staking ErasStakersClipped (r:1 w:0) - // Storage: Staking ErasRewardPoints (r:1 w:0) - // Storage: Staking ErasValidatorPrefs (r:1 w:0) - // Storage: Staking Payee (r:1 w:0) - // Storage: System Account (r:1 w:1) + // Proof Size summary in bytes: + // Measured: `66704` + // Estimated: `69179` + // Minimum execution time: 99_616 nanoseconds. + Weight::from_ref_time(910_033_266) + .saturating_add(Weight::from_proof_size(69179)) + // Standard Error: 58_519 + .saturating_add(Weight::from_ref_time(4_878_008).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: Staking CurrentEra (r:1 w:0) + /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking ErasStakersOverview (r:1 w:0) + /// Proof: Staking ErasStakersOverview (max_values: None, max_size: Some(92), added: 2567, mode: MaxEncodedLen) + /// Storage: Staking ErasValidatorReward (r:1 w:0) + /// Proof: Staking ErasValidatorReward (max_values: None, max_size: Some(28), added: 2503, mode: MaxEncodedLen) + /// Storage: Staking Bonded (r:257 w:0) + /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) + /// Storage: Staking Ledger (r:1 w:1) + /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) + /// Storage: Staking ClaimedRewards (r:1 w:1) + /// Proof Skipped: Staking ClaimedRewards (max_values: None, max_size: None, mode: Measured) + /// Storage: Staking ErasStakersPaged (r:1 w:0) + /// Proof Skipped: Staking ErasStakersPaged (max_values: None, max_size: None, mode: Measured) + /// Storage: Staking ErasRewardPoints (r:1 w:0) + /// Proof Skipped: Staking ErasRewardPoints (max_values: None, max_size: None, mode: Measured) + /// Storage: Staking ErasValidatorPrefs (r:1 w:0) + /// Proof: Staking ErasValidatorPrefs (max_values: None, max_size: Some(57), added: 2532, mode: MaxEncodedLen) + /// Storage: Staking Payee (r:257 w:0) + /// Proof: Staking Payee (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) + /// Storage: System Account (r:257 w:257) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// The range of component `n` is `[0, 256]`. fn payout_stakers_dead_controller(n: u32, ) -> Weight { - // Minimum execution time: 134_323 nanoseconds. - Weight::from_ref_time(200_066_020) - // Standard Error: 16_654 - .saturating_add(Weight::from_ref_time(21_841_097).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(11)) + // Proof Size summary in bytes: + // Measured: `20450 + n * (143 ±0)` + // Estimated: `76596 + n * (8187 ±1)` + // Minimum execution time: 120_810 nanoseconds. + Weight::from_ref_time(153_474_546) + .saturating_add(Weight::from_proof_size(76596)) + // Standard Error: 18_966 + .saturating_add(Weight::from_ref_time(28_752_414).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(11_u64)) .saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(n.into()))) - .saturating_add(T::DbWeight::get().writes(3)) + .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(n.into()))) + .saturating_add(Weight::from_proof_size(8187).saturating_mul(n.into())) } - // Storage: Staking CurrentEra (r:1 w:0) - // Storage: Staking ErasStakersOverview (r:1 w:0) - // Storage: Staking ErasValidatorReward (r:1 w:0) - // Storage: Staking Bonded (r:1 w:0) - // Storage: Staking Ledger (r:1 w:1) - // Storage: Staking ClaimedRewards (r:1 w:1) - // Storage: Staking ErasStakersPaged (r:1 w:0) - // Storage: Staking ErasStakersClipped (r:1 w:0) - // Storage: Staking ErasRewardPoints (r:1 w:0) - // Storage: Staking ErasValidatorPrefs (r:1 w:0) - // Storage: Staking Payee (r:1 w:0) - // Storage: System Account (r:1 w:1) - // Storage: Balances Locks (r:1 w:1) + /// Storage: Staking Bonded (r:257 w:0) + /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) + /// Storage: Staking Ledger (r:257 w:257) + /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) + /// Storage: Staking ErasStakersClipped (r:1 w:0) + /// Proof Skipped: Staking ErasStakersClipped (max_values: None, max_size: None, mode: Measured) + /// Storage: Staking ErasStakersOverview (r:1 w:0) + /// Proof: Staking ErasStakersOverview (max_values: None, max_size: Some(92), added: 2567, mode: MaxEncodedLen) + /// Storage: Staking ClaimedRewards (r:1 w:1) + /// Proof Skipped: Staking ClaimedRewards (max_values: None, max_size: None, mode: Measured) + /// Storage: Staking CurrentEra (r:1 w:0) + /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking ErasValidatorReward (r:1 w:0) + /// Proof: Staking ErasValidatorReward (max_values: None, max_size: Some(28), added: 2503, mode: MaxEncodedLen) + /// Storage: Staking ErasStakersPaged (r:1 w:0) + /// Proof Skipped: Staking ErasStakersPaged (max_values: None, max_size: None, mode: Measured) + /// Storage: Staking ErasRewardPoints (r:1 w:0) + /// Proof Skipped: Staking ErasRewardPoints (max_values: None, max_size: None, mode: Measured) + /// Storage: Staking ErasValidatorPrefs (r:1 w:0) + /// Proof: Staking ErasValidatorPrefs (max_values: None, max_size: Some(57), added: 2532, mode: MaxEncodedLen) + /// Storage: Staking Payee (r:257 w:0) + /// Proof: Staking Payee (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) + /// Storage: System Account (r:257 w:257) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:257 w:257) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) /// The range of component `n` is `[0, 256]`. fn payout_stakers_alive_staked(n: u32, ) -> Weight { - // Minimum execution time: 166_885 nanoseconds. - Weight::from_ref_time(231_648_127) - // Standard Error: 30_392 - .saturating_add(Weight::from_ref_time(30_760_443).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(12)) + // Proof Size summary in bytes: + // Measured: `35204 + n * (465 ±0)` + // Estimated: `149575 + n * (17014 ±3)` + // Minimum execution time: 150_324 nanoseconds. + Weight::from_ref_time(148_039_697) + .saturating_add(Weight::from_proof_size(149575)) + // Standard Error: 39_048 + .saturating_add(Weight::from_ref_time(43_172_238).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(13_u64)) .saturating_add(T::DbWeight::get().reads((5_u64).saturating_mul(n.into()))) - .saturating_add(T::DbWeight::get().writes(4)) + .saturating_add(T::DbWeight::get().writes(4_u64)) .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(n.into()))) + .saturating_add(Weight::from_proof_size(17014).saturating_mul(n.into())) } - - // Storage: Staking Ledger (r:1 w:1) - // Storage: Balances Locks (r:1 w:1) - // Storage: System Account (r:1 w:1) - // Storage: VoterList ListNodes (r:3 w:3) - // Storage: Staking Bonded (r:1 w:0) - // Storage: VoterList ListBags (r:2 w:2) + /// Storage: Staking Ledger (r:1 w:1) + /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: VoterList ListNodes (r:3 w:3) + /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) + /// Storage: Staking Bonded (r:1 w:0) + /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) + /// Storage: VoterList ListBags (r:2 w:2) + /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) /// The range of component `l` is `[1, 32]`. fn rebond(l: u32, ) -> Weight { - // Minimum execution time: 92_462 nanoseconds. - Weight::from_ref_time(93_684_047) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(51_643).saturating_mul(l.into())) - .saturating_add(T::DbWeight::get().reads(9)) - .saturating_add(T::DbWeight::get().writes(8)) - } - // Storage: System Account (r:1 w:1) - // Storage: Staking Bonded (r:1 w:1) - // Storage: Staking Ledger (r:1 w:1) - // Storage: Staking SlashingSpans (r:1 w:1) - // Storage: Staking Validators (r:1 w:0) - // Storage: Staking Nominators (r:1 w:1) - // Storage: Staking CounterForNominators (r:1 w:1) - // Storage: VoterList ListNodes (r:2 w:2) - // Storage: VoterList ListBags (r:1 w:1) - // Storage: VoterList CounterForListNodes (r:1 w:1) - // Storage: Balances Locks (r:1 w:1) - // Storage: Staking Payee (r:0 w:1) - // Storage: Staking SpanSlash (r:0 w:1) + // Proof Size summary in bytes: + // Measured: `2215 + l * (7 ±0)` + // Estimated: `25491` + // Minimum execution time: 86_750 nanoseconds. + Weight::from_ref_time(90_496_328) + .saturating_add(Weight::from_proof_size(25491)) + // Standard Error: 5_292 + .saturating_add(Weight::from_ref_time(58_052).saturating_mul(l.into())) + .saturating_add(T::DbWeight::get().reads(9_u64)) + .saturating_add(T::DbWeight::get().writes(8_u64)) + } + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Staking Bonded (r:1 w:1) + /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) + /// Storage: Staking Ledger (r:1 w:1) + /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) + /// Storage: Staking SlashingSpans (r:1 w:1) + /// Proof Skipped: Staking SlashingSpans (max_values: None, max_size: None, mode: Measured) + /// Storage: Staking Validators (r:1 w:0) + /// Proof: Staking Validators (max_values: None, max_size: Some(45), added: 2520, mode: MaxEncodedLen) + /// Storage: Staking Nominators (r:1 w:1) + /// Proof: Staking Nominators (max_values: None, max_size: Some(558), added: 3033, mode: MaxEncodedLen) + /// Storage: Staking CounterForNominators (r:1 w:1) + /// Proof: Staking CounterForNominators (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: VoterList ListNodes (r:2 w:2) + /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) + /// Storage: VoterList ListBags (r:1 w:1) + /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) + /// Storage: VoterList CounterForListNodes (r:1 w:1) + /// Proof: VoterList CounterForListNodes (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Staking Payee (r:0 w:1) + /// Proof: Staking Payee (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) + /// Storage: Staking SpanSlash (r:0 w:100) + /// Proof: Staking SpanSlash (max_values: None, max_size: Some(76), added: 2551, mode: MaxEncodedLen) /// The range of component `s` is `[1, 100]`. fn reap_stash(s: u32, ) -> Weight { - // Minimum execution time: 92_003 nanoseconds. - Weight::from_ref_time(93_936_550) - // Standard Error: 2_091 - .saturating_add(Weight::from_ref_time(1_088_847).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(12)) - .saturating_add(T::DbWeight::get().writes(12)) + // Proof Size summary in bytes: + // Measured: `2388 + s * (4 ±0)` + // Estimated: `31712 + s * (4 ±0)` + // Minimum execution time: 89_155 nanoseconds. + Weight::from_ref_time(94_547_569) + .saturating_add(Weight::from_proof_size(31712)) + // Standard Error: 4_227 + .saturating_add(Weight::from_ref_time(1_330_189).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(12_u64)) + .saturating_add(T::DbWeight::get().writes(12_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) + .saturating_add(Weight::from_proof_size(4).saturating_mul(s.into())) } - // Storage: VoterList CounterForListNodes (r:1 w:0) - // Storage: VoterList ListBags (r:200 w:0) - // Storage: VoterList ListNodes (r:101 w:0) - // Storage: Staking Nominators (r:101 w:0) - // Storage: Staking Validators (r:2 w:0) - // Storage: Staking Bonded (r:101 w:0) - // Storage: Staking Ledger (r:101 w:0) - // Storage: Staking CounterForValidators (r:1 w:0) - // Storage: Staking ValidatorCount (r:1 w:0) - // Storage: Staking MinimumValidatorCount (r:1 w:0) - // Storage: Staking CurrentEra (r:1 w:1) - // Storage: Staking ErasValidatorPrefs (r:0 w:1) - // Storage: Staking ErasStakersPaged (r:0 w:1) - // Storage: Staking ErasStakersOverview (r:0 w:1) - // Storage: Staking ErasStakers (r:0 w:1) - // Storage: Staking ErasTotalStake (r:0 w:1) - // Storage: Staking ErasStartSessionIndex (r:0 w:1) - // Storage: Staking MinimumActiveStake (r:0 w:1) + /// Storage: VoterList CounterForListNodes (r:1 w:0) + /// Proof: VoterList CounterForListNodes (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: VoterList ListBags (r:200 w:0) + /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) + /// Storage: VoterList ListNodes (r:110 w:0) + /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) + /// Storage: Staking Nominators (r:110 w:0) + /// Proof: Staking Nominators (max_values: None, max_size: Some(558), added: 3033, mode: MaxEncodedLen) + /// Storage: Staking Validators (r:11 w:0) + /// Proof: Staking Validators (max_values: None, max_size: Some(45), added: 2520, mode: MaxEncodedLen) + /// Storage: Staking Bonded (r:110 w:0) + /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) + /// Storage: Staking Ledger (r:110 w:0) + /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) + /// Storage: Staking CounterForValidators (r:1 w:0) + /// Proof: Staking CounterForValidators (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking ValidatorCount (r:1 w:0) + /// Proof: Staking ValidatorCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking MinimumValidatorCount (r:1 w:0) + /// Proof: Staking MinimumValidatorCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking CurrentEra (r:1 w:1) + /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking ErasValidatorPrefs (r:0 w:10) + /// Proof: Staking ErasValidatorPrefs (max_values: None, max_size: Some(57), added: 2532, mode: MaxEncodedLen) + /// Storage: Staking ErasStakersPaged (r:0 w:10) + /// Proof Skipped: Staking ErasStakersPaged (max_values: None, max_size: None, mode: Measured) + /// Storage: Staking ErasStakersOverview (r:0 w:10) + /// Proof: Staking ErasStakersOverview (max_values: None, max_size: Some(92), added: 2567, mode: MaxEncodedLen) + /// Storage: Staking ErasTotalStake (r:0 w:1) + /// Proof: Staking ErasTotalStake (max_values: None, max_size: Some(28), added: 2503, mode: MaxEncodedLen) + /// Storage: Staking ErasStartSessionIndex (r:0 w:1) + /// Proof: Staking ErasStartSessionIndex (max_values: None, max_size: Some(16), added: 2491, mode: MaxEncodedLen) + /// Storage: Staking MinimumActiveStake (r:0 w:1) + /// Proof: Staking MinimumActiveStake (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) /// The range of component `v` is `[1, 10]`. /// The range of component `n` is `[0, 100]`. fn new_era(v: u32, n: u32, ) -> Weight { - // Minimum execution time: 504_224 nanoseconds. - Weight::from_ref_time(506_290_000) - // Standard Error: 1_802_746 - .saturating_add(Weight::from_ref_time(60_725_475).saturating_mul(v.into())) - // Standard Error: 179_633 - .saturating_add(Weight::from_ref_time(13_820_500).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(206)) + // Proof Size summary in bytes: + // Measured: `0 + v * (3662 ±0) + n * (816 ±0)` + // Estimated: `523708 + v * (15469 ±41) + n * (12348 ±4)` + // Minimum execution time: 577_839 nanoseconds. + Weight::from_ref_time(587_063_000) + .saturating_add(Weight::from_proof_size(523708)) + // Standard Error: 2_193_535 + .saturating_add(Weight::from_ref_time(72_675_973).saturating_mul(v.into())) + // Standard Error: 218_573 + .saturating_add(Weight::from_ref_time(19_272_321).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(206_u64)) .saturating_add(T::DbWeight::get().reads((5_u64).saturating_mul(v.into()))) .saturating_add(T::DbWeight::get().reads((4_u64).saturating_mul(n.into()))) - .saturating_add(T::DbWeight::get().writes(3)) - .saturating_add(T::DbWeight::get().writes((4_u64).saturating_mul(v.into()))) - } - // Storage: VoterList CounterForListNodes (r:1 w:0) - // Storage: VoterList ListBags (r:200 w:0) - // Storage: VoterList ListNodes (r:1500 w:0) - // Storage: Staking Nominators (r:1500 w:0) - // Storage: Staking Validators (r:500 w:0) - // Storage: Staking Bonded (r:1500 w:0) - // Storage: Staking Ledger (r:1500 w:0) - // Storage: Staking MinimumActiveStake (r:0 w:1) + .saturating_add(T::DbWeight::get().writes(3_u64)) + .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(v.into()))) + .saturating_add(Weight::from_proof_size(15469).saturating_mul(v.into())) + .saturating_add(Weight::from_proof_size(12348).saturating_mul(n.into())) + } + /// Storage: VoterList CounterForListNodes (r:1 w:0) + /// Proof: VoterList CounterForListNodes (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: VoterList ListBags (r:200 w:0) + /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) + /// Storage: VoterList ListNodes (r:2000 w:0) + /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) + /// Storage: Staking Nominators (r:2000 w:0) + /// Proof: Staking Nominators (max_values: None, max_size: Some(558), added: 3033, mode: MaxEncodedLen) + /// Storage: Staking Validators (r:1000 w:0) + /// Proof: Staking Validators (max_values: None, max_size: Some(45), added: 2520, mode: MaxEncodedLen) + /// Storage: Staking Bonded (r:2000 w:0) + /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) + /// Storage: Staking Ledger (r:2000 w:0) + /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) + /// Storage: Staking MinimumActiveStake (r:0 w:1) + /// Proof: Staking MinimumActiveStake (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) /// The range of component `v` is `[500, 1000]`. /// The range of component `n` is `[500, 1000]`. fn get_npos_voters(v: u32, n: u32, ) -> Weight { - // Minimum execution time: 24_224_895 nanoseconds. - Weight::from_ref_time(24_374_544_000) - // Standard Error: 319_103 - .saturating_add(Weight::from_ref_time(3_422_743).saturating_mul(v.into())) - // Standard Error: 319_103 - .saturating_add(Weight::from_ref_time(2_914_359).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(201)) + // Proof Size summary in bytes: + // Measured: `3125 + v * (459 ±0) + n * (1007 ±0)` + // Estimated: `511899 + v * (14295 ±0) + n * (11775 ±0)` + // Minimum execution time: 38_014_741 nanoseconds. + Weight::from_ref_time(39_016_264_000) + .saturating_add(Weight::from_proof_size(511899)) + // Standard Error: 409_554 + .saturating_add(Weight::from_ref_time(4_585_268).saturating_mul(v.into())) + // Standard Error: 409_554 + .saturating_add(Weight::from_ref_time(5_027_951).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(201_u64)) .saturating_add(T::DbWeight::get().reads((5_u64).saturating_mul(v.into()))) .saturating_add(T::DbWeight::get().reads((4_u64).saturating_mul(n.into()))) - .saturating_add(T::DbWeight::get().writes(1)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + .saturating_add(Weight::from_proof_size(14295).saturating_mul(v.into())) + .saturating_add(Weight::from_proof_size(11775).saturating_mul(n.into())) } - // Storage: Staking CounterForValidators (r:1 w:0) - // Storage: Staking Validators (r:501 w:0) + /// Storage: Staking CounterForValidators (r:1 w:0) + /// Proof: Staking CounterForValidators (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking Validators (r:1001 w:0) + /// Proof: Staking Validators (max_values: None, max_size: Some(45), added: 2520, mode: MaxEncodedLen) /// The range of component `v` is `[500, 1000]`. fn get_npos_targets(v: u32, ) -> Weight { - // Minimum execution time: 4_765_318 nanoseconds. - Weight::from_ref_time(4_816_708_000) - // Standard Error: 54_677 - .saturating_add(Weight::from_ref_time(3_541_818).saturating_mul(v.into())) - .saturating_add(T::DbWeight::get().reads(2)) + // Proof Size summary in bytes: + // Measured: `979 + v * (50 ±0)` + // Estimated: `3019 + v * (2520 ±0)` + // Minimum execution time: 4_283_114 nanoseconds. + Weight::from_ref_time(4_393_678_000) + .saturating_add(Weight::from_proof_size(3019)) + // Standard Error: 49_897 + .saturating_add(Weight::from_ref_time(3_190_372).saturating_mul(v.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(v.into()))) + .saturating_add(Weight::from_proof_size(2520).saturating_mul(v.into())) } - // Storage: Staking MinCommission (r:0 w:1) - // 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) + /// Storage: Staking MinCommission (r:0 w:1) + /// Proof: Staking MinCommission (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking MinValidatorBond (r:0 w:1) + /// Proof: Staking MinValidatorBond (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) + /// Storage: Staking MaxValidatorsCount (r:0 w:1) + /// Proof: Staking MaxValidatorsCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking ChillThreshold (r:0 w:1) + /// Proof: Staking ChillThreshold (max_values: Some(1), max_size: Some(1), added: 496, mode: MaxEncodedLen) + /// Storage: Staking MaxNominatorsCount (r:0 w:1) + /// Proof: Staking MaxNominatorsCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking MinNominatorBond (r:0 w:1) + /// Proof: Staking MinNominatorBond (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) fn set_staking_configs_all_set() -> Weight { - // Minimum execution time: 10_480 nanoseconds. - Weight::from_ref_time(10_914_000) - .saturating_add(T::DbWeight::get().writes(6)) - } - // Storage: Staking MinCommission (r:0 w:1) - // 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) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 7_398 nanoseconds. + Weight::from_ref_time(7_711_000) + .saturating_add(Weight::from_proof_size(0)) + .saturating_add(T::DbWeight::get().writes(6_u64)) + } + /// Storage: Staking MinCommission (r:0 w:1) + /// Proof: Staking MinCommission (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking MinValidatorBond (r:0 w:1) + /// Proof: Staking MinValidatorBond (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) + /// Storage: Staking MaxValidatorsCount (r:0 w:1) + /// Proof: Staking MaxValidatorsCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking ChillThreshold (r:0 w:1) + /// Proof: Staking ChillThreshold (max_values: Some(1), max_size: Some(1), added: 496, mode: MaxEncodedLen) + /// Storage: Staking MaxNominatorsCount (r:0 w:1) + /// Proof: Staking MaxNominatorsCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking MinNominatorBond (r:0 w:1) + /// Proof: Staking MinNominatorBond (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) fn set_staking_configs_all_remove() -> Weight { - // Minimum execution time: 9_529 nanoseconds. - Weight::from_ref_time(10_159_000) - .saturating_add(T::DbWeight::get().writes(6)) - } - // Storage: Staking Ledger (r:1 w:0) - // Storage: Staking Nominators (r:1 w:1) - // Storage: Staking ChillThreshold (r:1 w:0) - // Storage: Staking MaxNominatorsCount (r:1 w:0) - // Storage: Staking CounterForNominators (r:1 w:1) - // Storage: Staking MinNominatorBond (r:1 w:0) - // Storage: Staking Validators (r:1 w:0) - // Storage: VoterList ListNodes (r:2 w:2) - // Storage: VoterList ListBags (r:1 w:1) - // Storage: VoterList CounterForListNodes (r:1 w:1) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 6_598 nanoseconds. + Weight::from_ref_time(6_970_000) + .saturating_add(Weight::from_proof_size(0)) + .saturating_add(T::DbWeight::get().writes(6_u64)) + } + /// Storage: Staking Ledger (r:1 w:0) + /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) + /// Storage: Staking Nominators (r:1 w:1) + /// Proof: Staking Nominators (max_values: None, max_size: Some(558), added: 3033, mode: MaxEncodedLen) + /// Storage: Staking ChillThreshold (r:1 w:0) + /// Proof: Staking ChillThreshold (max_values: Some(1), max_size: Some(1), added: 496, mode: MaxEncodedLen) + /// Storage: Staking MaxNominatorsCount (r:1 w:0) + /// Proof: Staking MaxNominatorsCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking CounterForNominators (r:1 w:1) + /// Proof: Staking CounterForNominators (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking MinNominatorBond (r:1 w:0) + /// Proof: Staking MinNominatorBond (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) + /// Storage: Staking Validators (r:1 w:0) + /// Proof: Staking Validators (max_values: None, max_size: Some(45), added: 2520, mode: MaxEncodedLen) + /// Storage: VoterList ListNodes (r:2 w:2) + /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) + /// Storage: VoterList ListBags (r:1 w:1) + /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) + /// Storage: VoterList CounterForListNodes (r:1 w:1) + /// Proof: VoterList CounterForListNodes (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) fn chill_other() -> Weight { - // Minimum execution time: 81_347 nanoseconds. - Weight::from_ref_time(81_957_000) - .saturating_add(T::DbWeight::get().reads(11)) - .saturating_add(T::DbWeight::get().writes(6)) + // Proof Size summary in bytes: + // Measured: `1933` + // Estimated: `19438` + // Minimum execution time: 72_003 nanoseconds. + Weight::from_ref_time(73_575_000) + .saturating_add(Weight::from_proof_size(19438)) + .saturating_add(T::DbWeight::get().reads(11_u64)) + .saturating_add(T::DbWeight::get().writes(6_u64)) } - // Storage: Staking MinCommission (r:1 w:0) - // Storage: Staking Validators (r:1 w:1) + /// Storage: Staking MinCommission (r:1 w:0) + /// Proof: Staking MinCommission (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking Validators (r:1 w:1) + /// Proof: Staking Validators (max_values: None, max_size: Some(45), added: 2520, mode: MaxEncodedLen) fn force_apply_min_commission() -> Weight { - // Minimum execution time: 19_153 nanoseconds. - Weight::from_ref_time(19_621_000) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) + // Proof Size summary in bytes: + // Measured: `691` + // Estimated: `3019` + // Minimum execution time: 13_540 nanoseconds. + Weight::from_ref_time(14_129_000) + .saturating_add(Weight::from_proof_size(3019)) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) } - // Storage: Staking MinCommission (r:0 w:1) + /// Storage: Staking MinCommission (r:0 w:1) + /// Proof: Staking MinCommission (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) fn set_min_commission() -> Weight { - // Minimum execution time: 6_058 nanoseconds. - Weight::from_ref_time(6_278_000) - .saturating_add(T::DbWeight::get().writes(1)) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 3_511 nanoseconds. + Weight::from_ref_time(3_633_000) + .saturating_add(Weight::from_proof_size(0)) + .saturating_add(T::DbWeight::get().writes(1_u64)) } } // For backwards compatibility and tests impl WeightInfo for () { - // Storage: Staking Bonded (r:1 w:1) - // Storage: Staking Ledger (r:1 w:1) - // Storage: Balances Locks (r:1 w:1) - // Storage: Staking Payee (r:0 w:1) + /// Storage: Staking Bonded (r:1 w:1) + /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) + /// Storage: Staking Ledger (r:1 w:1) + /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Staking Payee (r:0 w:1) + /// Proof: Staking Payee (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) fn bond() -> Weight { - // Minimum execution time: 51_815 nanoseconds. - Weight::from_ref_time(52_367_000) - .saturating_add(RocksDbWeight::get().reads(3)) - .saturating_add(RocksDbWeight::get().writes(4)) - } - // Storage: Staking Bonded (r:1 w:0) - // Storage: Staking Ledger (r:1 w:1) - // Storage: Balances Locks (r:1 w:1) - // Storage: VoterList ListNodes (r:3 w:3) - // Storage: VoterList ListBags (r:2 w:2) + // Proof Size summary in bytes: + // Measured: `1074` + // Estimated: `9887` + // Minimum execution time: 42_791 nanoseconds. + Weight::from_ref_time(43_964_000) + .saturating_add(Weight::from_proof_size(9887)) + .saturating_add(RocksDbWeight::get().reads(3_u64)) + .saturating_add(RocksDbWeight::get().writes(4_u64)) + } + /// Storage: Staking Bonded (r:1 w:0) + /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) + /// Storage: Staking Ledger (r:1 w:1) + /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: VoterList ListNodes (r:3 w:3) + /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) + /// Storage: VoterList ListBags (r:2 w:2) + /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) fn bond_extra() -> Weight { - // Minimum execution time: 91_792 nanoseconds. - Weight::from_ref_time(92_729_000) - .saturating_add(RocksDbWeight::get().reads(8)) - .saturating_add(RocksDbWeight::get().writes(7)) - } - // Storage: Staking Ledger (r:1 w:1) - // Storage: Staking Nominators (r:1 w:0) - // Storage: Staking MinNominatorBond (r:1 w:0) - // Storage: Staking CurrentEra (r:1 w:0) - // Storage: Balances Locks (r:1 w:1) - // Storage: System Account (r:1 w:1) - // Storage: VoterList ListNodes (r:3 w:3) - // Storage: Staking Bonded (r:1 w:0) - // Storage: VoterList ListBags (r:2 w:2) + // Proof Size summary in bytes: + // Measured: `2214` + // Estimated: `22888` + // Minimum execution time: 87_712 nanoseconds. + Weight::from_ref_time(90_269_000) + .saturating_add(Weight::from_proof_size(22888)) + .saturating_add(RocksDbWeight::get().reads(8_u64)) + .saturating_add(RocksDbWeight::get().writes(7_u64)) + } + /// Storage: Staking Ledger (r:1 w:1) + /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) + /// Storage: Staking Nominators (r:1 w:0) + /// Proof: Staking Nominators (max_values: None, max_size: Some(558), added: 3033, mode: MaxEncodedLen) + /// Storage: Staking MinNominatorBond (r:1 w:0) + /// Proof: Staking MinNominatorBond (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) + /// Storage: Staking CurrentEra (r:1 w:0) + /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: VoterList ListNodes (r:3 w:3) + /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) + /// Storage: Staking Bonded (r:1 w:0) + /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) + /// Storage: VoterList ListBags (r:2 w:2) + /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) fn unbond() -> Weight { - // Minimum execution time: 97_647 nanoseconds. - Weight::from_ref_time(98_731_000) - .saturating_add(RocksDbWeight::get().reads(12)) - .saturating_add(RocksDbWeight::get().writes(8)) - } - // Storage: Staking Ledger (r:1 w:1) - // Storage: Staking CurrentEra (r:1 w:0) - // Storage: Balances Locks (r:1 w:1) - // Storage: System Account (r:1 w:1) + // Proof Size summary in bytes: + // Measured: `2419` + // Estimated: `29534` + // Minimum execution time: 95_748 nanoseconds. + Weight::from_ref_time(98_423_000) + .saturating_add(Weight::from_proof_size(29534)) + .saturating_add(RocksDbWeight::get().reads(12_u64)) + .saturating_add(RocksDbWeight::get().writes(8_u64)) + } + /// Storage: Staking Ledger (r:1 w:1) + /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) + /// Storage: Staking CurrentEra (r:1 w:0) + /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// The range of component `s` is `[0, 100]`. fn withdraw_unbonded_update(s: u32, ) -> Weight { - // Minimum execution time: 44_744 nanoseconds. - Weight::from_ref_time(45_658_968) - // Standard Error: 692 - .saturating_add(Weight::from_ref_time(65_958).saturating_mul(s.into())) - .saturating_add(RocksDbWeight::get().reads(4)) - .saturating_add(RocksDbWeight::get().writes(3)) - } - // Storage: Staking Ledger (r:1 w:1) - // Storage: Staking CurrentEra (r:1 w:0) - // Storage: Staking Bonded (r:1 w:1) - // Storage: Staking SlashingSpans (r:1 w:0) - // Storage: Staking Validators (r:1 w:0) - // Storage: Staking Nominators (r:1 w:1) - // Storage: Staking CounterForNominators (r:1 w:1) - // Storage: VoterList ListNodes (r:2 w:2) - // Storage: VoterList ListBags (r:1 w:1) - // Storage: VoterList CounterForListNodes (r:1 w:1) - // Storage: System Account (r:1 w:1) - // Storage: Balances Locks (r:1 w:1) - // Storage: Staking Payee (r:0 w:1) - // Storage: Staking SpanSlash (r:0 w:2) + // Proof Size summary in bytes: + // Measured: `1080` + // Estimated: `10442` + // Minimum execution time: 34_556 nanoseconds. + Weight::from_ref_time(36_352_208) + .saturating_add(Weight::from_proof_size(10442)) + // Standard Error: 975 + .saturating_add(Weight::from_ref_time(42_685).saturating_mul(s.into())) + .saturating_add(RocksDbWeight::get().reads(4_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) + } + /// Storage: Staking Ledger (r:1 w:1) + /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) + /// Storage: Staking CurrentEra (r:1 w:0) + /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking Bonded (r:1 w:1) + /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) + /// Storage: Staking SlashingSpans (r:1 w:1) + /// Proof Skipped: Staking SlashingSpans (max_values: None, max_size: None, mode: Measured) + /// Storage: Staking Validators (r:1 w:0) + /// Proof: Staking Validators (max_values: None, max_size: Some(45), added: 2520, mode: MaxEncodedLen) + /// Storage: Staking Nominators (r:1 w:1) + /// Proof: Staking Nominators (max_values: None, max_size: Some(558), added: 3033, mode: MaxEncodedLen) + /// Storage: Staking CounterForNominators (r:1 w:1) + /// Proof: Staking CounterForNominators (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: VoterList ListNodes (r:2 w:2) + /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) + /// Storage: VoterList ListBags (r:1 w:1) + /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) + /// Storage: VoterList CounterForListNodes (r:1 w:1) + /// Proof: VoterList CounterForListNodes (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Staking Payee (r:0 w:1) + /// Proof: Staking Payee (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) + /// Storage: Staking SpanSlash (r:0 w:100) + /// Proof: Staking SpanSlash (max_values: None, max_size: Some(76), added: 2551, mode: MaxEncodedLen) /// The range of component `s` is `[0, 100]`. fn withdraw_unbonded_kill(s: u32, ) -> Weight { - // Minimum execution time: 86_013 nanoseconds. - Weight::from_ref_time(91_544_236) - // Standard Error: 2_273 - .saturating_add(Weight::from_ref_time(1_073_291).saturating_mul(s.into())) - .saturating_add(RocksDbWeight::get().reads(13)) - .saturating_add(RocksDbWeight::get().writes(12)) + // Proof Size summary in bytes: + // Measured: `2388 + s * (4 ±0)` + // Estimated: `32205 + s * (4 ±0)` + // Minimum execution time: 82_858 nanoseconds. + Weight::from_ref_time(90_123_003) + .saturating_add(Weight::from_proof_size(32205)) + // Standard Error: 3_084 + .saturating_add(Weight::from_ref_time(1_363_655).saturating_mul(s.into())) + .saturating_add(RocksDbWeight::get().reads(13_u64)) + .saturating_add(RocksDbWeight::get().writes(12_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(s.into()))) + .saturating_add(Weight::from_proof_size(4).saturating_mul(s.into())) } - // Storage: Staking Ledger (r:1 w:0) - // Storage: Staking MinValidatorBond (r:1 w:0) - // Storage: Staking MinCommission (r:1 w:0) - // Storage: Staking Validators (r:1 w:1) - // Storage: Staking MaxValidatorsCount (r:1 w:0) - // Storage: Staking Nominators (r:1 w:0) - // Storage: Staking Bonded (r:1 w:0) - // Storage: VoterList ListNodes (r:1 w:1) - // Storage: VoterList ListBags (r:1 w:1) - // Storage: VoterList CounterForListNodes (r:1 w:1) - // Storage: Staking CounterForValidators (r:1 w:1) + /// Storage: Staking Ledger (r:1 w:0) + /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) + /// Storage: Staking MinValidatorBond (r:1 w:0) + /// Proof: Staking MinValidatorBond (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) + /// Storage: Staking MinCommission (r:1 w:0) + /// Proof: Staking MinCommission (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking Validators (r:1 w:1) + /// Proof: Staking Validators (max_values: None, max_size: Some(45), added: 2520, mode: MaxEncodedLen) + /// Storage: Staking MaxValidatorsCount (r:1 w:0) + /// Proof: Staking MaxValidatorsCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking Nominators (r:1 w:0) + /// Proof: Staking Nominators (max_values: None, max_size: Some(558), added: 3033, mode: MaxEncodedLen) + /// Storage: Staking Bonded (r:1 w:0) + /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) + /// Storage: VoterList ListNodes (r:1 w:1) + /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) + /// Storage: VoterList ListBags (r:1 w:1) + /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) + /// Storage: VoterList CounterForListNodes (r:1 w:1) + /// Proof: VoterList CounterForListNodes (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking CounterForValidators (r:1 w:1) + /// Proof: Staking CounterForValidators (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) fn validate() -> Weight { - // Minimum execution time: 66_579 nanoseconds. - Weight::from_ref_time(67_026_000) - .saturating_add(RocksDbWeight::get().reads(11)) - .saturating_add(RocksDbWeight::get().writes(5)) + // Proof Size summary in bytes: + // Measured: `1404` + // Estimated: `19359` + // Minimum execution time: 57_223 nanoseconds. + Weight::from_ref_time(59_188_000) + .saturating_add(Weight::from_proof_size(19359)) + .saturating_add(RocksDbWeight::get().reads(11_u64)) + .saturating_add(RocksDbWeight::get().writes(5_u64)) } - // Storage: Staking Ledger (r:1 w:0) - // Storage: Staking Nominators (r:1 w:1) + /// Storage: Staking Ledger (r:1 w:0) + /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) + /// Storage: Staking Nominators (r:128 w:128) + /// Proof: Staking Nominators (max_values: None, max_size: Some(558), added: 3033, mode: MaxEncodedLen) /// The range of component `k` is `[1, 128]`. fn kick(k: u32, ) -> Weight { - // Minimum execution time: 40_716 nanoseconds. - Weight::from_ref_time(43_678_932) - // Standard Error: 15_099 - .saturating_add(Weight::from_ref_time(6_814_991).saturating_mul(k.into())) - .saturating_add(RocksDbWeight::get().reads(1)) + // Proof Size summary in bytes: + // Measured: `1287 + k * (601 ±0)` + // Estimated: `3566 + k * (3033 ±0)` + // Minimum execution time: 30_970 nanoseconds. + Weight::from_ref_time(32_205_531) + .saturating_add(Weight::from_proof_size(3566)) + // Standard Error: 12_307 + .saturating_add(Weight::from_ref_time(8_599_234).saturating_mul(k.into())) + .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(k.into()))) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(k.into()))) + .saturating_add(Weight::from_proof_size(3033).saturating_mul(k.into())) } - // Storage: Staking Ledger (r:1 w:0) - // Storage: Staking MinNominatorBond (r:1 w:0) - // Storage: Staking Nominators (r:1 w:1) - // Storage: Staking MaxNominatorsCount (r:1 w:0) - // Storage: Staking Validators (r:2 w:0) - // Storage: Staking CurrentEra (r:1 w:0) - // Storage: Staking Bonded (r:1 w:0) - // Storage: VoterList ListNodes (r:2 w:2) - // Storage: VoterList ListBags (r:1 w:1) - // Storage: VoterList CounterForListNodes (r:1 w:1) - // Storage: Staking CounterForNominators (r:1 w:1) + /// Storage: Staking Ledger (r:1 w:0) + /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) + /// Storage: Staking MinNominatorBond (r:1 w:0) + /// Proof: Staking MinNominatorBond (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) + /// Storage: Staking Nominators (r:1 w:1) + /// Proof: Staking Nominators (max_values: None, max_size: Some(558), added: 3033, mode: MaxEncodedLen) + /// Storage: Staking MaxNominatorsCount (r:1 w:0) + /// Proof: Staking MaxNominatorsCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking Validators (r:17 w:0) + /// Proof: Staking Validators (max_values: None, max_size: Some(45), added: 2520, mode: MaxEncodedLen) + /// Storage: Staking CurrentEra (r:1 w:0) + /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking Bonded (r:1 w:0) + /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) + /// Storage: VoterList ListNodes (r:2 w:2) + /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) + /// Storage: VoterList ListBags (r:1 w:1) + /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) + /// Storage: VoterList CounterForListNodes (r:1 w:1) + /// Proof: VoterList CounterForListNodes (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking CounterForNominators (r:1 w:1) + /// Proof: Staking CounterForNominators (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) /// The range of component `n` is `[1, 16]`. fn nominate(n: u32, ) -> Weight { - // Minimum execution time: 71_258 nanoseconds. - Weight::from_ref_time(70_901_125) - // Standard Error: 6_183 - .saturating_add(Weight::from_ref_time(2_777_341).saturating_mul(n.into())) - .saturating_add(RocksDbWeight::get().reads(12)) + // Proof Size summary in bytes: + // Measured: `1942 + n * (105 ±0)` + // Estimated: `21988 + n * (2520 ±0)` + // Minimum execution time: 69_223 nanoseconds. + Weight::from_ref_time(68_719_145) + .saturating_add(Weight::from_proof_size(21988)) + // Standard Error: 19_229 + .saturating_add(Weight::from_ref_time(4_075_338).saturating_mul(n.into())) + .saturating_add(RocksDbWeight::get().reads(12_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(n.into()))) - .saturating_add(RocksDbWeight::get().writes(6)) - } - // Storage: Staking Ledger (r:1 w:0) - // Storage: Staking Validators (r:1 w:0) - // Storage: Staking Nominators (r:1 w:1) - // Storage: Staking CounterForNominators (r:1 w:1) - // Storage: VoterList ListNodes (r:2 w:2) - // Storage: VoterList ListBags (r:1 w:1) - // Storage: VoterList CounterForListNodes (r:1 w:1) + .saturating_add(RocksDbWeight::get().writes(6_u64)) + .saturating_add(Weight::from_proof_size(2520).saturating_mul(n.into())) + } + /// Storage: Staking Ledger (r:1 w:0) + /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) + /// Storage: Staking Validators (r:1 w:0) + /// Proof: Staking Validators (max_values: None, max_size: Some(45), added: 2520, mode: MaxEncodedLen) + /// Storage: Staking Nominators (r:1 w:1) + /// Proof: Staking Nominators (max_values: None, max_size: Some(558), added: 3033, mode: MaxEncodedLen) + /// Storage: Staking CounterForNominators (r:1 w:1) + /// Proof: Staking CounterForNominators (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: VoterList ListNodes (r:2 w:2) + /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) + /// Storage: VoterList ListBags (r:1 w:1) + /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) + /// Storage: VoterList CounterForListNodes (r:1 w:1) + /// Proof: VoterList CounterForListNodes (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) fn chill() -> Weight { - // Minimum execution time: 66_052 nanoseconds. - Weight::from_ref_time(66_480_000) - .saturating_add(RocksDbWeight::get().reads(8)) - .saturating_add(RocksDbWeight::get().writes(6)) + // Proof Size summary in bytes: + // Measured: `1778` + // Estimated: `17932` + // Minimum execution time: 58_126 nanoseconds. + Weight::from_ref_time(59_792_000) + .saturating_add(Weight::from_proof_size(17932)) + .saturating_add(RocksDbWeight::get().reads(8_u64)) + .saturating_add(RocksDbWeight::get().writes(6_u64)) } - // Storage: Staking Ledger (r:1 w:0) - // Storage: Staking Payee (r:0 w:1) + /// Storage: Staking Ledger (r:1 w:0) + /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) + /// Storage: Staking Payee (r:0 w:1) + /// Proof: Staking Payee (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) fn set_payee() -> Weight { - // Minimum execution time: 18_008 nanoseconds. - Weight::from_ref_time(18_360_000) - .saturating_add(RocksDbWeight::get().reads(1)) - .saturating_add(RocksDbWeight::get().writes(1)) + // Proof Size summary in bytes: + // Measured: `835` + // Estimated: `3566` + // Minimum execution time: 13_555 nanoseconds. + Weight::from_ref_time(14_016_000) + .saturating_add(Weight::from_proof_size(3566)) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) } - // Storage: Staking Bonded (r:1 w:1) - // Storage: Staking Ledger (r:2 w:2) + /// Storage: Staking Bonded (r:1 w:1) + /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) + /// Storage: Staking Ledger (r:2 w:2) + /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) fn set_controller() -> Weight { - // Minimum execution time: 25_979 nanoseconds. - Weight::from_ref_time(26_350_000) - .saturating_add(RocksDbWeight::get().reads(3)) - .saturating_add(RocksDbWeight::get().writes(3)) + // Proof Size summary in bytes: + // Measured: `934` + // Estimated: `9679` + // Minimum execution time: 21_301 nanoseconds. + Weight::from_ref_time(22_586_000) + .saturating_add(Weight::from_proof_size(9679)) + .saturating_add(RocksDbWeight::get().reads(3_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) } - // Storage: Staking ValidatorCount (r:0 w:1) + /// Storage: Staking ValidatorCount (r:0 w:1) + /// Proof: Staking ValidatorCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) fn set_validator_count() -> Weight { - // Minimum execution time: 5_009 nanoseconds. - Weight::from_ref_time(5_248_000) - .saturating_add(RocksDbWeight::get().writes(1)) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 2_830 nanoseconds. + Weight::from_ref_time(2_957_000) + .saturating_add(Weight::from_proof_size(0)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) } - // Storage: Staking ForceEra (r:0 w:1) + /// Storage: Staking ForceEra (r:0 w:1) + /// Proof: Staking ForceEra (max_values: Some(1), max_size: Some(1), added: 496, mode: MaxEncodedLen) fn force_no_eras() -> Weight { - // Minimum execution time: 19_493 nanoseconds. - Weight::from_ref_time(19_888_000) - .saturating_add(RocksDbWeight::get().writes(1)) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 10_600 nanoseconds. + Weight::from_ref_time(11_114_000) + .saturating_add(Weight::from_proof_size(0)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) } - // Storage: Staking ForceEra (r:0 w:1) + /// Storage: Staking ForceEra (r:0 w:1) + /// Proof: Staking ForceEra (max_values: Some(1), max_size: Some(1), added: 496, mode: MaxEncodedLen) fn force_new_era() -> Weight { - // Minimum execution time: 19_425 nanoseconds. - Weight::from_ref_time(19_991_000) - .saturating_add(RocksDbWeight::get().writes(1)) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 10_432 nanoseconds. + Weight::from_ref_time(10_984_000) + .saturating_add(Weight::from_proof_size(0)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) } - // Storage: Staking ForceEra (r:0 w:1) + /// Storage: Staking ForceEra (r:0 w:1) + /// Proof: Staking ForceEra (max_values: Some(1), max_size: Some(1), added: 496, mode: MaxEncodedLen) fn force_new_era_always() -> Weight { - // Minimum execution time: 19_690 nanoseconds. - Weight::from_ref_time(20_010_000) - .saturating_add(RocksDbWeight::get().writes(1)) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 10_565 nanoseconds. + Weight::from_ref_time(11_139_000) + .saturating_add(Weight::from_proof_size(0)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) } - // Storage: Staking Invulnerables (r:0 w:1) + /// Storage: Staking Invulnerables (r:0 w:1) + /// Proof Skipped: Staking Invulnerables (max_values: Some(1), max_size: None, mode: Measured) /// The range of component `v` is `[0, 1000]`. fn set_invulnerables(v: u32, ) -> Weight { - // Minimum execution time: 5_375 nanoseconds. - Weight::from_ref_time(6_217_068) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 2_988 nanoseconds. + Weight::from_ref_time(3_521_842) + .saturating_add(Weight::from_proof_size(0)) // Standard Error: 43 - .saturating_add(Weight::from_ref_time(9_885).saturating_mul(v.into())) - .saturating_add(RocksDbWeight::get().writes(1)) - } - // Storage: Staking Bonded (r:1 w:1) - // Storage: Staking SlashingSpans (r:1 w:0) - // Storage: Staking Validators (r:1 w:0) - // Storage: Staking Nominators (r:1 w:1) - // Storage: Staking CounterForNominators (r:1 w:1) - // Storage: VoterList ListNodes (r:2 w:2) - // Storage: VoterList ListBags (r:1 w:1) - // Storage: VoterList CounterForListNodes (r:1 w:1) - // Storage: System Account (r:1 w:1) - // Storage: Balances Locks (r:1 w:1) - // Storage: Staking Ledger (r:0 w:1) - // Storage: Staking Payee (r:0 w:1) - // Storage: Staking SpanSlash (r:0 w:2) + .saturating_add(Weight::from_ref_time(9_580).saturating_mul(v.into())) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: Staking Bonded (r:1 w:1) + /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) + /// Storage: Staking SlashingSpans (r:1 w:1) + /// Proof Skipped: Staking SlashingSpans (max_values: None, max_size: None, mode: Measured) + /// Storage: Staking Validators (r:1 w:0) + /// Proof: Staking Validators (max_values: None, max_size: Some(45), added: 2520, mode: MaxEncodedLen) + /// Storage: Staking Nominators (r:1 w:1) + /// Proof: Staking Nominators (max_values: None, max_size: Some(558), added: 3033, mode: MaxEncodedLen) + /// Storage: Staking CounterForNominators (r:1 w:1) + /// Proof: Staking CounterForNominators (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: VoterList ListNodes (r:2 w:2) + /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) + /// Storage: VoterList ListBags (r:1 w:1) + /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) + /// Storage: VoterList CounterForListNodes (r:1 w:1) + /// Proof: VoterList CounterForListNodes (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Staking Ledger (r:0 w:1) + /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) + /// Storage: Staking Payee (r:0 w:1) + /// Proof: Staking Payee (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) + /// Storage: Staking SpanSlash (r:0 w:100) + /// Proof: Staking SpanSlash (max_values: None, max_size: Some(76), added: 2551, mode: MaxEncodedLen) /// The range of component `s` is `[0, 100]`. fn force_unstake(s: u32, ) -> Weight { - // Minimum execution time: 79_630 nanoseconds. - Weight::from_ref_time(85_354_738) - // Standard Error: 2_555 - .saturating_add(Weight::from_ref_time(1_086_827).saturating_mul(s.into())) - .saturating_add(RocksDbWeight::get().reads(11)) - .saturating_add(RocksDbWeight::get().writes(12)) + // Proof Size summary in bytes: + // Measured: `2118 + s * (4 ±0)` + // Estimated: `27870 + s * (4 ±0)` + // Minimum execution time: 75_086 nanoseconds. + Weight::from_ref_time(82_863_879) + .saturating_add(Weight::from_proof_size(27870)) + // Standard Error: 3_873 + .saturating_add(Weight::from_ref_time(1_339_680).saturating_mul(s.into())) + .saturating_add(RocksDbWeight::get().reads(11_u64)) + .saturating_add(RocksDbWeight::get().writes(12_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(s.into()))) + .saturating_add(Weight::from_proof_size(4).saturating_mul(s.into())) } - // Storage: Staking UnappliedSlashes (r:1 w:1) + /// Storage: Staking UnappliedSlashes (r:1 w:1) + /// Proof Skipped: Staking UnappliedSlashes (max_values: None, max_size: None, mode: Measured) /// The range of component `s` is `[1, 1000]`. fn cancel_deferred_slash(s: u32, ) -> Weight { - // Minimum execution time: 92_209 nanoseconds. - Weight::from_ref_time(901_022_610) - // Standard Error: 59_320 - .saturating_add(Weight::from_ref_time(4_943_518).saturating_mul(s.into())) - .saturating_add(RocksDbWeight::get().reads(1)) - .saturating_add(RocksDbWeight::get().writes(1)) - } - // Storage: Staking CurrentEra (r:1 w:0) - // Storage: Staking ErasStakersOverview (r:1 w:0) - // Storage: Staking ErasValidatorReward (r:1 w:0) - // Storage: Staking Bonded (r:1 w:0) - // Storage: Staking Ledger (r:1 w:1) - // Storage: Staking ClaimedRewards (r:1 w:1) - // Storage: Staking ErasStakersPaged (r:1 w:0) - // Storage: Staking ErasStakersClipped (r:1 w:0) - // Storage: Staking ErasRewardPoints (r:1 w:0) - // Storage: Staking ErasValidatorPrefs (r:1 w:0) - // Storage: Staking Payee (r:1 w:0) - // Storage: System Account (r:1 w:1) + // Proof Size summary in bytes: + // Measured: `66704` + // Estimated: `69179` + // Minimum execution time: 99_616 nanoseconds. + Weight::from_ref_time(910_033_266) + .saturating_add(Weight::from_proof_size(69179)) + // Standard Error: 58_519 + .saturating_add(Weight::from_ref_time(4_878_008).saturating_mul(s.into())) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: Staking CurrentEra (r:1 w:0) + /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking ErasStakersOverview (r:1 w:0) + /// Proof: Staking ErasStakersOverview (max_values: None, max_size: Some(92), added: 2567, mode: MaxEncodedLen) + /// Storage: Staking ErasValidatorReward (r:1 w:0) + /// Proof: Staking ErasValidatorReward (max_values: None, max_size: Some(28), added: 2503, mode: MaxEncodedLen) + /// Storage: Staking Bonded (r:257 w:0) + /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) + /// Storage: Staking Ledger (r:1 w:1) + /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) + /// Storage: Staking ClaimedRewards (r:1 w:1) + /// Proof Skipped: Staking ClaimedRewards (max_values: None, max_size: None, mode: Measured) + /// Storage: Staking ErasStakersPaged (r:1 w:0) + /// Proof Skipped: Staking ErasStakersPaged (max_values: None, max_size: None, mode: Measured) + /// Storage: Staking ErasRewardPoints (r:1 w:0) + /// Proof Skipped: Staking ErasRewardPoints (max_values: None, max_size: None, mode: Measured) + /// Storage: Staking ErasValidatorPrefs (r:1 w:0) + /// Proof: Staking ErasValidatorPrefs (max_values: None, max_size: Some(57), added: 2532, mode: MaxEncodedLen) + /// Storage: Staking Payee (r:257 w:0) + /// Proof: Staking Payee (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) + /// Storage: System Account (r:257 w:257) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// The range of component `n` is `[0, 256]`. fn payout_stakers_dead_controller(n: u32, ) -> Weight { - // Minimum execution time: 134_323 nanoseconds. - Weight::from_ref_time(200_066_020) - // Standard Error: 16_654 - .saturating_add(Weight::from_ref_time(21_841_097).saturating_mul(n.into())) - .saturating_add(RocksDbWeight::get().reads(11)) + // Proof Size summary in bytes: + // Measured: `20450 + n * (143 ±0)` + // Estimated: `76596 + n * (8187 ±1)` + // Minimum execution time: 120_810 nanoseconds. + Weight::from_ref_time(153_474_546) + .saturating_add(Weight::from_proof_size(76596)) + // Standard Error: 18_966 + .saturating_add(Weight::from_ref_time(28_752_414).saturating_mul(n.into())) + .saturating_add(RocksDbWeight::get().reads(11_u64)) .saturating_add(RocksDbWeight::get().reads((3_u64).saturating_mul(n.into()))) - .saturating_add(RocksDbWeight::get().writes(3)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(n.into()))) + .saturating_add(Weight::from_proof_size(8187).saturating_mul(n.into())) } - // Storage: Staking CurrentEra (r:1 w:0) - // Storage: Staking ErasStakersOverview (r:1 w:0) - // Storage: Staking ErasValidatorReward (r:1 w:0) - // Storage: Staking Bonded (r:1 w:0) - // Storage: Staking Ledger (r:1 w:1) - // Storage: Staking ClaimedRewards (r:1 w:1) - // Storage: Staking ErasStakersPaged (r:1 w:0) - // Storage: Staking ErasStakersClipped (r:1 w:0) - // Storage: Staking ErasRewardPoints (r:1 w:0) - // Storage: Staking ErasValidatorPrefs (r:1 w:0) - // Storage: Staking Payee (r:1 w:0) - // Storage: System Account (r:1 w:1) - // Storage: Balances Locks (r:1 w:1) + /// Storage: Staking Bonded (r:257 w:0) + /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) + /// Storage: Staking Ledger (r:257 w:257) + /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) + /// Storage: Staking ErasStakersClipped (r:1 w:0) + /// Proof Skipped: Staking ErasStakersClipped (max_values: None, max_size: None, mode: Measured) + /// Storage: Staking ErasStakersOverview (r:1 w:0) + /// Proof: Staking ErasStakersOverview (max_values: None, max_size: Some(92), added: 2567, mode: MaxEncodedLen) + /// Storage: Staking ClaimedRewards (r:1 w:1) + /// Proof Skipped: Staking ClaimedRewards (max_values: None, max_size: None, mode: Measured) + /// Storage: Staking CurrentEra (r:1 w:0) + /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking ErasValidatorReward (r:1 w:0) + /// Proof: Staking ErasValidatorReward (max_values: None, max_size: Some(28), added: 2503, mode: MaxEncodedLen) + /// Storage: Staking ErasStakersPaged (r:1 w:0) + /// Proof Skipped: Staking ErasStakersPaged (max_values: None, max_size: None, mode: Measured) + /// Storage: Staking ErasRewardPoints (r:1 w:0) + /// Proof Skipped: Staking ErasRewardPoints (max_values: None, max_size: None, mode: Measured) + /// Storage: Staking ErasValidatorPrefs (r:1 w:0) + /// Proof: Staking ErasValidatorPrefs (max_values: None, max_size: Some(57), added: 2532, mode: MaxEncodedLen) + /// Storage: Staking Payee (r:257 w:0) + /// Proof: Staking Payee (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) + /// Storage: System Account (r:257 w:257) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:257 w:257) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) /// The range of component `n` is `[0, 256]`. fn payout_stakers_alive_staked(n: u32, ) -> Weight { - // Minimum execution time: 166_885 nanoseconds. - Weight::from_ref_time(231_648_127) - // Standard Error: 30_392 - .saturating_add(Weight::from_ref_time(30_760_443).saturating_mul(n.into())) - .saturating_add(RocksDbWeight::get().reads(12)) + // Proof Size summary in bytes: + // Measured: `35204 + n * (465 ±0)` + // Estimated: `149575 + n * (17014 ±3)` + // Minimum execution time: 150_324 nanoseconds. + Weight::from_ref_time(148_039_697) + .saturating_add(Weight::from_proof_size(149575)) + // Standard Error: 39_048 + .saturating_add(Weight::from_ref_time(43_172_238).saturating_mul(n.into())) + .saturating_add(RocksDbWeight::get().reads(13_u64)) .saturating_add(RocksDbWeight::get().reads((5_u64).saturating_mul(n.into()))) - .saturating_add(RocksDbWeight::get().writes(4)) + .saturating_add(RocksDbWeight::get().writes(4_u64)) .saturating_add(RocksDbWeight::get().writes((3_u64).saturating_mul(n.into()))) + .saturating_add(Weight::from_proof_size(17014).saturating_mul(n.into())) } - // Storage: Staking Ledger (r:1 w:1) - // Storage: Balances Locks (r:1 w:1) - // Storage: System Account (r:1 w:1) - // Storage: VoterList ListNodes (r:3 w:3) - // Storage: Staking Bonded (r:1 w:0) - // Storage: VoterList ListBags (r:2 w:2) + /// Storage: Staking Ledger (r:1 w:1) + /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: VoterList ListNodes (r:3 w:3) + /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) + /// Storage: Staking Bonded (r:1 w:0) + /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) + /// Storage: VoterList ListBags (r:2 w:2) + /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) /// The range of component `l` is `[1, 32]`. fn rebond(l: u32, ) -> Weight { - // Minimum execution time: 92_462 nanoseconds. - Weight::from_ref_time(93_684_047) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(51_643).saturating_mul(l.into())) - .saturating_add(RocksDbWeight::get().reads(9)) - .saturating_add(RocksDbWeight::get().writes(8)) - } - // Storage: System Account (r:1 w:1) - // Storage: Staking Bonded (r:1 w:1) - // Storage: Staking Ledger (r:1 w:1) - // Storage: Staking SlashingSpans (r:1 w:1) - // Storage: Staking Validators (r:1 w:0) - // Storage: Staking Nominators (r:1 w:1) - // Storage: Staking CounterForNominators (r:1 w:1) - // Storage: VoterList ListNodes (r:2 w:2) - // Storage: VoterList ListBags (r:1 w:1) - // Storage: VoterList CounterForListNodes (r:1 w:1) - // Storage: Balances Locks (r:1 w:1) - // Storage: Staking Payee (r:0 w:1) - // Storage: Staking SpanSlash (r:0 w:1) + // Proof Size summary in bytes: + // Measured: `2215 + l * (7 ±0)` + // Estimated: `25491` + // Minimum execution time: 86_750 nanoseconds. + Weight::from_ref_time(90_496_328) + .saturating_add(Weight::from_proof_size(25491)) + // Standard Error: 5_292 + .saturating_add(Weight::from_ref_time(58_052).saturating_mul(l.into())) + .saturating_add(RocksDbWeight::get().reads(9_u64)) + .saturating_add(RocksDbWeight::get().writes(8_u64)) + } + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Staking Bonded (r:1 w:1) + /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) + /// Storage: Staking Ledger (r:1 w:1) + /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) + /// Storage: Staking SlashingSpans (r:1 w:1) + /// Proof Skipped: Staking SlashingSpans (max_values: None, max_size: None, mode: Measured) + /// Storage: Staking Validators (r:1 w:0) + /// Proof: Staking Validators (max_values: None, max_size: Some(45), added: 2520, mode: MaxEncodedLen) + /// Storage: Staking Nominators (r:1 w:1) + /// Proof: Staking Nominators (max_values: None, max_size: Some(558), added: 3033, mode: MaxEncodedLen) + /// Storage: Staking CounterForNominators (r:1 w:1) + /// Proof: Staking CounterForNominators (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: VoterList ListNodes (r:2 w:2) + /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) + /// Storage: VoterList ListBags (r:1 w:1) + /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) + /// Storage: VoterList CounterForListNodes (r:1 w:1) + /// Proof: VoterList CounterForListNodes (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Staking Payee (r:0 w:1) + /// Proof: Staking Payee (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) + /// Storage: Staking SpanSlash (r:0 w:100) + /// Proof: Staking SpanSlash (max_values: None, max_size: Some(76), added: 2551, mode: MaxEncodedLen) /// The range of component `s` is `[1, 100]`. fn reap_stash(s: u32, ) -> Weight { - // Minimum execution time: 92_003 nanoseconds. - Weight::from_ref_time(93_936_550) - // Standard Error: 2_091 - .saturating_add(Weight::from_ref_time(1_088_847).saturating_mul(s.into())) - .saturating_add(RocksDbWeight::get().reads(12)) - .saturating_add(RocksDbWeight::get().writes(12)) + // Proof Size summary in bytes: + // Measured: `2388 + s * (4 ±0)` + // Estimated: `31712 + s * (4 ±0)` + // Minimum execution time: 89_155 nanoseconds. + Weight::from_ref_time(94_547_569) + .saturating_add(Weight::from_proof_size(31712)) + // Standard Error: 4_227 + .saturating_add(Weight::from_ref_time(1_330_189).saturating_mul(s.into())) + .saturating_add(RocksDbWeight::get().reads(12_u64)) + .saturating_add(RocksDbWeight::get().writes(12_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(s.into()))) + .saturating_add(Weight::from_proof_size(4).saturating_mul(s.into())) } - // Storage: VoterList CounterForListNodes (r:1 w:0) - // Storage: VoterList ListBags (r:200 w:0) - // Storage: VoterList ListNodes (r:101 w:0) - // Storage: Staking Nominators (r:101 w:0) - // Storage: Staking Validators (r:2 w:0) - // Storage: Staking Bonded (r:101 w:0) - // Storage: Staking Ledger (r:101 w:0) - // Storage: Staking CounterForValidators (r:1 w:0) - // Storage: Staking ValidatorCount (r:1 w:0) - // Storage: Staking MinimumValidatorCount (r:1 w:0) - // Storage: Staking CurrentEra (r:1 w:1) - // Storage: Staking ErasValidatorPrefs (r:0 w:1) - // Storage: Staking ErasStakersPaged (r:0 w:1) - // Storage: Staking ErasStakersOverview (r:0 w:1) - // Storage: Staking ErasStakers (r:0 w:1) - // Storage: Staking ErasTotalStake (r:0 w:1) - // Storage: Staking ErasStartSessionIndex (r:0 w:1) - // Storage: Staking MinimumActiveStake (r:0 w:1) + /// Storage: VoterList CounterForListNodes (r:1 w:0) + /// Proof: VoterList CounterForListNodes (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: VoterList ListBags (r:200 w:0) + /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) + /// Storage: VoterList ListNodes (r:110 w:0) + /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) + /// Storage: Staking Nominators (r:110 w:0) + /// Proof: Staking Nominators (max_values: None, max_size: Some(558), added: 3033, mode: MaxEncodedLen) + /// Storage: Staking Validators (r:11 w:0) + /// Proof: Staking Validators (max_values: None, max_size: Some(45), added: 2520, mode: MaxEncodedLen) + /// Storage: Staking Bonded (r:110 w:0) + /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) + /// Storage: Staking Ledger (r:110 w:0) + /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) + /// Storage: Staking CounterForValidators (r:1 w:0) + /// Proof: Staking CounterForValidators (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking ValidatorCount (r:1 w:0) + /// Proof: Staking ValidatorCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking MinimumValidatorCount (r:1 w:0) + /// Proof: Staking MinimumValidatorCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking CurrentEra (r:1 w:1) + /// Proof: Staking CurrentEra (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking ErasValidatorPrefs (r:0 w:10) + /// Proof: Staking ErasValidatorPrefs (max_values: None, max_size: Some(57), added: 2532, mode: MaxEncodedLen) + /// Storage: Staking ErasStakersPaged (r:0 w:10) + /// Proof Skipped: Staking ErasStakersPaged (max_values: None, max_size: None, mode: Measured) + /// Storage: Staking ErasStakersOverview (r:0 w:10) + /// Proof: Staking ErasStakersOverview (max_values: None, max_size: Some(92), added: 2567, mode: MaxEncodedLen) + /// Storage: Staking ErasTotalStake (r:0 w:1) + /// Proof: Staking ErasTotalStake (max_values: None, max_size: Some(28), added: 2503, mode: MaxEncodedLen) + /// Storage: Staking ErasStartSessionIndex (r:0 w:1) + /// Proof: Staking ErasStartSessionIndex (max_values: None, max_size: Some(16), added: 2491, mode: MaxEncodedLen) + /// Storage: Staking MinimumActiveStake (r:0 w:1) + /// Proof: Staking MinimumActiveStake (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) /// The range of component `v` is `[1, 10]`. /// The range of component `n` is `[0, 100]`. fn new_era(v: u32, n: u32, ) -> Weight { - // Minimum execution time: 504_224 nanoseconds. - Weight::from_ref_time(506_290_000) - // Standard Error: 1_802_746 - .saturating_add(Weight::from_ref_time(60_725_475).saturating_mul(v.into())) - // Standard Error: 179_633 - .saturating_add(Weight::from_ref_time(13_820_500).saturating_mul(n.into())) - .saturating_add(RocksDbWeight::get().reads(206)) + // Proof Size summary in bytes: + // Measured: `0 + v * (3662 ±0) + n * (816 ±0)` + // Estimated: `523708 + v * (15469 ±41) + n * (12348 ±4)` + // Minimum execution time: 577_839 nanoseconds. + Weight::from_ref_time(587_063_000) + .saturating_add(Weight::from_proof_size(523708)) + // Standard Error: 2_193_535 + .saturating_add(Weight::from_ref_time(72_675_973).saturating_mul(v.into())) + // Standard Error: 218_573 + .saturating_add(Weight::from_ref_time(19_272_321).saturating_mul(n.into())) + .saturating_add(RocksDbWeight::get().reads(206_u64)) .saturating_add(RocksDbWeight::get().reads((5_u64).saturating_mul(v.into()))) .saturating_add(RocksDbWeight::get().reads((4_u64).saturating_mul(n.into()))) - .saturating_add(RocksDbWeight::get().writes(3)) - .saturating_add(RocksDbWeight::get().writes((4_u64).saturating_mul(v.into()))) - } - // Storage: VoterList CounterForListNodes (r:1 w:0) - // Storage: VoterList ListBags (r:200 w:0) - // Storage: VoterList ListNodes (r:1500 w:0) - // Storage: Staking Nominators (r:1500 w:0) - // Storage: Staking Validators (r:500 w:0) - // Storage: Staking Bonded (r:1500 w:0) - // Storage: Staking Ledger (r:1500 w:0) - // Storage: Staking MinimumActiveStake (r:0 w:1) + .saturating_add(RocksDbWeight::get().writes(3_u64)) + .saturating_add(RocksDbWeight::get().writes((3_u64).saturating_mul(v.into()))) + .saturating_add(Weight::from_proof_size(15469).saturating_mul(v.into())) + .saturating_add(Weight::from_proof_size(12348).saturating_mul(n.into())) + } + /// Storage: VoterList CounterForListNodes (r:1 w:0) + /// Proof: VoterList CounterForListNodes (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: VoterList ListBags (r:200 w:0) + /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) + /// Storage: VoterList ListNodes (r:2000 w:0) + /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) + /// Storage: Staking Nominators (r:2000 w:0) + /// Proof: Staking Nominators (max_values: None, max_size: Some(558), added: 3033, mode: MaxEncodedLen) + /// Storage: Staking Validators (r:1000 w:0) + /// Proof: Staking Validators (max_values: None, max_size: Some(45), added: 2520, mode: MaxEncodedLen) + /// Storage: Staking Bonded (r:2000 w:0) + /// Proof: Staking Bonded (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) + /// Storage: Staking Ledger (r:2000 w:0) + /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) + /// Storage: Staking MinimumActiveStake (r:0 w:1) + /// Proof: Staking MinimumActiveStake (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) /// The range of component `v` is `[500, 1000]`. /// The range of component `n` is `[500, 1000]`. fn get_npos_voters(v: u32, n: u32, ) -> Weight { - // Minimum execution time: 24_224_895 nanoseconds. - Weight::from_ref_time(24_374_544_000) - // Standard Error: 319_103 - .saturating_add(Weight::from_ref_time(3_422_743).saturating_mul(v.into())) - // Standard Error: 319_103 - .saturating_add(Weight::from_ref_time(2_914_359).saturating_mul(n.into())) - .saturating_add(RocksDbWeight::get().reads(201)) + // Proof Size summary in bytes: + // Measured: `3125 + v * (459 ±0) + n * (1007 ±0)` + // Estimated: `511899 + v * (14295 ±0) + n * (11775 ±0)` + // Minimum execution time: 38_014_741 nanoseconds. + Weight::from_ref_time(39_016_264_000) + .saturating_add(Weight::from_proof_size(511899)) + // Standard Error: 409_554 + .saturating_add(Weight::from_ref_time(4_585_268).saturating_mul(v.into())) + // Standard Error: 409_554 + .saturating_add(Weight::from_ref_time(5_027_951).saturating_mul(n.into())) + .saturating_add(RocksDbWeight::get().reads(201_u64)) .saturating_add(RocksDbWeight::get().reads((5_u64).saturating_mul(v.into()))) .saturating_add(RocksDbWeight::get().reads((4_u64).saturating_mul(n.into()))) - .saturating_add(RocksDbWeight::get().writes(1)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + .saturating_add(Weight::from_proof_size(14295).saturating_mul(v.into())) + .saturating_add(Weight::from_proof_size(11775).saturating_mul(n.into())) } - // Storage: Staking CounterForValidators (r:1 w:0) - // Storage: Staking Validators (r:501 w:0) + /// Storage: Staking CounterForValidators (r:1 w:0) + /// Proof: Staking CounterForValidators (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking Validators (r:1001 w:0) + /// Proof: Staking Validators (max_values: None, max_size: Some(45), added: 2520, mode: MaxEncodedLen) /// The range of component `v` is `[500, 1000]`. fn get_npos_targets(v: u32, ) -> Weight { - // Minimum execution time: 4_765_318 nanoseconds. - Weight::from_ref_time(4_816_708_000) - // Standard Error: 54_677 - .saturating_add(Weight::from_ref_time(3_541_818).saturating_mul(v.into())) - .saturating_add(RocksDbWeight::get().reads(2)) + // Proof Size summary in bytes: + // Measured: `979 + v * (50 ±0)` + // Estimated: `3019 + v * (2520 ±0)` + // Minimum execution time: 4_283_114 nanoseconds. + Weight::from_ref_time(4_393_678_000) + .saturating_add(Weight::from_proof_size(3019)) + // Standard Error: 49_897 + .saturating_add(Weight::from_ref_time(3_190_372).saturating_mul(v.into())) + .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(v.into()))) + .saturating_add(Weight::from_proof_size(2520).saturating_mul(v.into())) } - // Storage: Staking MinCommission (r:0 w:1) - // 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) + /// Storage: Staking MinCommission (r:0 w:1) + /// Proof: Staking MinCommission (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking MinValidatorBond (r:0 w:1) + /// Proof: Staking MinValidatorBond (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) + /// Storage: Staking MaxValidatorsCount (r:0 w:1) + /// Proof: Staking MaxValidatorsCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking ChillThreshold (r:0 w:1) + /// Proof: Staking ChillThreshold (max_values: Some(1), max_size: Some(1), added: 496, mode: MaxEncodedLen) + /// Storage: Staking MaxNominatorsCount (r:0 w:1) + /// Proof: Staking MaxNominatorsCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking MinNominatorBond (r:0 w:1) + /// Proof: Staking MinNominatorBond (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) fn set_staking_configs_all_set() -> Weight { - // Minimum execution time: 10_480 nanoseconds. - Weight::from_ref_time(10_914_000) - .saturating_add(RocksDbWeight::get().writes(6)) - } - // Storage: Staking MinCommission (r:0 w:1) - // 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) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 7_398 nanoseconds. + Weight::from_ref_time(7_711_000) + .saturating_add(Weight::from_proof_size(0)) + .saturating_add(RocksDbWeight::get().writes(6_u64)) + } + /// Storage: Staking MinCommission (r:0 w:1) + /// Proof: Staking MinCommission (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking MinValidatorBond (r:0 w:1) + /// Proof: Staking MinValidatorBond (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) + /// Storage: Staking MaxValidatorsCount (r:0 w:1) + /// Proof: Staking MaxValidatorsCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking ChillThreshold (r:0 w:1) + /// Proof: Staking ChillThreshold (max_values: Some(1), max_size: Some(1), added: 496, mode: MaxEncodedLen) + /// Storage: Staking MaxNominatorsCount (r:0 w:1) + /// Proof: Staking MaxNominatorsCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking MinNominatorBond (r:0 w:1) + /// Proof: Staking MinNominatorBond (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) fn set_staking_configs_all_remove() -> Weight { - // Minimum execution time: 9_529 nanoseconds. - Weight::from_ref_time(10_159_000) - .saturating_add(RocksDbWeight::get().writes(6)) - } - // Storage: Staking Ledger (r:1 w:0) - // Storage: Staking Nominators (r:1 w:1) - // Storage: Staking ChillThreshold (r:1 w:0) - // Storage: Staking MaxNominatorsCount (r:1 w:0) - // Storage: Staking CounterForNominators (r:1 w:1) - // Storage: Staking MinNominatorBond (r:1 w:0) - // Storage: Staking Validators (r:1 w:0) - // Storage: VoterList ListNodes (r:2 w:2) - // Storage: VoterList ListBags (r:1 w:1) - // Storage: VoterList CounterForListNodes (r:1 w:1) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 6_598 nanoseconds. + Weight::from_ref_time(6_970_000) + .saturating_add(Weight::from_proof_size(0)) + .saturating_add(RocksDbWeight::get().writes(6_u64)) + } + /// Storage: Staking Ledger (r:1 w:0) + /// Proof: Staking Ledger (max_values: None, max_size: Some(1091), added: 3566, mode: MaxEncodedLen) + /// Storage: Staking Nominators (r:1 w:1) + /// Proof: Staking Nominators (max_values: None, max_size: Some(558), added: 3033, mode: MaxEncodedLen) + /// Storage: Staking ChillThreshold (r:1 w:0) + /// Proof: Staking ChillThreshold (max_values: Some(1), max_size: Some(1), added: 496, mode: MaxEncodedLen) + /// Storage: Staking MaxNominatorsCount (r:1 w:0) + /// Proof: Staking MaxNominatorsCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking CounterForNominators (r:1 w:1) + /// Proof: Staking CounterForNominators (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking MinNominatorBond (r:1 w:0) + /// Proof: Staking MinNominatorBond (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) + /// Storage: Staking Validators (r:1 w:0) + /// Proof: Staking Validators (max_values: None, max_size: Some(45), added: 2520, mode: MaxEncodedLen) + /// Storage: VoterList ListNodes (r:2 w:2) + /// Proof: VoterList ListNodes (max_values: None, max_size: Some(154), added: 2629, mode: MaxEncodedLen) + /// Storage: VoterList ListBags (r:1 w:1) + /// Proof: VoterList ListBags (max_values: None, max_size: Some(82), added: 2557, mode: MaxEncodedLen) + /// Storage: VoterList CounterForListNodes (r:1 w:1) + /// Proof: VoterList CounterForListNodes (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) fn chill_other() -> Weight { - // Minimum execution time: 81_347 nanoseconds. - Weight::from_ref_time(81_957_000) - .saturating_add(RocksDbWeight::get().reads(11)) - .saturating_add(RocksDbWeight::get().writes(6)) + // Proof Size summary in bytes: + // Measured: `1933` + // Estimated: `19438` + // Minimum execution time: 72_003 nanoseconds. + Weight::from_ref_time(73_575_000) + .saturating_add(Weight::from_proof_size(19438)) + .saturating_add(RocksDbWeight::get().reads(11_u64)) + .saturating_add(RocksDbWeight::get().writes(6_u64)) } - // Storage: Staking MinCommission (r:1 w:0) - // Storage: Staking Validators (r:1 w:1) + /// Storage: Staking MinCommission (r:1 w:0) + /// Proof: Staking MinCommission (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + /// Storage: Staking Validators (r:1 w:1) + /// Proof: Staking Validators (max_values: None, max_size: Some(45), added: 2520, mode: MaxEncodedLen) fn force_apply_min_commission() -> Weight { - // Minimum execution time: 19_153 nanoseconds. - Weight::from_ref_time(19_621_000) - .saturating_add(RocksDbWeight::get().reads(2)) - .saturating_add(RocksDbWeight::get().writes(1)) + // Proof Size summary in bytes: + // Measured: `691` + // Estimated: `3019` + // Minimum execution time: 13_540 nanoseconds. + Weight::from_ref_time(14_129_000) + .saturating_add(Weight::from_proof_size(3019)) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) } - // Storage: Staking MinCommission (r:0 w:1) + /// Storage: Staking MinCommission (r:0 w:1) + /// Proof: Staking MinCommission (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) fn set_min_commission() -> Weight { - // Minimum execution time: 6_058 nanoseconds. - Weight::from_ref_time(6_278_000) - .saturating_add(RocksDbWeight::get().writes(1)) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 3_511 nanoseconds. + Weight::from_ref_time(3_633_000) + .saturating_add(Weight::from_proof_size(0)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) } } From 21c20f27f0e39e8d7cbc1c5b71c188f00bc8a9d1 Mon Sep 17 00:00:00 2001 From: Ankan Date: Wed, 22 Feb 2023 18:58:57 +0100 Subject: [PATCH 161/162] rename to consistent names --- bin/node/runtime/src/lib.rs | 2 +- frame/fast-unstake/src/benchmarking.rs | 2 +- frame/fast-unstake/src/lib.rs | 2 +- frame/fast-unstake/src/mock.rs | 2 +- frame/staking/CHANGELOG.md | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 4d65213e5602c..f84f5d32c9ffa 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -597,7 +597,7 @@ impl pallet_fast_unstake::Config for Runtime { type Staking = Staking; type MaxErasToCheckPerBlock = ConstU32<1>; #[cfg(feature = "runtime-benchmarks")] - type MaxBackersPerValidator = MaxExposurePageSize; + type MaxExposurePageSize = MaxExposurePageSize; type WeightInfo = (); } diff --git a/frame/fast-unstake/src/benchmarking.rs b/frame/fast-unstake/src/benchmarking.rs index 5ec997e8eaa2a..5d31c1f9ded41 100644 --- a/frame/fast-unstake/src/benchmarking.rs +++ b/frame/fast-unstake/src/benchmarking.rs @@ -74,7 +74,7 @@ fn setup_staking(v: u32, until: EraIndex) { .collect::>(); for era in 0..=until { - let others = (0..T::MaxBackersPerValidator::get()) + let others = (0..T::MaxExposurePageSize::get()) .map(|s| { let who = frame_benchmarking::account::("nominator", era, s); let value = ed; diff --git a/frame/fast-unstake/src/lib.rs b/frame/fast-unstake/src/lib.rs index 81eb3087b998e..8b05e9b553b0a 100644 --- a/frame/fast-unstake/src/lib.rs +++ b/frame/fast-unstake/src/lib.rs @@ -142,7 +142,7 @@ pub mod pallet { /// Use only for benchmarking. #[cfg(feature = "runtime-benchmarks")] - type MaxBackersPerValidator: Get; + type MaxExposurePageSize: Get; } /// The current "head of the queue" being unstaked. diff --git a/frame/fast-unstake/src/mock.rs b/frame/fast-unstake/src/mock.rs index 56a23555e6fd0..49b29c448e27b 100644 --- a/frame/fast-unstake/src/mock.rs +++ b/frame/fast-unstake/src/mock.rs @@ -188,7 +188,7 @@ impl fast_unstake::Config for Runtime { type WeightInfo = (); type MaxErasToCheckPerBlock = ConstU32<16>; #[cfg(feature = "runtime-benchmarks")] - type MaxBackersPerValidator = ConstU32<128>; + type MaxExposurePageSize = ConstU32<128>; } type Block = frame_system::mocking::MockBlock; diff --git a/frame/staking/CHANGELOG.md b/frame/staking/CHANGELOG.md index 41b1e9ab7184c..411f63b397c7e 100644 --- a/frame/staking/CHANGELOG.md +++ b/frame/staking/CHANGELOG.md @@ -7,7 +7,7 @@ on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). We maintain a single integer version number for staking pallet to keep track of all storage migrations. -## [14] - UNRELEASED +## [14] ### Added From 2aa08d63239cfb0e2d5f95126b89cb2e2f5f9912 Mon Sep 17 00:00:00 2001 From: Ankan Date: Mon, 27 Feb 2023 00:26:30 +0100 Subject: [PATCH 162/162] some docs --- frame/staking/src/pallet/mod.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index d79181236b3d0..56447b8e510a1 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -440,6 +440,7 @@ pub mod pallet { /// pages of rewards that needs to be claimed. /// /// This is keyed first by the era index to allow bulk deletion and then the stash account. + /// Should only be accessed through `EraInfo`. /// /// Is it removed after [`Config::HistoryDepth`] eras. /// If stakers hasn't been set or has been removed then empty overview is returned. @@ -486,7 +487,7 @@ pub mod pallet { /// Paginated exposure of a validator at given era. /// /// This is keyed first by the era index to allow bulk deletion, then stash account and finally - /// the page. + /// the page. Should only be accessed through `EraInfo`. /// /// This is cleared after [`Config::HistoryDepth`] eras. #[pallet::storage] @@ -697,6 +698,8 @@ pub mod pallet { // validator stake is added only in page zero let validator_stake = if page == 0 { overview.own } else { Zero::zero() }; + // since overview is present, paged exposure will always be present except when a + // validator has only own stake and no nominator stake. let exposure_page = >::get((era, validator, page)).unwrap_or_default();