From 6c808b664d53876ebca9bcbd1ff0c666915119d5 Mon Sep 17 00:00:00 2001 From: giuseppere Date: Mon, 11 Nov 2024 16:05:15 +0100 Subject: [PATCH 001/101] add MaxInvulnerables --- substrate/frame/staking/src/pallet/mod.rs | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs index 5210bef853b2..c7692ce679fc 100644 --- a/substrate/frame/staking/src/pallet/mod.rs +++ b/substrate/frame/staking/src/pallet/mod.rs @@ -296,6 +296,10 @@ pub mod pallet { #[pallet::no_default_bounds] type DisablingStrategy: DisablingStrategy; + /// Maximum number of invulnerable validators. + #[pallet::constant] + type MaxInvulnerables: Get; + /// Some parameters of the benchmarking. #[cfg(feature = "std")] type BenchmarkingConfig: BenchmarkingConfig; @@ -343,6 +347,7 @@ pub mod pallet { type MaxControllersInDeprecationBatch = ConstU32<100>; type EventListeners = (); type DisablingStrategy = crate::UpToLimitDisablingStrategy; + type MaxInvulnerables = ConstU32<4>; #[cfg(feature = "std")] type BenchmarkingConfig = crate::TestBenchmarkingConfig; type WeightInfo = (); @@ -365,7 +370,8 @@ pub mod pallet { #[pallet::storage] #[pallet::getter(fn invulnerables)] #[pallet::unbounded] - pub type Invulnerables = StorageValue<_, Vec, ValueQuery>; + pub type Invulnerables = + StorageValue<_, BoundedVec, ValueQuery>; /// Map from all locked "stash" accounts to the controller account. /// @@ -757,7 +763,11 @@ pub mod pallet { fn build(&self) { ValidatorCount::::put(self.validator_count); MinimumValidatorCount::::put(self.minimum_validator_count); - Invulnerables::::put(&self.invulnerables); + assert!( + self.invulnerables.len() as u32 <= T::MaxInvulnerables::get(), + "Too many invulnerable validators at genesis." + ); + >::put(BoundedVec::truncate_from(self.invulnerables.clone())); ForceEra::::put(self.force_era); CanceledSlashPayout::::put(self.canceled_payout); SlashRewardFraction::::put(self.slash_reward_fraction); @@ -1541,7 +1551,11 @@ pub mod pallet { invulnerables: Vec, ) -> DispatchResult { ensure_root(origin)?; - >::put(invulnerables); + ensure!( + invulnerables.len() as u32 <= T::MaxInvulnerables::get(), + Error::::BoundNotMet + ); + >::put(BoundedVec::truncate_from(invulnerables)); Ok(()) } From 1b18bb12a00e9ab9f79d11b0f8a6034b5170fec5 Mon Sep 17 00:00:00 2001 From: giuseppere Date: Wed, 13 Nov 2024 14:51:15 +0100 Subject: [PATCH 002/101] add `MaxActiveValidators` --- polkadot/runtime/westend/src/lib.rs | 2 + substrate/frame/staking/src/benchmarking.rs | 17 +++++-- substrate/frame/staking/src/lib.rs | 15 ++++--- substrate/frame/staking/src/migrations.rs | 6 +++ substrate/frame/staking/src/pallet/impls.rs | 18 +++++++- substrate/frame/staking/src/pallet/mod.rs | 23 +++++++--- substrate/frame/staking/src/slashing.rs | 2 +- substrate/frame/staking/src/tests.rs | 49 ++++++++++++--------- 8 files changed, 91 insertions(+), 41 deletions(-) diff --git a/polkadot/runtime/westend/src/lib.rs b/polkadot/runtime/westend/src/lib.rs index 4c04af111f81..f628e50f6870 100644 --- a/polkadot/runtime/westend/src/lib.rs +++ b/polkadot/runtime/westend/src/lib.rs @@ -756,6 +756,8 @@ impl pallet_staking::Config for Runtime { type EventListeners = (NominationPools, DelegatedStaking); type WeightInfo = weights::pallet_staking::WeightInfo; type DisablingStrategy = pallet_staking::UpToLimitDisablingStrategy; + type MaxInvulnerables = frame_support::traits::ConstU32<4>; + type MaxActiveValidators = MaxActiveValidators; } impl pallet_fast_unstake::Config for Runtime { diff --git a/substrate/frame/staking/src/benchmarking.rs b/substrate/frame/staking/src/benchmarking.rs index 96bd3860542f..6be34ba8a408 100644 --- a/substrate/frame/staking/src/benchmarking.rs +++ b/substrate/frame/staking/src/benchmarking.rs @@ -24,6 +24,7 @@ use testing_utils::*; use codec::Decode; use frame_election_provider_support::{bounds::DataProviderBounds, SortedListProvider}; use frame_support::{ + assert_ok, pallet_prelude::*, storage::bounded_vec::BoundedVec, traits::{Get, Imbalance, UnfilteredDispatchable}, @@ -122,10 +123,14 @@ pub fn create_validator_with_nominators( assert_ne!(Validators::::count(), 0); assert_eq!(Nominators::::count(), original_nominator_count + nominators.len() as u32); + let mut reward_map = BoundedBTreeMap::new(); + for (validator, reward) in points_individual { + assert_ok!(reward_map.try_insert(validator, reward)); + } // Give Era Points - let reward = EraRewardPoints:: { + let reward = EraRewardPoints:: { total: points_total, - individual: points_individual.into_iter().collect(), + individual: reward_map, }; let current_era = CurrentEra::::get().unwrap(); @@ -865,10 +870,14 @@ mod benchmarks { payout_calls_arg.push((validator.clone(), current_era)); } + let mut reward_map = BoundedBTreeMap::new(); + for (validator, reward) in points_individual { + assert_ok!(reward_map.try_insert(validator, reward)); + } // Give Era Points - let reward = EraRewardPoints:: { + let reward = EraRewardPoints:: { total: points_total, - individual: points_individual.into_iter().collect(), + individual: reward_map, }; ErasRewardPoints::::insert(current_era, reward); diff --git a/substrate/frame/staking/src/lib.rs b/substrate/frame/staking/src/lib.rs index 19d999109d8d..cc8f303e9542 100644 --- a/substrate/frame/staking/src/lib.rs +++ b/substrate/frame/staking/src/lib.rs @@ -321,7 +321,7 @@ use scale_info::TypeInfo; use sp_runtime::{ curve::PiecewiseLinear, traits::{AtLeast32BitUnsigned, Convert, StaticLookup, Zero}, - Perbill, Perquintill, Rounding, RuntimeDebug, Saturating, + BoundedBTreeMap, Perbill, Perquintill, Rounding, RuntimeDebug, Saturating, }; use sp_staking::{ offence::{Offence, OffenceError, ReportOffence}, @@ -385,17 +385,20 @@ pub struct ActiveEraInfo { /// Reward points of an era. Used to split era total payout between validators. /// /// This points will be used to reward validators and their respective nominators. -#[derive(PartialEq, Encode, Decode, RuntimeDebug, TypeInfo)] -pub struct EraRewardPoints { +#[derive(PartialEq, Encode, Decode, RuntimeDebug, TypeInfo, MaxEncodedLen)] +#[scale_info(skip_type_params(MaxActiveValidators))] +pub struct EraRewardPoints> { /// Total number of points. Equals the sum of reward points for each validator. pub total: RewardPoint, /// The reward points earned by a given validator. - pub individual: BTreeMap, + pub individual: BoundedBTreeMap, } -impl Default for EraRewardPoints { +impl> Default + for EraRewardPoints +{ fn default() -> Self { - EraRewardPoints { total: Default::default(), individual: BTreeMap::new() } + EraRewardPoints { total: Default::default(), individual: BoundedBTreeMap::new() } } } diff --git a/substrate/frame/staking/src/migrations.rs b/substrate/frame/staking/src/migrations.rs index 5c9cf8613213..4fff319d2050 100644 --- a/substrate/frame/staking/src/migrations.rs +++ b/substrate/frame/staking/src/migrations.rs @@ -60,6 +60,12 @@ impl Default for ObsoleteReleases { #[storage_alias] type StorageVersion = StorageValue, ObsoleteReleases, ValueQuery>; +/// Migrating all unbounded storage items to bounded +pub mod v16 { + use super::*; + // TODO +} + /// Migrating `OffendingValidators` from `Vec<(u32, bool)>` to `Vec` pub mod v15 { use super::*; diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs index d3423d82769d..0ada5564e4e6 100644 --- a/substrate/frame/staking/src/pallet/impls.rs +++ b/substrate/frame/staking/src/pallet/impls.rs @@ -857,8 +857,22 @@ impl Pallet { if let Some(active_era) = Self::active_era() { >::mutate(active_era.index, |era_rewards| { for (validator, points) in validators_points.into_iter() { - *era_rewards.individual.entry(validator).or_default() += points; - era_rewards.total += points; + match era_rewards.individual.get_mut(&validator) { + Some(value) => *value += points, + None => { + if let Ok(_) = + era_rewards.individual.try_insert(validator.clone(), points) + { + era_rewards.total += points; + } else { + log!( + warn, + "Could not add reward points to {}: max numbers of rewarded validators reached", + validator + ); + } + }, + }; } }); } diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs index c7692ce679fc..946a9366902e 100644 --- a/substrate/frame/staking/src/pallet/mod.rs +++ b/substrate/frame/staking/src/pallet/mod.rs @@ -300,6 +300,10 @@ pub mod pallet { #[pallet::constant] type MaxInvulnerables: Get; + /// Maximum number of active validators in an era. + #[pallet::constant] + type MaxActiveValidators: Get; + /// Some parameters of the benchmarking. #[cfg(feature = "std")] type BenchmarkingConfig: BenchmarkingConfig; @@ -348,6 +352,7 @@ pub mod pallet { type EventListeners = (); type DisablingStrategy = crate::UpToLimitDisablingStrategy; type MaxInvulnerables = ConstU32<4>; + type MaxActiveValidators = ConstU32<100>; #[cfg(feature = "std")] type BenchmarkingConfig = crate::TestBenchmarkingConfig; type WeightInfo = (); @@ -626,10 +631,14 @@ pub mod pallet { /// 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] #[pallet::getter(fn eras_reward_points)] - pub type ErasRewardPoints = - StorageMap<_, Twox64Concat, EraIndex, EraRewardPoints, ValueQuery>; + pub type ErasRewardPoints = StorageMap< + _, + Twox64Concat, + EraIndex, + EraRewardPoints, + ValueQuery, + >; /// The total amount staked for the last [`Config::HistoryDepth`] eras. /// If total hasn't been set or has been removed then 0 stake is returned. @@ -729,11 +738,11 @@ pub mod pallet { /// implementor of [`DisablingStrategy`] defines if a validator should be disabled which /// implicitly means that the implementor also controls the max number of disabled validators. /// - /// The vec is always kept sorted so that we can find whether a given validator has previously - /// offended using binary search. + /// The bounded vec is always kept sorted so that we can find whether a given validator has + /// previously offended using binary search. #[pallet::storage] - #[pallet::unbounded] - pub type DisabledValidators = StorageValue<_, Vec, ValueQuery>; + pub type DisabledValidators = + StorageValue<_, BoundedVec, ValueQuery>; /// The threshold for when users can start calling `chill_other` for other validators / /// nominators. The threshold is compared to the actual number of validators / nominators diff --git a/substrate/frame/staking/src/slashing.rs b/substrate/frame/staking/src/slashing.rs index 9fb782265b8b..eb2c02184e96 100644 --- a/substrate/frame/staking/src/slashing.rs +++ b/substrate/frame/staking/src/slashing.rs @@ -330,7 +330,7 @@ fn add_offending_validator(params: &SlashParams) { // Add the validator to `DisabledValidators` and disable it. Do nothing if it is // already disabled. if let Err(index) = disabled.binary_search_by_key(&offender, |index| *index) { - disabled.insert(index, offender); + disabled.try_insert(index, offender); T::SessionInterface::disable_validator(offender); } } diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index d1dc6c3db659..a7a9b29e20c6 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -335,13 +335,14 @@ fn rewards_should_work() { assert_eq!(asset::total_balance::(&11), init_balance_11); assert_eq!(asset::total_balance::(&21), init_balance_21); assert_eq!(asset::total_balance::(&101), init_balance_101); - assert_eq!( - Staking::eras_reward_points(active_era()), - EraRewardPoints { - total: 50 * 3, - individual: vec![(11, 100), (21, 50)].into_iter().collect(), - } - ); + + let eras_reward_points = Staking::eras_reward_points(active_era()); + + assert_eq!(eras_reward_points.total, 50 * 3); + assert_eq!(eras_reward_points.individual.get(&11), Some(&100)); + assert_eq!(eras_reward_points.individual.get(&21), Some(&50)); + assert_eq!(eras_reward_points.individual.keys().cloned().collect::>(), [11, 21]); + let part_for_11 = Perbill::from_rational::(1000, 1125); let part_for_21 = Perbill::from_rational::(1000, 1375); let part_for_101_from_11 = Perbill::from_rational::(125, 1125); @@ -2328,9 +2329,11 @@ fn reward_validator_slashing_validator_does_not_overflow() { let _ = asset::set_stakeable_balance::(&11, stake); let exposure = Exposure:: { total: stake, own: stake, others: vec![] }; - let reward = EraRewardPoints:: { + let mut reward_map = BoundedBTreeMap::new(); + assert_ok!(reward_map.try_insert(11, 1)); + let reward = EraRewardPoints::::MaxActiveValidators> { total: 1, - individual: vec![(11, 1)].into_iter().collect(), + individual: reward_map, }; // Check reward @@ -2386,10 +2389,11 @@ fn reward_from_authorship_event_handler_works() { // 21 is rewarded as an uncle producer // 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)].into_iter().collect(), total: 40 }, - ); + + let eras_reward_points = ErasRewardPoints::::get(active_era()); + assert_eq!(eras_reward_points.total, 40); + assert_eq!(eras_reward_points.individual.get(&11), Some(&(20 * 2))); + assert_eq!(eras_reward_points.individual.keys().cloned().collect::>(), [11]); }) } @@ -2403,10 +2407,11 @@ fn add_reward_points_fns_works() { Pallet::::reward_by_ids(vec![(21, 1), (11, 1), (11, 1)]); - assert_eq!( - ErasRewardPoints::::get(active_era()), - EraRewardPoints { individual: vec![(11, 4), (21, 2)].into_iter().collect(), total: 6 }, - ); + let eras_reward_points = ErasRewardPoints::::get(active_era()); + assert_eq!(eras_reward_points.total, 40); + assert_eq!(eras_reward_points.individual.get(&11), Some(&4)); + assert_eq!(eras_reward_points.individual.get(&21), Some(&2)); + assert_eq!(eras_reward_points.individual.keys().cloned().collect::>(), [11, 21]); }) } @@ -6880,12 +6885,14 @@ fn test_runtime_api_pending_rewards() { assert_ok!(Staking::bond(RuntimeOrigin::signed(v), stake, RewardDestination::Staked)); } + let mut reward_map = BoundedBTreeMap::new(); + assert_ok!(reward_map.try_insert(validator_one, 1)); + assert_ok!(reward_map.try_insert(validator_two, 1)); + assert_ok!(reward_map.try_insert(validator_three, 1)); // Add reward points - let reward = EraRewardPoints:: { + let reward = EraRewardPoints::::MaxActiveValidators> { total: 1, - individual: vec![(validator_one, 1), (validator_two, 1), (validator_three, 1)] - .into_iter() - .collect(), + individual: reward_map, }; ErasRewardPoints::::insert(0, reward); From 4edb8e164c29c8c19ca68742368da63a1c60d04a Mon Sep 17 00:00:00 2001 From: giuseppere Date: Wed, 13 Nov 2024 16:49:10 +0100 Subject: [PATCH 003/101] fix + start working on migrations --- substrate/frame/staking/src/migrations.rs | 42 ++++++++++++++++++++++- substrate/frame/staking/src/pallet/mod.rs | 6 ++-- 2 files changed, 43 insertions(+), 5 deletions(-) diff --git a/substrate/frame/staking/src/migrations.rs b/substrate/frame/staking/src/migrations.rs index 4fff319d2050..4194d4ae777e 100644 --- a/substrate/frame/staking/src/migrations.rs +++ b/substrate/frame/staking/src/migrations.rs @@ -63,7 +63,47 @@ type StorageVersion = StorageValue, ObsoleteReleases, Value /// Migrating all unbounded storage items to bounded pub mod v16 { use super::*; - // TODO + + pub struct VersionUncheckedMigrateV15ToV16(core::marker::PhantomData); + impl UncheckedOnRuntimeUpgrade for VersionUncheckedMigrateV15ToV16 { + fn on_runtime_upgrade() -> Weight { + // BoundedVec with MaxActiveValidators limit, this should always work + let disabled_validators = BoundedVec::try_from(DisabledValidators::::get()); + if disabled_validators.is_ok() { + DisabledValidators::::set(disabled_validators.unwrap()); + } else { + log!(warn, "Could not insert disabled validators in bounded vector."); + } + + // BoundedVec with MaxActiveValidators limit, this should always work + let invulnerables = BoundedVec::try_from(Invulnerables::::get()); + if invulnerables.is_ok() { + Invulnerables::::set(invulnerables.unwrap()); + } else { + log!(warn, "Could not insert invulnerables in bounded vector."); + } + + let eras_rewards = ErasRewardPoints::::get(); + for + + log!(info, "v15 applied successfully."); + T::DbWeight::get().reads_writes(1, 1) + } + + // TODO + #[cfg(feature = "try-runtime")] + fn post_upgrade(_state: Vec) -> Result<(), TryRuntimeError> { + Ok(()) + } + } + + pub type MigrateV15ToV16 = VersionedMigration< + 15, + 16, + VersionUncheckedMigrateV15ToV16, + Pallet, + ::DbWeight, + >; } /// Migrating `OffendingValidators` from `Vec<(u32, bool)>` to `Vec` diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs index d237a0d51815..50bc22e8ed0d 100644 --- a/substrate/frame/staking/src/pallet/mod.rs +++ b/substrate/frame/staking/src/pallet/mod.rs @@ -371,7 +371,6 @@ pub mod pallet { /// easy to initialize and the performance hit is minimal (we expect no more than four /// invulnerables) and restricted to testnets. #[pallet::storage] - #[pallet::unbounded] pub type Invulnerables = StorageValue<_, BoundedVec, ValueQuery>; @@ -619,7 +618,6 @@ pub mod pallet { /// 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::getter(fn eras_reward_points)] pub type ErasRewardPoints = StorageMap< _, Twox64Concat, @@ -1004,7 +1002,7 @@ pub mod pallet { } /// Get the validators that may never be slashed or forcibly kicked out. - pub fn invulnerables() -> Vec { + pub fn invulnerables() -> BoundedVec { Invulnerables::::get() } @@ -1096,7 +1094,7 @@ pub mod pallet { /// Get the rewards for the last [`Config::HistoryDepth`] eras. pub fn eras_reward_points( era_index: EncodeLikeEraIndex, - ) -> EraRewardPoints + ) -> EraRewardPoints where EncodeLikeEraIndex: codec::EncodeLike, { From 65c7de61823e37fc587b761a1a447253075825c2 Mon Sep 17 00:00:00 2001 From: giuseppere Date: Wed, 13 Nov 2024 17:47:33 +0100 Subject: [PATCH 004/101] nit (typo) --- substrate/frame/staking/src/migrations.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/substrate/frame/staking/src/migrations.rs b/substrate/frame/staking/src/migrations.rs index 4194d4ae777e..559f99e327da 100644 --- a/substrate/frame/staking/src/migrations.rs +++ b/substrate/frame/staking/src/migrations.rs @@ -83,9 +83,6 @@ pub mod v16 { log!(warn, "Could not insert invulnerables in bounded vector."); } - let eras_rewards = ErasRewardPoints::::get(); - for - log!(info, "v15 applied successfully."); T::DbWeight::get().reads_writes(1, 1) } From 35069c97c7be2dc7ff1407f0fe77ed094b14eaa3 Mon Sep 17 00:00:00 2001 From: giuseppere Date: Thu, 14 Nov 2024 17:46:57 +0100 Subject: [PATCH 005/101] fix migrations for `BoundedVec` --- substrate/frame/staking/src/migrations.rs | 26 ++++++++++++++--------- substrate/frame/staking/src/mock.rs | 2 ++ 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/substrate/frame/staking/src/migrations.rs b/substrate/frame/staking/src/migrations.rs index 559f99e327da..e45a8794bdd3 100644 --- a/substrate/frame/staking/src/migrations.rs +++ b/substrate/frame/staking/src/migrations.rs @@ -68,19 +68,18 @@ pub mod v16 { impl UncheckedOnRuntimeUpgrade for VersionUncheckedMigrateV15ToV16 { fn on_runtime_upgrade() -> Weight { // BoundedVec with MaxActiveValidators limit, this should always work - let disabled_validators = BoundedVec::try_from(DisabledValidators::::get()); - if disabled_validators.is_ok() { - DisabledValidators::::set(disabled_validators.unwrap()); - } else { - log!(warn, "Could not insert disabled validators in bounded vector."); + let disabled_validators_maybe = + BoundedVec::try_from(v15::DisabledValidators::::get()); + match disabled_validators_maybe { + Ok(disabled_validators) => DisabledValidators::::set(disabled_validators), + Err(_) => log!(warn, "Could not insert disabled validators in bounded vector."), } // BoundedVec with MaxActiveValidators limit, this should always work - let invulnerables = BoundedVec::try_from(Invulnerables::::get()); - if invulnerables.is_ok() { - Invulnerables::::set(invulnerables.unwrap()); - } else { - log!(warn, "Could not insert invulnerables in bounded vector."); + let invulnerables_maybe = BoundedVec::try_from(v15::Invulnerables::::get()); + match invulnerables_maybe { + Ok(invulnerables) => Invulnerables::::set(invulnerables), + Err(_) => log!(warn, "Could not insert invulnerables in bounded vector."), } log!(info, "v15 applied successfully."); @@ -107,6 +106,13 @@ pub mod v16 { pub mod v15 { use super::*; + #[frame_support::storage_alias] + pub(crate) type DisabledValidators = StorageValue, Vec, ValueQuery>; + + #[frame_support::storage_alias] + pub(crate) type Invulnerables = + StorageValue, Vec<::AccountId>, ValueQuery>; + // The disabling strategy used by staking pallet type DefaultDisablingStrategy = UpToLimitDisablingStrategy; diff --git a/substrate/frame/staking/src/mock.rs b/substrate/frame/staking/src/mock.rs index 2d3446d2dabc..316c4a1b4d89 100644 --- a/substrate/frame/staking/src/mock.rs +++ b/substrate/frame/staking/src/mock.rs @@ -285,6 +285,8 @@ impl crate::pallet::pallet::Config for Test { type MaxControllersInDeprecationBatch = MaxControllersInDeprecationBatch; type EventListeners = EventListenerMock; type DisablingStrategy = pallet_staking::UpToLimitDisablingStrategy; + type MaxInvulnerables = ConstU32<4>; + type MaxActiveValidators = ConstU32<100>; } pub struct WeightedNominationsQuota; From eb93a7024eb2bab8e5fb3a21847f7ab6de4c6f54 Mon Sep 17 00:00:00 2001 From: giuseppere Date: Thu, 14 Nov 2024 18:28:14 +0100 Subject: [PATCH 006/101] Migrate `ErasRewardPoints` --- substrate/frame/staking/src/migrations.rs | 45 +++++++++++++++++++++-- substrate/frame/staking/src/tests.rs | 5 ++- 2 files changed, 45 insertions(+), 5 deletions(-) diff --git a/substrate/frame/staking/src/migrations.rs b/substrate/frame/staking/src/migrations.rs index e45a8794bdd3..de395c9e2f26 100644 --- a/substrate/frame/staking/src/migrations.rs +++ b/substrate/frame/staking/src/migrations.rs @@ -72,17 +72,34 @@ pub mod v16 { BoundedVec::try_from(v15::DisabledValidators::::get()); match disabled_validators_maybe { Ok(disabled_validators) => DisabledValidators::::set(disabled_validators), - Err(_) => log!(warn, "Could not insert disabled validators in bounded vector."), + Err(_) => log!(warn, "Migration failed for DisabledValidators from v15 to v16."), } // BoundedVec with MaxActiveValidators limit, this should always work let invulnerables_maybe = BoundedVec::try_from(v15::Invulnerables::::get()); match invulnerables_maybe { Ok(invulnerables) => Invulnerables::::set(invulnerables), - Err(_) => log!(warn, "Could not insert invulnerables in bounded vector."), + Err(_) => log!(warn, "Migration failed for Invulnerables from v15 to v16."), } - log!(info, "v15 applied successfully."); + for (era_index, era_rewards) in v15::ErasRewardPoints::::iter() { + let individual_rewards_maybe = BoundedBTreeMap::try_from(era_rewards.individual); + match individual_rewards_maybe { + Ok(individual_rewards) => { + let bounded_era_rewards = EraRewardPoints::< + ::AccountId, + ::MaxActiveValidators, + > { + individual: individual_rewards, + total: era_rewards.total, + }; + ErasRewardPoints::::insert(era_index, bounded_era_rewards); + }, + Err(_) => log!(warn, "Migration failed for ErasRewardPoints from v15 to v16."), + } + } + + log!(info, "v16 applied successfully."); T::DbWeight::get().reads_writes(1, 1) } @@ -105,6 +122,7 @@ pub mod v16 { /// Migrating `OffendingValidators` from `Vec<(u32, bool)>` to `Vec` pub mod v15 { use super::*; + use frame_support::Twox64Concat; #[frame_support::storage_alias] pub(crate) type DisabledValidators = StorageValue, Vec, ValueQuery>; @@ -113,6 +131,27 @@ pub mod v15 { pub(crate) type Invulnerables = StorageValue, Vec<::AccountId>, ValueQuery>; + #[derive(PartialEq, Encode, Decode, RuntimeDebug, TypeInfo)] + pub struct EraRewardPoints { + pub total: u32, + pub individual: BTreeMap, + } + + impl Default for EraRewardPoints { + fn default() -> Self { + EraRewardPoints { total: Default::default(), individual: BTreeMap::new() } + } + } + + #[frame_support::storage_alias] + pub(crate) type ErasRewardPoints = StorageMap< + Pallet, + Twox64Concat, + u32, + EraRewardPoints<::AccountId>, + ValueQuery, + >; + // The disabling strategy used by staking pallet type DefaultDisablingStrategy = UpToLimitDisablingStrategy; diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index f267b28a829b..d158b4f18851 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -28,6 +28,7 @@ use frame_support::{ dispatch::{extract_actual_weight, GetDispatchInfo, WithPostDispatchInfo}, pallet_prelude::*, traits::{Currency, Get, ReservableCurrency}, + BoundedVec, }; use mock::*; @@ -335,7 +336,7 @@ fn rewards_should_work() { assert_eq!(asset::total_balance::(&11), init_balance_11); assert_eq!(asset::total_balance::(&21), init_balance_21); assert_eq!(asset::total_balance::(&101), init_balance_101); - + let eras_reward_points = Staking::eras_reward_points(active_era()); assert_eq!(eras_reward_points.total, 50 * 3); @@ -8395,7 +8396,7 @@ mod getters { sp_io::TestExternalities::default().execute_with(|| { // given let v: Vec = vec![1, 2, 3]; - Invulnerables::::put(v.clone()); + Invulnerables::::put(BoundedVec::try_from(v.clone()).unwrap()); // when let result = Staking::invulnerables(); From 58cf45da46a84d91e19cfc6bd65185fa754947c5 Mon Sep 17 00:00:00 2001 From: giuseppere Date: Fri, 15 Nov 2024 14:48:22 +0100 Subject: [PATCH 007/101] small fixes - `BoundedBTreeMap` --- substrate/frame/staking/src/slashing.rs | 2 +- substrate/frame/staking/src/tests.rs | 21 ++++++++++++--------- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/substrate/frame/staking/src/slashing.rs b/substrate/frame/staking/src/slashing.rs index eb2c02184e96..cf764d1cc10a 100644 --- a/substrate/frame/staking/src/slashing.rs +++ b/substrate/frame/staking/src/slashing.rs @@ -330,7 +330,7 @@ fn add_offending_validator(params: &SlashParams) { // Add the validator to `DisabledValidators` and disable it. Do nothing if it is // already disabled. if let Err(index) = disabled.binary_search_by_key(&offender, |index| *index) { - disabled.try_insert(index, offender); + debug_assert!(disabled.try_insert(index, offender).is_ok()); T::SessionInterface::disable_validator(offender); } } diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index d158b4f18851..42391859c52a 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -8353,11 +8353,11 @@ mod getters { pallet::pallet::{Invulnerables, MinimumValidatorCount, ValidatorCount}, slashing, tests::{Staking, Test}, - ActiveEra, ActiveEraInfo, BalanceOf, CanceledSlashPayout, ClaimedRewards, CurrentEra, - CurrentPlannedSession, EraRewardPoints, ErasRewardPoints, ErasStakersClipped, - ErasStartSessionIndex, ErasTotalStake, ErasValidatorPrefs, ErasValidatorReward, ForceEra, - Forcing, Nominations, Nominators, Perbill, SlashRewardFraction, SlashingSpans, - ValidatorPrefs, Validators, + ActiveEra, ActiveEraInfo, BalanceOf, BoundedBTreeMap, BoundedVec, CanceledSlashPayout, + ClaimedRewards, CurrentEra, CurrentPlannedSession, EraRewardPoints, ErasRewardPoints, + ErasStakersClipped, ErasStartSessionIndex, ErasTotalStake, ErasValidatorPrefs, + ErasValidatorReward, ForceEra, Forcing, Nominations, Nominators, Perbill, + SlashRewardFraction, SlashingSpans, ValidatorPrefs, Validators, }; use sp_staking::{EraIndex, Exposure, IndividualExposure, Page, SessionIndex}; @@ -8573,10 +8573,13 @@ mod getters { sp_io::TestExternalities::default().execute_with(|| { // given let era: EraIndex = 12; - let reward_points = EraRewardPoints:: { - total: 1, - individual: vec![(11, 1)].into_iter().collect(), - }; + let mut reward_map = BoundedBTreeMap::new(); + assert_ok!(reward_map.try_insert(11, 1)); + let reward_points = + EraRewardPoints::::MaxActiveValidators> { + total: 1, + individual: reward_map, + }; ErasRewardPoints::::insert(era, reward_points); // when From 74f205537e277b1c42d78f1095ead87378e2db2f Mon Sep 17 00:00:00 2001 From: giuseppere Date: Fri, 15 Nov 2024 17:19:42 +0100 Subject: [PATCH 008/101] fix --- polkadot/runtime/test-runtime/src/lib.rs | 2 ++ substrate/bin/node/runtime/src/lib.rs | 2 ++ substrate/frame/staking/src/pallet/impls.rs | 3 +-- substrate/frame/staking/src/tests.rs | 2 +- 4 files changed, 6 insertions(+), 3 deletions(-) diff --git a/polkadot/runtime/test-runtime/src/lib.rs b/polkadot/runtime/test-runtime/src/lib.rs index d2ed5abb6ed1..e320d342020f 100644 --- a/polkadot/runtime/test-runtime/src/lib.rs +++ b/polkadot/runtime/test-runtime/src/lib.rs @@ -396,6 +396,8 @@ impl pallet_staking::Config for Runtime { type EventListeners = (); type WeightInfo = (); type DisablingStrategy = pallet_staking::UpToLimitDisablingStrategy; + type MaxInvulnerables = ConstU32<4>; + type MaxActiveValidators = ConstU32<1000>; } parameter_types! { diff --git a/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs index 914b51fb5621..8f29bf985016 100644 --- a/substrate/bin/node/runtime/src/lib.rs +++ b/substrate/bin/node/runtime/src/lib.rs @@ -743,6 +743,8 @@ impl pallet_staking::Config for Runtime { type WeightInfo = pallet_staking::weights::SubstrateWeight; type BenchmarkingConfig = StakingBenchmarkingConfig; type DisablingStrategy = pallet_staking::UpToLimitDisablingStrategy; + type MaxInvulnerables = ConstU32<4>; + type MaxActiveValidators = ConstU32<1000>; } impl pallet_fast_unstake::Config for Runtime { diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs index 16212aa73ada..8e2f36c95d4c 100644 --- a/substrate/frame/staking/src/pallet/impls.rs +++ b/substrate/frame/staking/src/pallet/impls.rs @@ -867,8 +867,7 @@ impl Pallet { } else { log!( warn, - "Could not add reward points to {}: max numbers of rewarded validators reached", - validator + "Could not add reward points: max numbers of rewarded validators reached" ); } }, diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index 42391859c52a..aa452fb88b38 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -8574,7 +8574,7 @@ mod getters { // given let era: EraIndex = 12; let mut reward_map = BoundedBTreeMap::new(); - assert_ok!(reward_map.try_insert(11, 1)); + frame_support::assert_ok!(reward_map.try_insert(11, 1)); let reward_points = EraRewardPoints::::MaxActiveValidators> { total: 1, From 362f50552869ba8274f785b59313f16d31c6906d Mon Sep 17 00:00:00 2001 From: giuseppere Date: Fri, 22 Nov 2024 18:04:41 +0100 Subject: [PATCH 009/101] Adapt to new recent `DisabledValidators` change --- substrate/frame/staking/src/migrations.rs | 107 ++++++++++++++------ substrate/frame/staking/src/pallet/mod.rs | 6 +- substrate/frame/staking/src/slashing.rs | 23 +++-- substrate/primitives/staking/src/offence.rs | 12 ++- templates/solochain/runtime/src/lib.rs | 15 ++- 5 files changed, 117 insertions(+), 46 deletions(-) diff --git a/substrate/frame/staking/src/migrations.rs b/substrate/frame/staking/src/migrations.rs index b6e7ea2dd43a..9b2704ce55a5 100644 --- a/substrate/frame/staking/src/migrations.rs +++ b/substrate/frame/staking/src/migrations.rs @@ -60,12 +60,88 @@ impl Default for ObsoleteReleases { #[storage_alias] type StorageVersion = StorageValue, ObsoleteReleases, ValueQuery>; +/// Migrating all unbounded storage items to bounded +pub mod v17 { + use super::*; + + pub struct VersionUncheckedMigrateV16ToV17(core::marker::PhantomData); + impl UncheckedOnRuntimeUpgrade for VersionUncheckedMigrateV16ToV17 { + fn on_runtime_upgrade() -> Weight { + let old_disabled_validators = v16::DisabledValidators::::get(); + // BoundedVec with MaxActiveValidators limit, this should always work + let disabled_validators_maybe = BoundedVec::try_from(old_disabled_validators); + match disabled_validators_maybe { + Ok(disabled_validators) => DisabledValidators::::set(disabled_validators), + Err(_) => log!(warn, "Migration failed for DisabledValidators from v16 to v17."), + } + + let old_invulnerables = v16::Invulnerables::::get(); + // BoundedVec with MaxActiveValidators limit, this should always work + let invulnerables_maybe = BoundedVec::try_from(old_invulnerables); + match invulnerables_maybe { + Ok(invulnerables) => Invulnerables::::set(invulnerables), + Err(_) => log!(warn, "Migration failed for Invulnerables from v15 to v16."), + } + + for (era_index, era_rewards) in v16::ErasRewardPoints::::iter() { + let individual_rewards_maybe = BoundedBTreeMap::try_from(era_rewards.individual); + match individual_rewards_maybe { + Ok(individual_rewards) => { + let bounded_era_rewards = EraRewardPoints::< + ::AccountId, + ::MaxActiveValidators, + > { + individual: individual_rewards, + total: era_rewards.total, + }; + ErasRewardPoints::::insert(era_index, bounded_era_rewards); + }, + Err(_) => log!(warn, "Migration failed for ErasRewardPoints from v15 to v16."), + } + } + + log!(info, "v17 applied successfully."); + T::DbWeight::get().reads_writes(1, 1) + } + } +} + /// Migrating `DisabledValidators` from `Vec` to `Vec<(u32, OffenceSeverity)>` to track offense /// severity for re-enabling purposes. pub mod v16 { use super::*; + use frame_support::Twox64Concat; use sp_staking::offence::OffenceSeverity; + #[frame_support::storage_alias] + pub(crate) type Invulnerables = + StorageValue, Vec<::AccountId>, ValueQuery>; + + #[derive(PartialEq, Encode, Decode, RuntimeDebug, TypeInfo)] + pub struct EraRewardPoints { + pub total: u32, + pub individual: BTreeMap, + } + + impl Default for EraRewardPoints { + fn default() -> Self { + EraRewardPoints { total: Default::default(), individual: BTreeMap::new() } + } + } + + #[frame_support::storage_alias] + pub(crate) type ErasRewardPoints = StorageMap< + Pallet, + Twox64Concat, + u32, + EraRewardPoints<::AccountId>, + ValueQuery, + >; + + #[frame_support::storage_alias] + pub(crate) type DisabledValidators = + StorageValue, Vec<(u32, OffenceSeverity)>, ValueQuery>; + pub struct VersionUncheckedMigrateV15ToV16(core::marker::PhantomData); impl UncheckedOnRuntimeUpgrade for VersionUncheckedMigrateV15ToV16 { #[cfg(feature = "try-runtime")] @@ -86,7 +162,7 @@ pub mod v16 { .map(|v| (v, max_offence)) .collect::>(); - DisabledValidators::::set(migrated); + v16::DisabledValidators::::set(migrated); log!(info, "v16 applied successfully."); T::DbWeight::get().reads_writes(1, 1) @@ -136,35 +212,6 @@ pub mod v16 { /// Migrating `OffendingValidators` from `Vec<(u32, bool)>` to `Vec` pub mod v15 { use super::*; - use frame_support::Twox64Concat; - - #[frame_support::storage_alias] - pub(crate) type DisabledValidators = StorageValue, Vec, ValueQuery>; - - #[frame_support::storage_alias] - pub(crate) type Invulnerables = - StorageValue, Vec<::AccountId>, ValueQuery>; - - #[derive(PartialEq, Encode, Decode, RuntimeDebug, TypeInfo)] - pub struct EraRewardPoints { - pub total: u32, - pub individual: BTreeMap, - } - - impl Default for EraRewardPoints { - fn default() -> Self { - EraRewardPoints { total: Default::default(), individual: BTreeMap::new() } - } - } - - #[frame_support::storage_alias] - pub(crate) type ErasRewardPoints = StorageMap< - Pallet, - Twox64Concat, - u32, - EraRewardPoints<::AccountId>, - ValueQuery, - >; // The disabling strategy used by staking pallet type DefaultDisablingStrategy = UpToLimitDisablingStrategy; diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs index 42cdf3688425..1a2c224b0375 100644 --- a/substrate/frame/staking/src/pallet/mod.rs +++ b/substrate/frame/staking/src/pallet/mod.rs @@ -70,7 +70,7 @@ pub mod pallet { use super::*; /// The in-code storage version. - const STORAGE_VERSION: StorageVersion = StorageVersion::new(16); + const STORAGE_VERSION: StorageVersion = StorageVersion::new(17); #[pallet::pallet] #[pallet::storage_version(STORAGE_VERSION)] @@ -718,7 +718,6 @@ pub mod pallet { /// whole era. For this reason they are kept here - only staking pallet knows about eras. The /// implementor of [`DisablingStrategy`] defines if a validator should be disabled which /// implicitly means that the implementor also controls the max number of disabled validators. - /// /// The vec is always kept sorted based on the u32 index so that we can find whether a given /// validator has previously offended using binary search. @@ -726,9 +725,8 @@ pub mod pallet { /// Additionally, each disabled validator is associated with an `OffenceSeverity` which /// represents how severe is the offence that got the validator disabled. #[pallet::storage] - #[pallet::unbounded] pub type DisabledValidators = - StorageValue<_, Vec<(u32, OffenceSeverity)>, ValueQuery>; + StorageValue<_, BoundedVec<(u32, OffenceSeverity), T::MaxActiveValidators>, ValueQuery>; /// The threshold for when users can start calling `chill_other` for other validators / /// nominators. The threshold is compared to the actual number of validators / nominators diff --git a/substrate/frame/staking/src/slashing.rs b/substrate/frame/staking/src/slashing.rs index ae76b0707dcb..d32dc992bd47 100644 --- a/substrate/frame/staking/src/slashing.rs +++ b/substrate/frame/staking/src/slashing.rs @@ -50,7 +50,7 @@ //! Based on research at use crate::{ - asset, BalanceOf, Config, DisabledValidators, DisablingStrategy, Error, Exposure, + asset, log, BalanceOf, Config, DisabledValidators, DisablingStrategy, Error, Exposure, NegativeImbalanceOf, NominatorSlashInEra, Pallet, Perbill, SessionInterface, SpanSlash, UnappliedSlash, ValidatorSlashInEra, }; @@ -340,13 +340,20 @@ fn add_offending_validator(params: &SlashParams) { }, Err(index) => { // Offender is not disabled, add to `DisabledValidators` and disable it - disabled.insert(index, (offender_idx, new_severity)); - // Propagate disablement to session level - T::SessionInterface::disable_validator(offender_idx); - // Emit event that a validator got disabled - >::deposit_event(super::Event::::ValidatorDisabled { - stash: params.stash.clone(), - }); + if disabled.try_insert(index, (offender_idx, new_severity)).is_ok() { + // Propagate disablement to session level + T::SessionInterface::disable_validator(offender_idx); + // Emit event that a validator got disabled + >::deposit_event(super::Event::::ValidatorDisabled { + stash: params.stash.clone(), + }); + } else { + log!( + warn, + "Validator with index {} could not be disabled: max disabled validators limit reached", + index + ) + } }, } } diff --git a/substrate/primitives/staking/src/offence.rs b/substrate/primitives/staking/src/offence.rs index e73e8efe5839..705e6aa0c4ac 100644 --- a/substrate/primitives/staking/src/offence.rs +++ b/substrate/primitives/staking/src/offence.rs @@ -19,7 +19,7 @@ //! that use staking. use alloc::vec::Vec; -use codec::{Decode, Encode}; +use codec::{Decode, Encode, MaxEncodedLen}; use sp_core::Get; use sp_runtime::{transaction_validity::TransactionValidityError, DispatchError, Perbill}; @@ -252,7 +252,15 @@ impl OffenceReportSystem for () { /// For instance used for the purposes of distinguishing who should be /// prioritized for disablement. #[derive( - Clone, Copy, PartialEq, Eq, Encode, Decode, sp_runtime::RuntimeDebug, scale_info::TypeInfo, + Clone, + Copy, + PartialEq, + Eq, + Encode, + Decode, + sp_runtime::RuntimeDebug, + scale_info::TypeInfo, + MaxEncodedLen, )] pub struct OffenceSeverity(pub Perbill); diff --git a/templates/solochain/runtime/src/lib.rs b/templates/solochain/runtime/src/lib.rs index ae0ea16ae42e..615f803c6aab 100644 --- a/templates/solochain/runtime/src/lib.rs +++ b/templates/solochain/runtime/src/lib.rs @@ -13,12 +13,15 @@ use alloc::vec::Vec; use sp_runtime::{ generic, impl_opaque_keys, traits::{BlakeTwo256, IdentifyAccount, Verify}, + type_with_default::TypeWithDefault, MultiAddress, MultiSignature, }; #[cfg(feature = "std")] use sp_version::NativeVersion; use sp_version::RuntimeVersion; +use scale_info::TypeInfo; + pub use frame_system::Call as SystemCall; pub use pallet_balances::Call as BalancesCall; pub use pallet_timestamp::Call as TimestampCall; @@ -122,14 +125,22 @@ pub type AccountId = <::Signer as IdentifyAccount>::Account /// Balance of an account. pub type Balance = u128; +#[derive(Debug, TypeInfo)] +pub struct DefaultNonceProvider; +impl sp_core::Get for DefaultNonceProvider { + fn get() -> u64 { + System::block_number() + } +} + /// Index of a transaction in the chain. -pub type Nonce = u32; +pub type Nonce = TypeWithDefault; /// A hash of some data used by the chain. pub type Hash = sp_core::H256; /// An index to a block. -pub type BlockNumber = u32; +pub type BlockNumber = u64; /// The address format for describing accounts. pub type Address = MultiAddress; From 4f21d534b044e44e718e306b6ecf1cd37ab626ca Mon Sep 17 00:00:00 2001 From: giuseppere Date: Mon, 25 Nov 2024 12:53:13 +0100 Subject: [PATCH 010/101] Change `MaxActiveValidators` to `MaxWinners` --- polkadot/runtime/test-runtime/src/lib.rs | 1 - polkadot/runtime/westend/src/lib.rs | 1 - substrate/bin/node/runtime/src/lib.rs | 1 - substrate/frame/staking/src/benchmarking.rs | 14 +++++++++++--- substrate/frame/staking/src/migrations.rs | 8 ++++---- substrate/frame/staking/src/mock.rs | 1 - substrate/frame/staking/src/pallet/mod.rs | 19 ++++++++++--------- substrate/frame/staking/src/tests.rs | 15 +++------------ 8 files changed, 28 insertions(+), 32 deletions(-) diff --git a/polkadot/runtime/test-runtime/src/lib.rs b/polkadot/runtime/test-runtime/src/lib.rs index 5996131dd6b2..858240b81e8c 100644 --- a/polkadot/runtime/test-runtime/src/lib.rs +++ b/polkadot/runtime/test-runtime/src/lib.rs @@ -397,7 +397,6 @@ impl pallet_staking::Config for Runtime { type WeightInfo = (); type DisablingStrategy = pallet_staking::UpToLimitWithReEnablingDisablingStrategy; type MaxInvulnerables = ConstU32<4>; - type MaxActiveValidators = ConstU32<1000>; } parameter_types! { diff --git a/polkadot/runtime/westend/src/lib.rs b/polkadot/runtime/westend/src/lib.rs index f2d4aef42632..603d58d10d95 100644 --- a/polkadot/runtime/westend/src/lib.rs +++ b/polkadot/runtime/westend/src/lib.rs @@ -757,7 +757,6 @@ impl pallet_staking::Config for Runtime { type WeightInfo = weights::pallet_staking::WeightInfo; type DisablingStrategy = pallet_staking::UpToLimitWithReEnablingDisablingStrategy; type MaxInvulnerables = frame_support::traits::ConstU32<4>; - type MaxActiveValidators = MaxActiveValidators; } impl pallet_fast_unstake::Config for Runtime { diff --git a/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs index fd17cbc13bc2..f1689a11b2a9 100644 --- a/substrate/bin/node/runtime/src/lib.rs +++ b/substrate/bin/node/runtime/src/lib.rs @@ -746,7 +746,6 @@ impl pallet_staking::Config for Runtime { type BenchmarkingConfig = StakingBenchmarkingConfig; type DisablingStrategy = pallet_staking::UpToLimitWithReEnablingDisablingStrategy; type MaxInvulnerables = ConstU32<4>; - type MaxActiveValidators = ConstU32<1000>; } impl pallet_fast_unstake::Config for Runtime { diff --git a/substrate/frame/staking/src/benchmarking.rs b/substrate/frame/staking/src/benchmarking.rs index d768dddda24a..3da40816ba5f 100644 --- a/substrate/frame/staking/src/benchmarking.rs +++ b/substrate/frame/staking/src/benchmarking.rs @@ -22,7 +22,9 @@ use crate::{asset, ConfigOp, Pallet as Staking}; use testing_utils::*; use codec::Decode; -use frame_election_provider_support::{bounds::DataProviderBounds, SortedListProvider}; +use frame_election_provider_support::{ + bounds::DataProviderBounds, ElectionProviderBase, SortedListProvider, +}; use frame_support::{ assert_ok, pallet_prelude::*, @@ -128,7 +130,10 @@ pub fn create_validator_with_nominators( assert_ok!(reward_map.try_insert(validator, reward)); } // Give Era Points - let reward = EraRewardPoints:: { + let reward = EraRewardPoints::< + T::AccountId, + ::MaxWinners, + > { total: points_total, individual: reward_map, }; @@ -875,7 +880,10 @@ mod benchmarks { assert_ok!(reward_map.try_insert(validator, reward)); } // Give Era Points - let reward = EraRewardPoints:: { + let reward = EraRewardPoints::< + T::AccountId, + ::MaxWinners, + > { total: points_total, individual: reward_map, }; diff --git a/substrate/frame/staking/src/migrations.rs b/substrate/frame/staking/src/migrations.rs index 9b2704ce55a5..ae3d1b80ea60 100644 --- a/substrate/frame/staking/src/migrations.rs +++ b/substrate/frame/staking/src/migrations.rs @@ -18,7 +18,7 @@ //! [CHANGELOG.md](https://github.com/paritytech/polkadot-sdk/blob/master/substrate/frame/staking/CHANGELOG.md). use super::*; -use frame_election_provider_support::SortedListProvider; +use frame_election_provider_support::{ElectionProviderBase, SortedListProvider}; use frame_support::{ migrations::VersionedMigration, pallet_prelude::ValueQuery, @@ -68,7 +68,7 @@ pub mod v17 { impl UncheckedOnRuntimeUpgrade for VersionUncheckedMigrateV16ToV17 { fn on_runtime_upgrade() -> Weight { let old_disabled_validators = v16::DisabledValidators::::get(); - // BoundedVec with MaxActiveValidators limit, this should always work + // BoundedVec with MaxWinners limit, this should always work let disabled_validators_maybe = BoundedVec::try_from(old_disabled_validators); match disabled_validators_maybe { Ok(disabled_validators) => DisabledValidators::::set(disabled_validators), @@ -76,7 +76,7 @@ pub mod v17 { } let old_invulnerables = v16::Invulnerables::::get(); - // BoundedVec with MaxActiveValidators limit, this should always work + // BoundedVec with MaxWinners limit, this should always work let invulnerables_maybe = BoundedVec::try_from(old_invulnerables); match invulnerables_maybe { Ok(invulnerables) => Invulnerables::::set(invulnerables), @@ -89,7 +89,7 @@ pub mod v17 { Ok(individual_rewards) => { let bounded_era_rewards = EraRewardPoints::< ::AccountId, - ::MaxActiveValidators, + <::ElectionProvider as ElectionProviderBase>::MaxWinners, > { individual: individual_rewards, total: era_rewards.total, diff --git a/substrate/frame/staking/src/mock.rs b/substrate/frame/staking/src/mock.rs index d62b46114d43..7e4ef0ca41d5 100644 --- a/substrate/frame/staking/src/mock.rs +++ b/substrate/frame/staking/src/mock.rs @@ -288,7 +288,6 @@ impl crate::pallet::pallet::Config for Test { type DisablingStrategy = pallet_staking::UpToLimitWithReEnablingDisablingStrategy; type MaxInvulnerables = ConstU32<4>; - type MaxActiveValidators = ConstU32<100>; } pub struct WeightedNominationsQuota; diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs index 1a2c224b0375..ed773515e027 100644 --- a/substrate/frame/staking/src/pallet/mod.rs +++ b/substrate/frame/staking/src/pallet/mod.rs @@ -301,10 +301,6 @@ pub mod pallet { #[pallet::constant] type MaxInvulnerables: Get; - /// Maximum number of active validators in an era. - #[pallet::constant] - type MaxActiveValidators: Get; - /// Some parameters of the benchmarking. #[cfg(feature = "std")] type BenchmarkingConfig: BenchmarkingConfig; @@ -353,7 +349,6 @@ pub mod pallet { type EventListeners = (); type DisablingStrategy = crate::UpToLimitDisablingStrategy; type MaxInvulnerables = ConstU32<4>; - type MaxActiveValidators = ConstU32<100>; #[cfg(feature = "std")] type BenchmarkingConfig = crate::TestBenchmarkingConfig; type WeightInfo = (); @@ -623,7 +618,7 @@ pub mod pallet { _, Twox64Concat, EraIndex, - EraRewardPoints, + EraRewardPoints::MaxWinners>, ValueQuery, >; @@ -725,8 +720,14 @@ pub mod pallet { /// Additionally, each disabled validator is associated with an `OffenceSeverity` which /// represents how severe is the offence that got the validator disabled. #[pallet::storage] - pub type DisabledValidators = - StorageValue<_, BoundedVec<(u32, OffenceSeverity), T::MaxActiveValidators>, ValueQuery>; + pub type DisabledValidators = StorageValue< + _, + BoundedVec< + (u32, OffenceSeverity), + ::MaxWinners, + >, + ValueQuery, + >; /// The threshold for when users can start calling `chill_other` for other validators / /// nominators. The threshold is compared to the actual number of validators / nominators @@ -1102,7 +1103,7 @@ pub mod pallet { /// Get the rewards for the last [`Config::HistoryDepth`] eras. pub fn eras_reward_points( era_index: EncodeLikeEraIndex, - ) -> EraRewardPoints + ) -> EraRewardPoints::MaxWinners> where EncodeLikeEraIndex: codec::EncodeLike, { diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index 2b518a18bd9d..c818bcccc1fc 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -2332,10 +2332,7 @@ fn reward_validator_slashing_validator_does_not_overflow() { let exposure = Exposure:: { total: stake, own: stake, others: vec![] }; let mut reward_map = BoundedBTreeMap::new(); assert_ok!(reward_map.try_insert(11, 1)); - let reward = EraRewardPoints::::MaxActiveValidators> { - total: 1, - individual: reward_map, - }; + let reward = EraRewardPoints:: { total: 1, individual: reward_map }; // Check reward ErasRewardPoints::::insert(0, reward); @@ -6913,10 +6910,7 @@ fn test_runtime_api_pending_rewards() { assert_ok!(reward_map.try_insert(validator_two, 1)); assert_ok!(reward_map.try_insert(validator_three, 1)); // Add reward points - let reward = EraRewardPoints::::MaxActiveValidators> { - total: 1, - individual: reward_map, - }; + let reward = EraRewardPoints:: { total: 1, individual: reward_map }; ErasRewardPoints::::insert(0, reward); // build exposure @@ -8984,10 +8978,7 @@ mod getters { let mut reward_map = BoundedBTreeMap::new(); frame_support::assert_ok!(reward_map.try_insert(11, 1)); let reward_points = - EraRewardPoints::::MaxActiveValidators> { - total: 1, - individual: reward_map, - }; + EraRewardPoints:: { total: 1, individual: reward_map }; ErasRewardPoints::::insert(era, reward_points); // when From e258baf8032edb32538e6074391666aa347378a1 Mon Sep 17 00:00:00 2001 From: giuseppere Date: Mon, 25 Nov 2024 12:56:35 +0100 Subject: [PATCH 011/101] undo change from another PR --- templates/solochain/runtime/src/lib.rs | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/templates/solochain/runtime/src/lib.rs b/templates/solochain/runtime/src/lib.rs index 615f803c6aab..ae0ea16ae42e 100644 --- a/templates/solochain/runtime/src/lib.rs +++ b/templates/solochain/runtime/src/lib.rs @@ -13,15 +13,12 @@ use alloc::vec::Vec; use sp_runtime::{ generic, impl_opaque_keys, traits::{BlakeTwo256, IdentifyAccount, Verify}, - type_with_default::TypeWithDefault, MultiAddress, MultiSignature, }; #[cfg(feature = "std")] use sp_version::NativeVersion; use sp_version::RuntimeVersion; -use scale_info::TypeInfo; - pub use frame_system::Call as SystemCall; pub use pallet_balances::Call as BalancesCall; pub use pallet_timestamp::Call as TimestampCall; @@ -125,22 +122,14 @@ pub type AccountId = <::Signer as IdentifyAccount>::Account /// Balance of an account. pub type Balance = u128; -#[derive(Debug, TypeInfo)] -pub struct DefaultNonceProvider; -impl sp_core::Get for DefaultNonceProvider { - fn get() -> u64 { - System::block_number() - } -} - /// Index of a transaction in the chain. -pub type Nonce = TypeWithDefault; +pub type Nonce = u32; /// A hash of some data used by the chain. pub type Hash = sp_core::H256; /// An index to a block. -pub type BlockNumber = u64; +pub type BlockNumber = u32; /// The address format for describing accounts. pub type Address = MultiAddress; From 01e2233cc99049c44b3354e7f457b37ab0793ae9 Mon Sep 17 00:00:00 2001 From: giuseppere Date: Mon, 25 Nov 2024 13:00:27 +0100 Subject: [PATCH 012/101] small fix for `MaxWinners` --- substrate/frame/staking/src/tests.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index c818bcccc1fc..5c2c56c23ccb 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -8754,7 +8754,7 @@ mod getters { mock::{self}, pallet::pallet::{Invulnerables, MinimumValidatorCount, ValidatorCount}, slashing, - tests::{Staking, Test}, + tests::{MaxWinners, Staking, Test}, ActiveEra, ActiveEraInfo, BalanceOf, BoundedBTreeMap, BoundedVec, CanceledSlashPayout, ClaimedRewards, CurrentEra, CurrentPlannedSession, EraRewardPoints, ErasRewardPoints, ErasStakersClipped, ErasStartSessionIndex, ErasTotalStake, ErasValidatorPrefs, From 243bec8686644ae112c5995d67a7147b6716a136 Mon Sep 17 00:00:00 2001 From: giuseppere Date: Mon, 25 Nov 2024 14:32:56 +0100 Subject: [PATCH 013/101] small fixes --- polkadot/runtime/westend/src/lib.rs | 1 + substrate/frame/staking/src/migrations.rs | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/polkadot/runtime/westend/src/lib.rs b/polkadot/runtime/westend/src/lib.rs index 603d58d10d95..3bd3d8bffe1b 100644 --- a/polkadot/runtime/westend/src/lib.rs +++ b/polkadot/runtime/westend/src/lib.rs @@ -1840,6 +1840,7 @@ pub mod migrations { parachains_shared::migration::MigrateToV1, parachains_scheduler::migration::MigrateV2ToV3, pallet_staking::migrations::v16::MigrateV15ToV16, + pallet_staking::migrations::v17::MigrateV16ToV17, // permanent pallet_xcm::migration::MigrateToLatestXcmVersion, ); diff --git a/substrate/frame/staking/src/migrations.rs b/substrate/frame/staking/src/migrations.rs index ae3d1b80ea60..c799f4c6cd1e 100644 --- a/substrate/frame/staking/src/migrations.rs +++ b/substrate/frame/staking/src/migrations.rs @@ -104,6 +104,14 @@ pub mod v17 { T::DbWeight::get().reads_writes(1, 1) } } + + pub type MigrateV16ToV17 = VersionedMigration< + 16, + 17, + VersionUncheckedMigrateV16ToV17, + Pallet, + ::DbWeight, + >; } /// Migrating `DisabledValidators` from `Vec` to `Vec<(u32, OffenceSeverity)>` to track offense From 9a25fbc4a0d68f170bd4aec6809a4ba31170432f Mon Sep 17 00:00:00 2001 From: giuseppere Date: Mon, 25 Nov 2024 15:44:32 +0100 Subject: [PATCH 014/101] Remove deprecated `ErasStakers` and `ErasStakersClipped` --- polkadot/runtime/common/src/try_runtime.rs | 36 +------- .../src/weights/pallet_fast_unstake.rs | 2 - .../westend/src/weights/pallet_staking.rs | 2 - substrate/frame/fast-unstake/src/weights.rs | 4 - substrate/frame/staking/src/lib.rs | 33 +------ substrate/frame/staking/src/pallet/impls.rs | 41 ++------- substrate/frame/staking/src/pallet/mod.rs | 69 +------------- substrate/frame/staking/src/tests.rs | 90 ++----------------- 8 files changed, 21 insertions(+), 256 deletions(-) diff --git a/polkadot/runtime/common/src/try_runtime.rs b/polkadot/runtime/common/src/try_runtime.rs index b22e17032920..a437e889390e 100644 --- a/polkadot/runtime/common/src/try_runtime.rs +++ b/polkadot/runtime/common/src/try_runtime.rs @@ -16,16 +16,10 @@ //! Common try-runtime only tests for runtimes. -use alloc::{collections::btree_set::BTreeSet, vec::Vec}; -use frame_support::{ - dispatch::RawOrigin, - traits::{Get, Hooks}, -}; +use frame_support::traits::{Get, Hooks}; use pallet_fast_unstake::{Pallet as FastUnstake, *}; -use pallet_staking::*; -/// register all inactive nominators for fast-unstake, and progress until they have all been -/// processed. +/// progress until the inactive nominators have all beenprocessed. pub fn migrate_all_inactive_nominators() where ::RuntimeEvent: TryInto>, @@ -34,32 +28,6 @@ where let mut unstaked_err = 0; let mut unstaked_slashed = 0; - let all_stakers = Ledger::::iter().map(|(ctrl, l)| (ctrl, l.stash)).collect::>(); - let mut all_exposed = BTreeSet::new(); - ErasStakers::::iter().for_each(|(_, val, expo)| { - all_exposed.insert(val); - all_exposed.extend(expo.others.iter().map(|ie| ie.who.clone())) - }); - - let eligible = all_stakers - .iter() - .filter_map(|(ctrl, stash)| all_exposed.contains(stash).then_some(ctrl)) - .collect::>(); - - log::info!( - target: "runtime::test", - "registering {} out of {} stakers for fast-unstake", - eligible.len(), - all_stakers.len() - ); - for ctrl in eligible { - if let Err(why) = - FastUnstake::::register_fast_unstake(RawOrigin::Signed(ctrl.clone()).into()) - { - log::warn!(target: "runtime::test", "failed to register {:?} due to {:?}", ctrl, why); - } - } - log::info!( target: "runtime::test", "registered {} successfully, starting at {:?}.", diff --git a/polkadot/runtime/westend/src/weights/pallet_fast_unstake.rs b/polkadot/runtime/westend/src/weights/pallet_fast_unstake.rs index 8c061688fc66..dafac66f9d77 100644 --- a/polkadot/runtime/westend/src/weights/pallet_fast_unstake.rs +++ b/polkadot/runtime/westend/src/weights/pallet_fast_unstake.rs @@ -108,8 +108,6 @@ impl pallet_fast_unstake::WeightInfo for WeightInfo /// Proof Skipped: ElectionProviderMultiPhase CurrentPhase (max_values: Some(1), 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 ErasStakers (r:257 w:0) - /// Proof Skipped: Staking ErasStakers (max_values: None, max_size: None, mode: Measured) /// The range of component `v` is `[1, 256]`. /// The range of component `b` is `[1, 64]`. fn on_idle_check(v: u32, b: u32, ) -> Weight { diff --git a/polkadot/runtime/westend/src/weights/pallet_staking.rs b/polkadot/runtime/westend/src/weights/pallet_staking.rs index 393fa0b37176..24d0a3e1485b 100644 --- a/polkadot/runtime/westend/src/weights/pallet_staking.rs +++ b/polkadot/runtime/westend/src/weights/pallet_staking.rs @@ -488,8 +488,6 @@ impl pallet_staking::WeightInfo for WeightInfo { /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// Storage: `Staking::Ledger` (r:65 w:65) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) - /// Storage: `Staking::ErasStakersClipped` (r:1 w:0) - /// Proof: `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) diff --git a/substrate/frame/fast-unstake/src/weights.rs b/substrate/frame/fast-unstake/src/weights.rs index efa2a67ae35d..8b16fccef470 100644 --- a/substrate/frame/fast-unstake/src/weights.rs +++ b/substrate/frame/fast-unstake/src/weights.rs @@ -120,8 +120,6 @@ impl WeightInfo for SubstrateWeight { /// Proof: `ElectionProviderMultiPhase::CurrentPhase` (`max_values`: Some(1), `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::ErasStakers` (r:1 w:0) - /// Proof: `Staking::ErasStakers` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Staking::ErasStakersPaged` (r:257 w:0) /// Proof: `Staking::ErasStakersPaged` (`max_values`: None, `max_size`: None, mode: `Measured`) /// The range of component `v` is `[1, 256]`. @@ -277,8 +275,6 @@ impl WeightInfo for () { /// Proof: `ElectionProviderMultiPhase::CurrentPhase` (`max_values`: Some(1), `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::ErasStakers` (r:1 w:0) - /// Proof: `Staking::ErasStakers` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Staking::ErasStakersPaged` (r:257 w:0) /// Proof: `Staking::ErasStakersPaged` (`max_values`: None, `max_size`: None, mode: `Measured`) /// The range of component `v` is `[1, 256]`. diff --git a/substrate/frame/staking/src/lib.rs b/substrate/frame/staking/src/lib.rs index 36460e6bf3b8..e9bf51688b96 100644 --- a/substrate/frame/staking/src/lib.rs +++ b/substrate/frame/staking/src/lib.rs @@ -1057,13 +1057,8 @@ impl EraInfo { let page_count = if let Some(overview) = >::get(&era, validator) { overview.page_count } else { - if >::contains_key(era, validator) { - // this means non paged exposure, and we treat them as single paged. - 1 - } else { - // if no exposure, then no rewards to claim. - return false - } + // if no exposure, then no rewards to claim. + return false }; // check if era is marked claimed in legacy storage. @@ -1112,12 +1107,6 @@ impl EraInfo { ) -> Option>> { 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(PagedExposure::from_clipped(>::get(era, validator))) - } - // no exposure for this validator if overview.is_none() { return None @@ -1146,10 +1135,6 @@ impl EraInfo { ) -> Exposure> { let overview = >::get(&era, validator); - if overview.is_none() { - return ErasStakers::::get(era, validator) - } - let overview = overview.expect("checked above; qed"); let mut others = Vec::with_capacity(overview.nominator_count as usize); @@ -1186,15 +1171,6 @@ impl EraInfo { 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 all_claimable_pages: Vec = (0..page_count).collect(); @@ -1203,11 +1179,6 @@ impl EraInfo { all_claimable_pages.into_iter().find(|p| !claimed_pages.contains(p)) } - /// 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, diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs index 01a1bd1419af..a94cb2a7beef 100644 --- a/substrate/frame/staking/src/pallet/impls.rs +++ b/substrate/frame/staking/src/pallet/impls.rs @@ -808,11 +808,7 @@ impl Pallet { pub(crate) fn clear_era_information(era_index: EraIndex) { // FIXME: We can possibly set a reasonable limit since we do this only once per era and // clean up state across multiple blocks. - let mut cursor = >::clear_prefix(era_index, u32::MAX, None); - debug_assert!(cursor.maybe_cursor.is_none()); - cursor = >::clear_prefix(era_index, u32::MAX, None); - debug_assert!(cursor.maybe_cursor.is_none()); - cursor = >::clear_prefix(era_index, u32::MAX, None); + let mut cursor = >::clear_prefix(era_index, u32::MAX, None); debug_assert!(cursor.maybe_cursor.is_none()); cursor = >::clear_prefix(era_index, u32::MAX, None); debug_assert!(cursor.maybe_cursor.is_none()); @@ -1167,9 +1163,10 @@ 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. + /// History note: This used to be a getter for old storage item `ErasStakers` deprecated in v14 + /// and deleted in v17. 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, @@ -1861,12 +1858,6 @@ impl StakingInterface for Pallet { } fn is_exposed_in_era(who: &Self::AccountId, era: &EraIndex) -> bool { - // look in the non paged exposures - // FIXME: Can be cleaned up once non paged exposures are cleared (https://github.com/paritytech/polkadot-sdk/issues/433) - ErasStakers::::iter_prefix(era).any(|(validator, exposures)| { - validator == *who || exposures.others.iter().any(|i| i.who == *who) - }) - || // look in the paged exposures ErasStakersPaged::::iter_prefix((era,)).any(|((validator, _), exposure_page)| { validator == *who || exposure_page.others.iter().any(|i| i.who == *who) @@ -1994,7 +1985,6 @@ impl Pallet { Self::check_bonded_consistency()?; Self::check_payees()?; Self::check_nominators()?; - Self::check_exposures()?; Self::check_paged_exposures()?; Self::check_count()?; Self::ensure_disabled_validators_sorted() @@ -2152,27 +2142,6 @@ impl Pallet { Ok(()) } - /// Invariants: - /// * For each era exposed validator, check if the exposure total is sane (exposure.total = - /// exposure.own + exposure.own). - fn check_exposures() -> Result<(), TryRuntimeError> { - let era = ActiveEra::::get().unwrap().index; - ErasStakers::::iter_prefix_values(era) - .map(|expo| { - ensure!( - expo.total == - expo.own + - expo.others - .iter() - .map(|e| e.value) - .fold(Zero::zero(), |acc, x| acc + x), - "wrong total exposure.", - ); - Ok(()) - }) - .collect::>() - } - /// Invariants: /// * For each paged era exposed validator, check if the exposure total is sane (exposure.total /// = exposure.own + exposure.own). diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs index ed773515e027..0073a7b470c8 100644 --- a/substrate/frame/staking/src/pallet/mod.rs +++ b/substrate/frame/staking/src/pallet/mod.rs @@ -146,10 +146,9 @@ pub mod pallet { /// Number of eras to keep in history. /// /// Following information is kept for eras in `[current_era - - /// HistoryDepth, current_era]`: `ErasStakers`, `ErasStakersClipped`, - /// `ErasValidatorPrefs`, `ErasValidatorReward`, `ErasRewardPoints`, - /// `ErasTotalStake`, `ErasStartSessionIndex`, `ClaimedRewards`, `ErasStakersPaged`, - /// `ErasStakersOverview`. + /// HistoryDepth, current_era]`: `ErasValidatorPrefs`, `ErasValidatorReward`, + /// `ErasRewardPoints`, `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 > @@ -480,26 +479,6 @@ pub mod pallet { #[pallet::storage] pub type ErasStartSessionIndex = StorageMap<_, Twox64Concat, EraIndex, SessionIndex>; - /// Exposure of validator at era. - /// - /// This is keyed first by the era index to allow bulk deletion and then the stash account. - /// - /// 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. - #[pallet::storage] - #[pallet::unbounded] - pub type ErasStakers = StorageDoubleMap< - _, - Twox64Concat, - EraIndex, - Twox64Concat, - T::AccountId, - Exposure>, - ValueQuery, - >; - /// Summary of validator exposure at a given era. /// /// This contains the total stake in support of the validator and their own stake. In addition, @@ -523,34 +502,6 @@ pub mod pallet { OptionQuery, >; - /// 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::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. - /// - /// This is keyed fist by the era index to allow bulk deletion and then the stash account. - /// - /// 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. - #[pallet::storage] - #[pallet::unbounded] - pub type ErasStakersClipped = StorageDoubleMap< - _, - Twox64Concat, - EraIndex, - Twox64Concat, - T::AccountId, - Exposure>, - ValueQuery, - >; - /// 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 @@ -588,7 +539,7 @@ pub mod pallet { ValueQuery, >; - /// Similar to `ErasStakers`, this holds the preferences of validators. + /// Exposure of validator at era with the preferences of validators. /// /// This is keyed first by the era index to allow bulk deletion and then the stash account. /// @@ -1054,18 +1005,6 @@ pub mod pallet { ErasStartSessionIndex::::get(era_index) } - /// Get the clipped exposure of a given validator at an era. - pub fn eras_stakers_clipped( - era_index: EncodeLikeEraIndex, - account_id: EncodeLikeAccountId, - ) -> Exposure> - where - EncodeLikeEraIndex: codec::EncodeLike, - EncodeLikeAccountId: codec::EncodeLike, - { - ErasStakersClipped::::get(era_index, account_id) - } - /// Get the paged history of claimed rewards by era for given validator. pub fn claimed_rewards( era_index: EncodeLikeEraIndex, diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index 5c2c56c23ccb..b59c652cd962 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -6826,62 +6826,10 @@ fn test_validator_exposure_is_backward_compatible_with_non_paged_rewards_payout( assert!(::is_exposed_in_era(&who, &1)); } - // 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); - >::insert( - 1, - 11, - Exposure { total: total_exposure, own: 1000, others: clipped_exposure.clone() }, - ); - - // verify `EraInfo` returns exposure from clipped storage - let actual_exposure_paged = EraInfo::::get_paged_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_metadata.page_count, 1); - let actual_exposure_full = EraInfo::::get_full_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); - - // validator is exposed - assert!(::is_exposed_in_era(&11, &1)); - // nominators are exposed - for i in 10..15 { - let who: AccountId = 1000 + i; - assert!(::is_exposed_in_era(&who, &1)); - } - - // for pages other than 0, clipped storage returns empty exposure - assert_eq!(EraInfo::::get_paged_exposure(1, &11, 1), None); - // 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_by_page(RuntimeOrigin::signed(1337), 11, 0, 0)); - // payout for page 1 fails - assert_noop!( - Staking::payout_stakers_by_page(RuntimeOrigin::signed(1337), 11, 0, 1), - Error::::InvalidPage - .with_weight(::WeightInfo::payout_stakers_alive_staked(0)) - ); }); } @@ -6924,11 +6872,10 @@ fn test_runtime_api_pending_rewards() { others: individual_exposures, }; - // add non-paged exposure for one and two. - >::insert(0, validator_one, exposure.clone()); - >::insert(0, validator_two, exposure.clone()); - // add paged exposure for third validator - EraInfo::::set_exposure(0, &validator_three, exposure); + // add exposure for validators + EraInfo::::set_exposure(0, &validator_one, exposure.clone()); + EraInfo::::set_exposure(0, &validator_two, exposure.clone()); + EraInfo::::set_exposure(0, &validator_three, exposure.clone()); // add some reward to be distributed ErasValidatorReward::::insert(0, 1000); @@ -8757,11 +8704,11 @@ mod getters { tests::{MaxWinners, Staking, Test}, ActiveEra, ActiveEraInfo, BalanceOf, BoundedBTreeMap, BoundedVec, CanceledSlashPayout, ClaimedRewards, CurrentEra, CurrentPlannedSession, EraRewardPoints, ErasRewardPoints, - ErasStakersClipped, ErasStartSessionIndex, ErasTotalStake, ErasValidatorPrefs, - ErasValidatorReward, ForceEra, Forcing, Nominations, Nominators, Perbill, - SlashRewardFraction, SlashingSpans, ValidatorPrefs, Validators, + ErasStartSessionIndex, ErasTotalStake, ErasValidatorPrefs, ErasValidatorReward, ForceEra, + Forcing, Nominations, Nominators, Perbill, SlashRewardFraction, SlashingSpans, + ValidatorPrefs, Validators, }; - use sp_staking::{EraIndex, Exposure, IndividualExposure, Page, SessionIndex}; + use sp_staking::{EraIndex, Page, SessionIndex}; #[test] fn get_validator_count_returns_value_from_storage() { @@ -8897,27 +8844,6 @@ mod getters { }); } - #[test] - fn get_eras_stakers_clipped_returns_value_from_storage() { - sp_io::TestExternalities::default().execute_with(|| { - // given - let era: EraIndex = 12; - let account_id: mock::AccountId = 1; - let exposure: Exposure> = Exposure { - total: 1125, - own: 1000, - others: vec![IndividualExposure { who: 101, value: 125 }], - }; - ErasStakersClipped::::insert(era, account_id, exposure.clone()); - - // when - let result = Staking::eras_stakers_clipped(era, &account_id); - - // then - assert_eq!(result, exposure); - }); - } - #[test] fn get_claimed_rewards_returns_value_from_storage() { sp_io::TestExternalities::default().execute_with(|| { From 98daabc622a3b939ea70c74f9116e0d830ec84ef Mon Sep 17 00:00:00 2001 From: giuseppere Date: Mon, 25 Nov 2024 16:24:26 +0100 Subject: [PATCH 015/101] Fixes from #5986 --- polkadot/runtime/common/src/try_runtime.rs | 36 +++- substrate/frame/staking/src/lib.rs | 57 ++---- substrate/frame/staking/src/pallet/impls.rs | 19 +- substrate/frame/staking/src/tests.rs | 196 +------------------- 4 files changed, 57 insertions(+), 251 deletions(-) diff --git a/polkadot/runtime/common/src/try_runtime.rs b/polkadot/runtime/common/src/try_runtime.rs index a437e889390e..795249dde20b 100644 --- a/polkadot/runtime/common/src/try_runtime.rs +++ b/polkadot/runtime/common/src/try_runtime.rs @@ -16,10 +16,16 @@ //! Common try-runtime only tests for runtimes. -use frame_support::traits::{Get, Hooks}; +use alloc::{collections::btree_set::BTreeSet, vec::Vec}; +use frame_support::{ + dispatch::RawOrigin, + traits::{Get, Hooks}, +}; use pallet_fast_unstake::{Pallet as FastUnstake, *}; +use pallet_staking::*; -/// progress until the inactive nominators have all beenprocessed. +/// register all inactive nominators for fast-unstake, and progress until they have all been +/// processed. pub fn migrate_all_inactive_nominators() where ::RuntimeEvent: TryInto>, @@ -28,6 +34,32 @@ where let mut unstaked_err = 0; let mut unstaked_slashed = 0; + let all_stakers = Ledger::::iter().map(|(ctrl, l)| (ctrl, l.stash)).collect::>(); + let mut all_exposed = BTreeSet::new(); + ErasStakersPaged::::iter().for_each(|((_era, val, _page), expo)| { + all_exposed.insert(val); + all_exposed.extend(expo.others.iter().map(|ie| ie.who.clone())) + }); + + let eligible = all_stakers + .iter() + .filter_map(|(ctrl, stash)| all_exposed.contains(stash).then_some(ctrl)) + .collect::>(); + + log::info!( + target: "runtime::test", + "registering {} out of {} stakers for fast-unstake", + eligible.len(), + all_stakers.len() + ); + for ctrl in eligible { + if let Err(why) = + FastUnstake::::register_fast_unstake(RawOrigin::Signed(ctrl.clone()).into()) + { + log::warn!(target: "runtime::test", "failed to register {:?} due to {:?}", ctrl, why); + } + } + log::info!( target: "runtime::test", "registered {} successfully, starting at {:?}.", diff --git a/substrate/frame/staking/src/lib.rs b/substrate/frame/staking/src/lib.rs index e9bf51688b96..44050b060f26 100644 --- a/substrate/frame/staking/src/lib.rs +++ b/substrate/frame/staking/src/lib.rs @@ -1054,37 +1054,11 @@ impl EraInfo { /// Returns true if validator has one or more page of era rewards not claimed yet. // Also looks at legacy storage that can be cleaned up after #433. pub fn pending_rewards(era: EraIndex, validator: &T::AccountId) -> bool { - let page_count = if let Some(overview) = >::get(&era, validator) { - overview.page_count - } else { - // if no exposure, then no rewards to claim. - return false - }; - - // check if era is marked claimed in legacy storage. - if >::get(validator) - .map(|l| l.legacy_claimed_rewards.contains(&era)) - .unwrap_or_default() - { - return false - } - - ClaimedRewards::::get(era, validator).len() < page_count as usize - } - - /// 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 `T::HistoryDepth` eras have passed and none of the older non-paged rewards - /// are relevant/claimable. - // Refer tracker issue for cleanup: https://github.com/paritytech/polkadot-sdk/issues/433 - pub(crate) fn is_rewards_claimed_with_legacy_fallback( - era: EraIndex, - ledger: &StakingLedger, - validator: &T::AccountId, - page: Page, - ) -> bool { - ledger.legacy_claimed_rewards.binary_search(&era).is_ok() || - Self::is_rewards_claimed(era, validator, page) + >::get(&era, validator) + .map(|overview| { + ClaimedRewards::::get(era, validator).len() < overview.page_count as usize + }) + .unwrap_or(false) } /// Check if the rewards for the given era and page index have been claimed. @@ -1092,7 +1066,7 @@ impl EraInfo { /// This is only used for paged rewards. Once older non-paged rewards are no longer /// 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: Page) -> bool { + pub(crate) fn is_rewards_claimed(era: EraIndex, validator: &T::AccountId, page: Page) -> bool { ClaimedRewards::::get(era, validator).contains(&page) } @@ -1105,14 +1079,7 @@ impl EraInfo { validator: &T::AccountId, page: Page, ) -> Option>> { - let overview = >::get(&era, validator); - - // no exposure for this validator - if overview.is_none() { - return None - } - - let overview = overview.expect("checked above; qed"); + let overview = >::get(&era, validator)?; // validator stake is added only in page zero let validator_stake = if page == 0 { overview.own } else { Zero::zero() }; @@ -1135,6 +1102,10 @@ impl EraInfo { ) -> Exposure> { let overview = >::get(&era, validator); + if overview.is_none() { + return Exposure::default() + } + let overview = overview.expect("checked above; qed"); let mut others = Vec::with_capacity(overview.nominator_count as usize); @@ -1166,11 +1137,7 @@ impl EraInfo { } /// Returns the next page that can be claimed or `None` if nothing to claim. - pub(crate) fn get_next_claimable_page( - era: EraIndex, - validator: &T::AccountId, - ledger: &StakingLedger, - ) -> Option { + pub(crate) fn get_next_claimable_page(era: EraIndex, validator: &T::AccountId) -> Option { // 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(); diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs index a94cb2a7beef..68f8aa3dc336 100644 --- a/substrate/frame/staking/src/pallet/impls.rs +++ b/substrate/frame/staking/src/pallet/impls.rs @@ -233,13 +233,8 @@ impl Pallet { validator_stash: T::AccountId, era: EraIndex, ) -> DispatchResultWithPostInfo { - let controller = Self::bonded(&validator_stash).ok_or_else(|| { - Error::::NotStash.with_weight(T::WeightInfo::payout_stakers_alive_staked(0)) - })?; - - let ledger = Self::ledger(StakingAccount::Controller(controller))?; - let page = EraInfo::::get_next_claimable_page(era, &validator_stash, &ledger) - .ok_or_else(|| { + let page = + EraInfo::::get_next_claimable_page(era, &validator_stash).ok_or_else(|| { Error::::AlreadyClaimed .with_weight(T::WeightInfo::payout_stakers_alive_staked(0)) })?; @@ -294,13 +289,13 @@ impl Pallet { let stash = ledger.stash.clone(); - if EraInfo::::is_rewards_claimed_with_legacy_fallback(era, &ledger, &stash, page) { + if EraInfo::::is_rewards_claimed(era, &stash, page) { return Err(Error::::AlreadyClaimed .with_weight(T::WeightInfo::payout_stakers_alive_staked(0))) - } else { - EraInfo::::set_rewards_as_claimed(era, &stash, page); } + EraInfo::::set_rewards_as_claimed(era, &stash, page); + let exposure = EraInfo::::get_paged_exposure(era, &stash, page).ok_or_else(|| { Error::::InvalidEraToReward .with_weight(T::WeightInfo::payout_stakers_alive_staked(0)) @@ -350,7 +345,7 @@ impl Pallet { era_index: era, validator_stash: stash.clone(), page, - next: EraInfo::::get_next_claimable_page(era, &stash, &ledger), + next: EraInfo::::get_next_claimable_page(era, &stash), }); let mut total_imbalance = PositiveImbalanceOf::::zero(); @@ -1163,7 +1158,7 @@ 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 + /// History note: This used to be a getter for the storage item `ErasStakers` deprecated in v14 /// and deleted in v17. 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. diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index b59c652cd962..511aa280cc2e 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -4063,17 +4063,8 @@ fn test_multi_page_payout_stakers_by_page() { ); // verify rewards are tracked to prevent double claims - let ledger = Staking::ledger(11.into()); 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 - ), - true - ); + assert_eq!(EraInfo::::is_rewards_claimed(1, &11, page), true); } for i in 3..16 { @@ -4095,15 +4086,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_with_legacy_fallback( - i - 1, - Staking::ledger(11.into()).as_ref().unwrap(), - &11, - page - ), - true - ); + assert_eq!(EraInfo::::is_rewards_claimed(i - 1, &11, page), true); } } @@ -4262,7 +4245,6 @@ fn test_multi_page_payout_stakers_backward_compatible() { } // verify we no longer track rewards in `legacy_claimed_rewards` vec - let ledger = Staking::ledger(11.into()); assert_eq!( Staking::ledger(11.into()).unwrap(), StakingLedgerInspect { @@ -4277,12 +4259,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_with_legacy_fallback( - 1, - ledger.as_ref().unwrap(), - &11, - page - ), + EraInfo::::is_rewards_claimed_with_legacy_fallback(1, &11, page), true ); } @@ -4307,12 +4284,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_with_legacy_fallback( - i - 1, - Staking::ledger(11.into()).as_ref().unwrap(), - &11, - page - ), + EraInfo::::is_rewards_claimed_with_legacy_fallback(i - 1, &11, page), true ); } @@ -6673,166 +6645,6 @@ 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, 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_with_legacy_fallback( - 1, - Staking::ledger(11.into()).as_ref().unwrap(), - &11, - 0 - ), - false - ); - assert_eq!( - EraInfo::::is_rewards_claimed_with_legacy_fallback( - 2, - Staking::ledger(11.into()).as_ref().unwrap(), - &11, - 0 - ), - false - ); - - // assume reward claim for era 1 was stored in legacy storage - Ledger::::insert( - 11, - StakingLedgerInspect { - 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_by_page(RuntimeOrigin::signed(1337), 11, 1, 0), - Error::::AlreadyClaimed - .with_weight(::WeightInfo::payout_stakers_alive_staked(0)), - ); - assert_eq!( - EraInfo::::is_rewards_claimed_with_legacy_fallback( - 1, - Staking::ledger(11.into()).as_ref().unwrap(), - &11, - 0 - ), - true - ); - - // 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_with_legacy_fallback( - 2, - Staking::ledger(11.into()).as_ref().unwrap(), - &11, - 0 - ), - true - ); - // but the new claimed rewards for era 2 is not stored in legacy storage - assert_eq!( - Ledger::::get(11).unwrap(), - StakingLedgerInspect { - 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 - MaxExposurePageSize::set(10); - bond_validator(11, 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, 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, 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_paged_exposure(1, &11, 0).unwrap().others(), - &actual_exposure_page_0.others - ); - assert_eq!( - EraInfo::::get_paged_exposure(1, &11, 1).unwrap().others(), - &actual_exposure_page_1.others - ); - assert_eq!(EraInfo::::get_page_count(1, &11), 2); - - // validator is exposed - assert!(::is_exposed_in_era(&11, &1)); - // nominators are exposed - for i in 10..15 { - let who: AccountId = 1000 + i; - assert!(::is_exposed_in_era(&who, &1)); - } - - let actual_exposure_full = EraInfo::::get_full_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); - }); -} - #[test] fn test_runtime_api_pending_rewards() { ExtBuilder::default().build_and_execute(|| { From aec5087e530f54e77fec3e94cf8aaa890f906302 Mon Sep 17 00:00:00 2001 From: giuseppere Date: Mon, 25 Nov 2024 16:26:28 +0100 Subject: [PATCH 016/101] nit --- substrate/frame/staking/src/tests.rs | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index 511aa280cc2e..591d794a4580 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -4258,10 +4258,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_with_legacy_fallback(1, &11, page), - true - ); + assert_eq!(EraInfo::::is_rewards_claimed(1, &11, page), true); } for i in 3..16 { @@ -4283,10 +4280,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_with_legacy_fallback(i - 1, &11, page), - true - ); + assert_eq!(EraInfo::::is_rewards_claimed(i - 1, &11, page), true); } } From 36204daf9fae6085e6b81ea84badc3652879a4cc Mon Sep 17 00:00:00 2001 From: giuseppere Date: Mon, 25 Nov 2024 17:28:22 +0100 Subject: [PATCH 017/101] remove unused import --- substrate/frame/staking/src/pallet/mod.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs index 0073a7b470c8..cd3773fb8e29 100644 --- a/substrate/frame/staking/src/pallet/mod.rs +++ b/substrate/frame/staking/src/pallet/mod.rs @@ -50,10 +50,10 @@ pub use impls::*; use crate::{ asset, slashing, weights::WeightInfo, AccountIdLookupOf, ActiveEraInfo, BalanceOf, - DisablingStrategy, EraPayout, EraRewardPoints, Exposure, ExposurePage, Forcing, - LedgerIntegrityState, MaxNominationsOf, NegativeImbalanceOf, Nominations, NominationsQuota, - PositiveImbalanceOf, RewardDestination, SessionInterface, StakingLedger, UnappliedSlash, - UnlockChunk, ValidatorPrefs, + DisablingStrategy, EraPayout, EraRewardPoints, ExposurePage, Forcing, LedgerIntegrityState, + MaxNominationsOf, NegativeImbalanceOf, Nominations, NominationsQuota, PositiveImbalanceOf, + RewardDestination, SessionInterface, StakingLedger, UnappliedSlash, UnlockChunk, + ValidatorPrefs, }; // The speculative number of spans are used as an input of the weight annotation of From 18e9bee5fc06dd5b3e034d208b4fdf6f63ebb056 Mon Sep 17 00:00:00 2001 From: giuseppere Date: Mon, 25 Nov 2024 18:24:11 +0100 Subject: [PATCH 018/101] fix `Invulnerables` migration --- substrate/frame/staking/src/migrations.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/substrate/frame/staking/src/migrations.rs b/substrate/frame/staking/src/migrations.rs index c799f4c6cd1e..1b15d4adca37 100644 --- a/substrate/frame/staking/src/migrations.rs +++ b/substrate/frame/staking/src/migrations.rs @@ -79,7 +79,7 @@ pub mod v17 { // BoundedVec with MaxWinners limit, this should always work let invulnerables_maybe = BoundedVec::try_from(old_invulnerables); match invulnerables_maybe { - Ok(invulnerables) => Invulnerables::::set(invulnerables), + Ok(invulnerables) => Invulnerables::::set(invulnerables.into()), Err(_) => log!(warn, "Migration failed for Invulnerables from v15 to v16."), } @@ -122,8 +122,7 @@ pub mod v16 { use sp_staking::offence::OffenceSeverity; #[frame_support::storage_alias] - pub(crate) type Invulnerables = - StorageValue, Vec<::AccountId>, ValueQuery>; + pub(crate) type Invulnerables = StorageValue, Vec, ValueQuery>; #[derive(PartialEq, Encode, Decode, RuntimeDebug, TypeInfo)] pub struct EraRewardPoints { From cbfd4a5443afb6e57bd30aab58aed2acf90c4b9f Mon Sep 17 00:00:00 2001 From: giuseppere Date: Tue, 26 Nov 2024 11:09:28 +0100 Subject: [PATCH 019/101] Undo migrations change --- substrate/frame/staking/src/migrations.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/substrate/frame/staking/src/migrations.rs b/substrate/frame/staking/src/migrations.rs index 1b15d4adca37..e7240909fcb3 100644 --- a/substrate/frame/staking/src/migrations.rs +++ b/substrate/frame/staking/src/migrations.rs @@ -79,8 +79,8 @@ pub mod v17 { // BoundedVec with MaxWinners limit, this should always work let invulnerables_maybe = BoundedVec::try_from(old_invulnerables); match invulnerables_maybe { - Ok(invulnerables) => Invulnerables::::set(invulnerables.into()), - Err(_) => log!(warn, "Migration failed for Invulnerables from v15 to v16."), + Ok(invulnerables) => Invulnerables::::set(invulnerables), + Err(_) => log!(warn, "Migration failed for Invulnerables from v16 to v17."), } for (era_index, era_rewards) in v16::ErasRewardPoints::::iter() { @@ -96,7 +96,7 @@ pub mod v17 { }; ErasRewardPoints::::insert(era_index, bounded_era_rewards); }, - Err(_) => log!(warn, "Migration failed for ErasRewardPoints from v15 to v16."), + Err(_) => log!(warn, "Migration failed for ErasRewardPoints from v16 to v17."), } } @@ -122,7 +122,8 @@ pub mod v16 { use sp_staking::offence::OffenceSeverity; #[frame_support::storage_alias] - pub(crate) type Invulnerables = StorageValue, Vec, ValueQuery>; + pub(crate) type Invulnerables = + StorageValue, Vec<::AccountId>, ValueQuery>; #[derive(PartialEq, Encode, Decode, RuntimeDebug, TypeInfo)] pub struct EraRewardPoints { From 9ca25a16a5f5fc0b0760dc2d8e4ac00a3600a7d4 Mon Sep 17 00:00:00 2001 From: giuseppere Date: Tue, 26 Nov 2024 11:31:27 +0100 Subject: [PATCH 020/101] debug --- substrate/frame/staking/src/migrations.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/substrate/frame/staking/src/migrations.rs b/substrate/frame/staking/src/migrations.rs index e7240909fcb3..1b27b85e76a8 100644 --- a/substrate/frame/staking/src/migrations.rs +++ b/substrate/frame/staking/src/migrations.rs @@ -76,11 +76,16 @@ pub mod v17 { } let old_invulnerables = v16::Invulnerables::::get(); + let old_invulnerables_len = old_invulnerables.len(); // BoundedVec with MaxWinners limit, this should always work let invulnerables_maybe = BoundedVec::try_from(old_invulnerables); match invulnerables_maybe { Ok(invulnerables) => Invulnerables::::set(invulnerables), - Err(_) => log!(warn, "Migration failed for Invulnerables from v16 to v17."), + Err(_) => log!( + warn, + "Migration failed for Invulnerables from v16 to v17: {} old invulnerables may get lost.", + old_invulnerables_len, + ), } for (era_index, era_rewards) in v16::ErasRewardPoints::::iter() { From 10e7295d81c4287aef4bbb92d4276ddda56ed099 Mon Sep 17 00:00:00 2001 From: giuseppere Date: Tue, 26 Nov 2024 12:42:46 +0100 Subject: [PATCH 021/101] Increase `MaxInvulnerables` to 20 + fix migrations msg --- polkadot/runtime/test-runtime/src/lib.rs | 2 +- polkadot/runtime/westend/src/lib.rs | 2 +- substrate/bin/node/runtime/src/lib.rs | 2 +- substrate/frame/staking/src/migrations.rs | 28 +++++++++++++++-------- substrate/frame/staking/src/pallet/mod.rs | 2 +- 5 files changed, 23 insertions(+), 13 deletions(-) diff --git a/polkadot/runtime/test-runtime/src/lib.rs b/polkadot/runtime/test-runtime/src/lib.rs index 858240b81e8c..e7ed4d54a654 100644 --- a/polkadot/runtime/test-runtime/src/lib.rs +++ b/polkadot/runtime/test-runtime/src/lib.rs @@ -396,7 +396,7 @@ impl pallet_staking::Config for Runtime { type EventListeners = (); type WeightInfo = (); type DisablingStrategy = pallet_staking::UpToLimitWithReEnablingDisablingStrategy; - type MaxInvulnerables = ConstU32<4>; + type MaxInvulnerables = ConstU32<20>; } parameter_types! { diff --git a/polkadot/runtime/westend/src/lib.rs b/polkadot/runtime/westend/src/lib.rs index 3bd3d8bffe1b..8b7863cab7b3 100644 --- a/polkadot/runtime/westend/src/lib.rs +++ b/polkadot/runtime/westend/src/lib.rs @@ -756,7 +756,7 @@ impl pallet_staking::Config for Runtime { type EventListeners = (NominationPools, DelegatedStaking); type WeightInfo = weights::pallet_staking::WeightInfo; type DisablingStrategy = pallet_staking::UpToLimitWithReEnablingDisablingStrategy; - type MaxInvulnerables = frame_support::traits::ConstU32<4>; + type MaxInvulnerables = frame_support::traits::ConstU32<20>; } impl pallet_fast_unstake::Config for Runtime { diff --git a/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs index f1689a11b2a9..8adeed309620 100644 --- a/substrate/bin/node/runtime/src/lib.rs +++ b/substrate/bin/node/runtime/src/lib.rs @@ -745,7 +745,7 @@ impl pallet_staking::Config for Runtime { type WeightInfo = pallet_staking::weights::SubstrateWeight; type BenchmarkingConfig = StakingBenchmarkingConfig; type DisablingStrategy = pallet_staking::UpToLimitWithReEnablingDisablingStrategy; - type MaxInvulnerables = ConstU32<4>; + type MaxInvulnerables = ConstU32<20>; } impl pallet_fast_unstake::Config for Runtime { diff --git a/substrate/frame/staking/src/migrations.rs b/substrate/frame/staking/src/migrations.rs index 1b27b85e76a8..ee489c6b4d26 100644 --- a/substrate/frame/staking/src/migrations.rs +++ b/substrate/frame/staking/src/migrations.rs @@ -67,25 +67,28 @@ pub mod v17 { pub struct VersionUncheckedMigrateV16ToV17(core::marker::PhantomData); impl UncheckedOnRuntimeUpgrade for VersionUncheckedMigrateV16ToV17 { fn on_runtime_upgrade() -> Weight { + let mut migration_errors = false; + let old_disabled_validators = v16::DisabledValidators::::get(); // BoundedVec with MaxWinners limit, this should always work let disabled_validators_maybe = BoundedVec::try_from(old_disabled_validators); match disabled_validators_maybe { Ok(disabled_validators) => DisabledValidators::::set(disabled_validators), - Err(_) => log!(warn, "Migration failed for DisabledValidators from v16 to v17."), + Err(_) => { + log!(warn, "Migration failed for DisabledValidators from v16 to v17."); + migration_errors = true; + }, } let old_invulnerables = v16::Invulnerables::::get(); - let old_invulnerables_len = old_invulnerables.len(); // BoundedVec with MaxWinners limit, this should always work let invulnerables_maybe = BoundedVec::try_from(old_invulnerables); match invulnerables_maybe { Ok(invulnerables) => Invulnerables::::set(invulnerables), - Err(_) => log!( - warn, - "Migration failed for Invulnerables from v16 to v17: {} old invulnerables may get lost.", - old_invulnerables_len, - ), + Err(_) => { + log!(warn, "Migration failed for Invulnerables from v16 to v17."); + migration_errors = true; + }, } for (era_index, era_rewards) in v16::ErasRewardPoints::::iter() { @@ -101,11 +104,18 @@ pub mod v17 { }; ErasRewardPoints::::insert(era_index, bounded_era_rewards); }, - Err(_) => log!(warn, "Migration failed for ErasRewardPoints from v16 to v17."), + Err(_) => { + log!(warn, "Migration failed for ErasRewardPoints from v16 to v17."); + migration_errors = true; + }, } } - log!(info, "v17 applied successfully."); + if migration_errors { + log!(warn, "v17 applied with some errors."); + } else { + log!(info, "v17 applied successfully."); + } T::DbWeight::get().reads_writes(1, 1) } } diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs index cd3773fb8e29..77c21ac01a6f 100644 --- a/substrate/frame/staking/src/pallet/mod.rs +++ b/substrate/frame/staking/src/pallet/mod.rs @@ -347,7 +347,7 @@ pub mod pallet { type MaxControllersInDeprecationBatch = ConstU32<100>; type EventListeners = (); type DisablingStrategy = crate::UpToLimitDisablingStrategy; - type MaxInvulnerables = ConstU32<4>; + type MaxInvulnerables = ConstU32<20>; #[cfg(feature = "std")] type BenchmarkingConfig = crate::TestBenchmarkingConfig; type WeightInfo = (); From b3186b1f49eaa0083be20550e22ae20d90be87a0 Mon Sep 17 00:00:00 2001 From: giuseppere Date: Tue, 26 Nov 2024 13:07:54 +0100 Subject: [PATCH 022/101] fix - `MaxInvulnerables` = 20 --- substrate/frame/staking/src/mock.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrate/frame/staking/src/mock.rs b/substrate/frame/staking/src/mock.rs index 7e4ef0ca41d5..22c1f52e3deb 100644 --- a/substrate/frame/staking/src/mock.rs +++ b/substrate/frame/staking/src/mock.rs @@ -287,7 +287,7 @@ impl crate::pallet::pallet::Config for Test { type EventListeners = EventListenerMock; type DisablingStrategy = pallet_staking::UpToLimitWithReEnablingDisablingStrategy; - type MaxInvulnerables = ConstU32<4>; + type MaxInvulnerables = ConstU32<20>; } pub struct WeightedNominationsQuota; From 336137ae0cec9c6ea5ea3e461d2c4f6427a7a5b2 Mon Sep 17 00:00:00 2001 From: giuseppere Date: Tue, 26 Nov 2024 14:47:18 +0100 Subject: [PATCH 023/101] Fix tests --- substrate/frame/staking/src/tests.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index 591d794a4580..5e795ebb2b51 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -2406,7 +2406,7 @@ fn add_reward_points_fns_works() { Pallet::::reward_by_ids(vec![(21, 1), (11, 1), (11, 1)]); let eras_reward_points = ErasRewardPoints::::get(active_era()); - assert_eq!(eras_reward_points.total, 40); + assert_eq!(eras_reward_points.total, 6); assert_eq!(eras_reward_points.individual.get(&11), Some(&4)); assert_eq!(eras_reward_points.individual.get(&21), Some(&2)); assert_eq!(eras_reward_points.individual.keys().cloned().collect::>(), [11, 21]); From c1911e156ce97157d81b13d398965bb1d23cc8b3 Mon Sep 17 00:00:00 2001 From: giuseppere Date: Tue, 26 Nov 2024 14:49:44 +0100 Subject: [PATCH 024/101] Fix impl --- substrate/frame/staking/src/pallet/impls.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs index 68f8aa3dc336..576af05a2ed7 100644 --- a/substrate/frame/staking/src/pallet/impls.rs +++ b/substrate/frame/staking/src/pallet/impls.rs @@ -849,7 +849,10 @@ impl Pallet { >::mutate(active_era.index, |era_rewards| { for (validator, points) in validators_points.into_iter() { match era_rewards.individual.get_mut(&validator) { - Some(value) => *value += points, + Some(value) => { + *value += points; + era_rewards.total += points; + }, None => { if let Ok(_) = era_rewards.individual.try_insert(validator.clone(), points) From 2ac794eb4cca4515d563d23dabb7cd72dde59134 Mon Sep 17 00:00:00 2001 From: giuseppere Date: Tue, 26 Nov 2024 15:20:26 +0100 Subject: [PATCH 025/101] Fix `Invulnerables` limit in benchmarking --- substrate/frame/staking/src/benchmarking.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/substrate/frame/staking/src/benchmarking.rs b/substrate/frame/staking/src/benchmarking.rs index 3da40816ba5f..b8593cf24aa0 100644 --- a/substrate/frame/staking/src/benchmarking.rs +++ b/substrate/frame/staking/src/benchmarking.rs @@ -608,8 +608,8 @@ mod benchmarks { } #[benchmark] - // Worst case scenario, the list of invulnerables is very long. - fn set_invulnerables(v: Linear<0, { MaxValidators::::get() }>) { + // Worst case scenario according to the invulnerables limit. + fn set_invulnerables(v: Linear<0, { T::MaxExposurePageSize::get() }>) { let mut invulnerables = Vec::new(); for i in 0..v { invulnerables.push(account("invulnerable", i, SEED)); From 583e46d0b5775bcf0ecbc4f5a4aebeb0487c57de Mon Sep 17 00:00:00 2001 From: giuseppere Date: Tue, 26 Nov 2024 17:46:28 +0100 Subject: [PATCH 026/101] Bound `ExposurePage.others` with `MaxExposurePageSize` --- substrate/frame/staking/src/lib.rs | 36 +++++++++----- substrate/frame/staking/src/migrations.rs | 48 ++++++++++++++++++- substrate/frame/staking/src/pallet/mod.rs | 7 +-- substrate/frame/staking/src/tests.rs | 6 +-- substrate/primitives/staking/src/lib.rs | 58 ++++++++++++++--------- 5 files changed, 111 insertions(+), 44 deletions(-) diff --git a/substrate/frame/staking/src/lib.rs b/substrate/frame/staking/src/lib.rs index 44050b060f26..e82e4f8722d7 100644 --- a/substrate/frame/staking/src/lib.rs +++ b/substrate/frame/staking/src/lib.rs @@ -743,25 +743,35 @@ pub struct Nominations { /// /// 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)] -pub struct PagedExposure { +#[derive(Encode, Decode, RuntimeDebug, TypeInfo, PartialEq, Eq, MaxEncodedLen)] +pub struct PagedExposure< + AccountId, + Balance: HasCompact + MaxEncodedLen, + MaxExposurePageSize: Get, +> { exposure_metadata: PagedExposureMetadata, - exposure_page: ExposurePage, + exposure_page: ExposurePage, } -impl - PagedExposure +impl< + AccountId, + Balance: HasCompact + Copy + AtLeast32BitUnsigned + MaxEncodedLen, + MaxExposurePageSize: Get, + > PagedExposure { /// Create a new instance of `PagedExposure` from legacy clipped exposures. pub fn from_clipped(exposure: Exposure) -> Self { + let old_exposures = exposure.others.len(); + let others = BoundedVec::try_from(exposure.others).unwrap_or_default(); + defensive_assert!(old_exposures == others.len(), "Too many exposures for a page"); Self { exposure_metadata: PagedExposureMetadata { total: exposure.total, own: exposure.own, - nominator_count: exposure.others.len() as u32, + nominator_count: others.len() as u32, page_count: 1, }, - exposure_page: ExposurePage { page_total: exposure.total, others: exposure.others }, + exposure_page: ExposurePage { page_total: exposure.total, others }, } } @@ -1078,7 +1088,7 @@ impl EraInfo { era: EraIndex, validator: &T::AccountId, page: Page, - ) -> Option>> { + ) -> Option, T::MaxExposurePageSize>> { let overview = >::get(&era, validator)?; // validator stake is added only in page zero @@ -1110,8 +1120,11 @@ impl EraInfo { 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()); + let nominators = + >::get((era, validator, page)).defensive_unwrap_or_default(); + for nominator_exposure in nominators.others { + others.push(nominator_exposure); + } } Exposure { total: overview.total, own: overview.own, others } @@ -1185,7 +1198,8 @@ impl EraInfo { .defensive_saturating_add((page_size as usize).defensive_saturating_sub(1)) .saturating_div(page_size as usize); - let (exposure_metadata, exposure_pages) = exposure.into_pages(page_size); + let (exposure_metadata, exposure_pages) = + exposure.into_pages::(page_size); defensive_assert!(exposure_pages.len() == expected_page_count, "unexpected page count"); >::insert(era, &validator, &exposure_metadata); diff --git a/substrate/frame/staking/src/migrations.rs b/substrate/frame/staking/src/migrations.rs index ee489c6b4d26..a45e33f14d56 100644 --- a/substrate/frame/staking/src/migrations.rs +++ b/substrate/frame/staking/src/migrations.rs @@ -21,7 +21,7 @@ use super::*; use frame_election_provider_support::{ElectionProviderBase, SortedListProvider}; use frame_support::{ migrations::VersionedMigration, - pallet_prelude::ValueQuery, + pallet_prelude::{NMapKey, OptionQuery, ValueQuery}, storage_alias, traits::{GetStorageVersion, OnRuntimeUpgrade, UncheckedOnRuntimeUpgrade}, }; @@ -111,8 +111,29 @@ pub mod v17 { } } + for ((era, validator, page), old_exposure_page) in v16::ErasStakersPaged::::iter() { + let individual_exposures_maybe = BoundedVec::try_from(old_exposure_page.others); + match individual_exposures_maybe { + Ok(individual_exposures) => { + let exposure_page = ExposurePage::< + ::AccountId, + BalanceOf, + ::MaxExposurePageSize, + > { + page_total: old_exposure_page.page_total, + others: individual_exposures, + }; + ErasStakersPaged::::insert((era, validator, page), exposure_page); + }, + Err(_) => { + log!(warn, "Migration failed for ErasStakersPaged from v16 to v17."); + migration_errors = true; + }, + } + } + if migration_errors { - log!(warn, "v17 applied with some errors."); + log!(warn, "v17 applied with some errors: state may be not coherent."); } else { log!(info, "v17 applied successfully."); } @@ -165,6 +186,29 @@ pub mod v16 { pub(crate) type DisabledValidators = StorageValue, Vec<(u32, OffenceSeverity)>, ValueQuery>; + #[derive( + PartialEq, Eq, PartialOrd, Ord, Clone, Encode, Decode, RuntimeDebug, TypeInfo, MaxEncodedLen, + )] + pub struct ExposurePage { + /// The total balance of this chunk/page. + #[codec(compact)] + pub page_total: Balance, + /// The portions of nominators stashes that are exposed. + pub others: Vec>, + } + + #[frame_support::storage_alias] + pub(crate) type ErasStakersPaged = StorageNMap< + Pallet, + ( + NMapKey, + NMapKey::AccountId>, + NMapKey, + ), + ExposurePage<::AccountId, BalanceOf>, + OptionQuery, + >; + pub struct VersionUncheckedMigrateV15ToV16(core::marker::PhantomData); impl UncheckedOnRuntimeUpgrade for VersionUncheckedMigrateV15ToV16 { #[cfg(feature = "try-runtime")] diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs index 77c21ac01a6f..6e24a1561d40 100644 --- a/substrate/frame/staking/src/pallet/mod.rs +++ b/substrate/frame/staking/src/pallet/mod.rs @@ -223,10 +223,6 @@ pub mod pallet { /// 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 - /// nominator payout. - /// /// Note: `MaxExposurePageSize` is used to bound `ClaimedRewards` and is unsafe to reduce /// without handling it in a migration. #[pallet::constant] @@ -509,7 +505,6 @@ pub mod pallet { /// /// This is cleared after [`Config::HistoryDepth`] eras. #[pallet::storage] - #[pallet::unbounded] pub type ErasStakersPaged = StorageNMap< _, ( @@ -517,7 +512,7 @@ pub mod pallet { NMapKey, NMapKey, ), - ExposurePage>, + ExposurePage, T::MaxExposurePageSize>, OptionQuery, >; diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index 5e795ebb2b51..d3b935651eee 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -6579,8 +6579,8 @@ fn can_page_exposure() { // when let (exposure_metadata, exposure_page): ( PagedExposureMetadata, - Vec>, - ) = exposure.clone().into_pages(3); + Vec>, + ) = exposure.clone().into_pages::(3); // then // 7 pages of nominators. @@ -6616,7 +6616,7 @@ fn should_retain_era_info_only_upto_history_depth() { for page in 0..3 { ErasStakersPaged::::insert( (era, &validator_stash, page), - ExposurePage { page_total: 100, others: vec![] }, + ExposurePage { page_total: 100, others: BoundedVec::new() }, ); } } diff --git a/substrate/primitives/staking/src/lib.rs b/substrate/primitives/staking/src/lib.rs index 17010a8907fc..87c629b5494c 100644 --- a/substrate/primitives/staking/src/lib.rs +++ b/substrate/primitives/staking/src/lib.rs @@ -28,8 +28,8 @@ use codec::{Decode, Encode, FullCodec, HasCompact, MaxEncodedLen}; use core::ops::Sub; use scale_info::TypeInfo; use sp_runtime::{ - traits::{AtLeast32BitUnsigned, Zero}, - DispatchError, DispatchResult, Perbill, RuntimeDebug, Saturating, + traits::{AtLeast32BitUnsigned, Get, Zero}, + BoundedVec, DispatchError, DispatchResult, Perbill, RuntimeDebug, Saturating, }; pub mod offence; @@ -346,8 +346,10 @@ pub trait StakingUnchecked: StakingInterface { } /// The amount of exposure for an era that an individual nominator has (susceptible to slashing). -#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Encode, Decode, RuntimeDebug, TypeInfo)] -pub struct IndividualExposure { +#[derive( + PartialEq, Eq, PartialOrd, Ord, Clone, Encode, Decode, RuntimeDebug, TypeInfo, MaxEncodedLen, +)] +pub struct IndividualExposure { /// The stash account of the nominator in question. pub who: AccountId, /// Amount of funds exposed. @@ -357,7 +359,7 @@ pub struct IndividualExposure { /// A snapshot of the stake backing a single validator in the system. #[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Encode, Decode, RuntimeDebug, TypeInfo)] -pub struct Exposure { +pub struct Exposure { /// The total balance backing this validator. #[codec(compact)] pub total: Balance, @@ -368,37 +370,43 @@ pub struct Exposure { pub others: Vec>, } -impl Default for Exposure { +impl Default + for Exposure +{ fn default() -> Self { Self { total: Default::default(), own: Default::default(), others: vec![] } } } -impl< - AccountId: Clone, - Balance: HasCompact + AtLeast32BitUnsigned + Copy + codec::MaxEncodedLen, - > Exposure +impl + Exposure { /// Splits an `Exposure` into `PagedExposureMetadata` and multiple chunks of /// `IndividualExposure` with each chunk having maximum of `page_size` elements. - pub fn into_pages( + pub fn into_pages( self, page_size: Page, - ) -> (PagedExposureMetadata, Vec>) { + ) -> (PagedExposureMetadata, Vec>) + where + MaxExposurePageSize: Get, + { let individual_chunks = self.others.chunks(page_size as usize); - let mut exposure_pages: Vec> = + let mut exposure_pages: Vec> = Vec::with_capacity(individual_chunks.len()); for chunk in individual_chunks { + debug_assert!(chunk.len() <= MaxExposurePageSize::get() as usize); let mut page_total: Balance = Zero::zero(); - let mut others: Vec> = - Vec::with_capacity(chunk.len()); + let mut others: BoundedVec< + IndividualExposure, + MaxExposurePageSize, + > = BoundedVec::new(); for individual in chunk.iter() { page_total.saturating_accrue(individual.value); - others.push(IndividualExposure { + let _ = others.try_push(IndividualExposure { who: individual.who.clone(), value: individual.value, - }) + }); } exposure_pages.push(ExposurePage { page_total, others }); @@ -417,18 +425,24 @@ 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 { +#[derive( + PartialEq, Eq, PartialOrd, Ord, Clone, Encode, Decode, RuntimeDebug, TypeInfo, MaxEncodedLen, +)] +pub struct ExposurePage< + AccountId, + Balance: HasCompact + MaxEncodedLen, + MaxExposurePageSize: Get, +> { /// The total balance of this chunk/page. #[codec(compact)] pub page_total: Balance, /// The portions of nominators stashes that are exposed. - pub others: Vec>, + pub others: BoundedVec, MaxExposurePageSize>, } -impl Default for ExposurePage { +impl> Default for ExposurePage { fn default() -> Self { - ExposurePage { page_total: Default::default(), others: vec![] } + ExposurePage { page_total: Default::default(), others: BoundedVec::new() } } } From 9e82b85c8d7288de93ec83038fc955a18752048f Mon Sep 17 00:00:00 2001 From: giuseppere Date: Wed, 27 Nov 2024 16:44:48 +0100 Subject: [PATCH 027/101] fix `TypeInfo` error --- substrate/primitives/staking/src/lib.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/substrate/primitives/staking/src/lib.rs b/substrate/primitives/staking/src/lib.rs index 87c629b5494c..7c1b8e75eede 100644 --- a/substrate/primitives/staking/src/lib.rs +++ b/substrate/primitives/staking/src/lib.rs @@ -428,6 +428,7 @@ impl> Default for Exposu Default, MaxEncodedLen, )] -pub struct PagedExposureMetadata { +pub struct PagedExposureMetadata { /// The total balance backing this validator. #[codec(compact)] pub total: Balance, From 1db7f395a68bd423b9b34cce8b2f94951746d7e7 Mon Sep 17 00:00:00 2001 From: giuseppere Date: Wed, 27 Nov 2024 16:48:11 +0100 Subject: [PATCH 028/101] fix benchmarking limit --- substrate/frame/staking/src/benchmarking.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrate/frame/staking/src/benchmarking.rs b/substrate/frame/staking/src/benchmarking.rs index b8593cf24aa0..4d7725e6ad3b 100644 --- a/substrate/frame/staking/src/benchmarking.rs +++ b/substrate/frame/staking/src/benchmarking.rs @@ -609,7 +609,7 @@ mod benchmarks { #[benchmark] // Worst case scenario according to the invulnerables limit. - fn set_invulnerables(v: Linear<0, { T::MaxExposurePageSize::get() }>) { + fn set_invulnerables(v: Linear<0, { T::MaxInvulnerables::get() }>) { let mut invulnerables = Vec::new(); for i in 0..v { invulnerables.push(account("invulnerable", i, SEED)); From e030506d8e266122bcbdf32673b2f891b21fc036 Mon Sep 17 00:00:00 2001 From: giuseppere Date: Wed, 27 Nov 2024 18:24:51 +0100 Subject: [PATCH 029/101] bound `BondedEras` Vec --- polkadot/runtime/test-runtime/src/lib.rs | 2 ++ polkadot/runtime/westend/src/lib.rs | 2 ++ substrate/bin/node/runtime/src/lib.rs | 2 ++ substrate/frame/staking/src/lib.rs | 10 ++++------ substrate/frame/staking/src/mock.rs | 1 + substrate/frame/staking/src/pallet/impls.rs | 5 +++-- substrate/frame/staking/src/pallet/mod.rs | 14 +++++++++++--- 7 files changed, 25 insertions(+), 11 deletions(-) diff --git a/polkadot/runtime/test-runtime/src/lib.rs b/polkadot/runtime/test-runtime/src/lib.rs index e7ed4d54a654..ceaa0f9cb540 100644 --- a/polkadot/runtime/test-runtime/src/lib.rs +++ b/polkadot/runtime/test-runtime/src/lib.rs @@ -340,6 +340,7 @@ parameter_types! { pub storage SessionsPerEra: SessionIndex = 6; // 28 eras for unbonding (7 days). pub storage BondingDuration: sp_staking::EraIndex = 28; + pub storage MaxBondedEras: u32 = (BondingDuration::get() as u32) + 1; // 27 eras in which slashes can be cancelled (a bit less than 7 days). pub storage SlashDeferDuration: sp_staking::EraIndex = 27; pub const RewardCurve: &'static PiecewiseLinear<'static> = &REWARD_CURVE; @@ -376,6 +377,7 @@ impl pallet_staking::Config for Runtime { type Reward = (); type SessionsPerEra = SessionsPerEra; type BondingDuration = BondingDuration; + type MaxBondedEras = MaxBondedEras; type SlashDeferDuration = SlashDeferDuration; type AdminOrigin = frame_system::EnsureNever<()>; type SessionInterface = Self; diff --git a/polkadot/runtime/westend/src/lib.rs b/polkadot/runtime/westend/src/lib.rs index 8b7863cab7b3..b92810a7ef51 100644 --- a/polkadot/runtime/westend/src/lib.rs +++ b/polkadot/runtime/westend/src/lib.rs @@ -716,6 +716,7 @@ parameter_types! { pub const SessionsPerEra: SessionIndex = prod_or_fast!(6, 1); // 2 eras for unbonding (12 hours). pub const BondingDuration: sp_staking::EraIndex = 2; + pub const MaxBondedEras: u32 = (BondingDuration::get() as u32) + 1; // 1 era in which slashes can be cancelled (6 hours). pub const SlashDeferDuration: sp_staking::EraIndex = 1; pub const MaxExposurePageSize: u32 = 64; @@ -738,6 +739,7 @@ impl pallet_staking::Config for Runtime { type Reward = (); type SessionsPerEra = SessionsPerEra; type BondingDuration = BondingDuration; + type MaxBondedEras = MaxBondedEras; type SlashDeferDuration = SlashDeferDuration; type AdminOrigin = EitherOf, StakingAdmin>; type SessionInterface = Self; diff --git a/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs index 8adeed309620..624c23478b19 100644 --- a/substrate/bin/node/runtime/src/lib.rs +++ b/substrate/bin/node/runtime/src/lib.rs @@ -694,6 +694,7 @@ pallet_staking_reward_curve::build! { parameter_types! { pub const SessionsPerEra: sp_staking::SessionIndex = 6; pub const BondingDuration: sp_staking::EraIndex = 24 * 28; + pub const MaxBondedEras: u32 = (BondingDuration::get() as u32) + 1; pub const SlashDeferDuration: sp_staking::EraIndex = 24 * 7; // 1/4 the bonding duration. pub const RewardCurve: &'static PiecewiseLinear<'static> = &REWARD_CURVE; pub const MaxNominators: u32 = 64; @@ -722,6 +723,7 @@ impl pallet_staking::Config for Runtime { type Reward = (); // rewards are minted from the void type SessionsPerEra = SessionsPerEra; type BondingDuration = BondingDuration; + type MaxBondedEras = MaxBondedEras; type SlashDeferDuration = SlashDeferDuration; /// A super-majority of the council can cancel the slash. type AdminOrigin = EitherOfDiverse< diff --git a/substrate/frame/staking/src/lib.rs b/substrate/frame/staking/src/lib.rs index e82e4f8722d7..0e3fc53cbb7c 100644 --- a/substrate/frame/staking/src/lib.rs +++ b/substrate/frame/staking/src/lib.rs @@ -386,17 +386,15 @@ pub struct ActiveEraInfo { /// /// This points will be used to reward validators and their respective nominators. #[derive(PartialEq, Encode, Decode, RuntimeDebug, TypeInfo, MaxEncodedLen)] -#[scale_info(skip_type_params(MaxActiveValidators))] -pub struct EraRewardPoints> { +#[scale_info(skip_type_params(MaxWinners))] +pub struct EraRewardPoints> { /// Total number of points. Equals the sum of reward points for each validator. pub total: RewardPoint, /// The reward points earned by a given validator. - pub individual: BoundedBTreeMap, + pub individual: BoundedBTreeMap, } -impl> Default - for EraRewardPoints -{ +impl> Default for EraRewardPoints { fn default() -> Self { EraRewardPoints { total: Default::default(), individual: BoundedBTreeMap::new() } } diff --git a/substrate/frame/staking/src/mock.rs b/substrate/frame/staking/src/mock.rs index 22c1f52e3deb..dd439b629c48 100644 --- a/substrate/frame/staking/src/mock.rs +++ b/substrate/frame/staking/src/mock.rs @@ -177,6 +177,7 @@ pallet_staking_reward_curve::build! { } parameter_types! { pub const BondingDuration: EraIndex = 3; + pub const MaxBondedEras: u32 = (BondingDuration::get() as u32) + 1; pub const RewardCurve: &'static PiecewiseLinear<'static> = &I_NPOS; } diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs index 576af05a2ed7..dae0d9d0aaa4 100644 --- a/substrate/frame/staking/src/pallet/impls.rs +++ b/substrate/frame/staking/src/pallet/impls.rs @@ -541,8 +541,6 @@ impl Pallet { let bonding_duration = T::BondingDuration::get(); BondedEras::::mutate(|bonded| { - bonded.push((active_era, start_session)); - if active_era > bonding_duration { let first_kept = active_era.defensive_saturating_sub(bonding_duration); @@ -559,6 +557,9 @@ impl Pallet { T::SessionInterface::prune_historical_up_to(first_session); } } + + debug_assert!((bonded.len() as u32) < T::MaxBondedEras::get()); + let _ = bonded.try_push((active_era, start_session)); }); Self::apply_unapplied_slashes(active_era); diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs index 6e24a1561d40..4a7a774cf2ef 100644 --- a/substrate/frame/staking/src/pallet/mod.rs +++ b/substrate/frame/staking/src/pallet/mod.rs @@ -192,6 +192,13 @@ pub mod pallet { #[pallet::constant] type BondingDuration: Get; + /// Maximum number of eras that staked funds could remain bonded for. + /// + /// Ideally, it should be `BondingDuration::get() + 1` to include all eras in the interval + /// [current_era - BondingDuration::get(), current_era]. + #[pallet::constant] + type MaxBondedEras: Get; + /// Number of eras that slashes are deferred by, after computation. /// /// This should be less than the bonding duration. Set to 0 if slashes @@ -320,6 +327,7 @@ pub mod pallet { parameter_types! { pub const SessionsPerEra: SessionIndex = 3; pub const BondingDuration: EraIndex = 3; + pub const MaxBondedEras: u32 = (BondingDuration::get() as u32) + 1; } #[frame_support::register_default_impl(TestDefaultConfig)] @@ -335,6 +343,7 @@ pub mod pallet { type Reward = (); type SessionsPerEra = SessionsPerEra; type BondingDuration = BondingDuration; + type MaxBondedEras = MaxBondedEras; type SlashDeferDuration = (); type SessionInterface = (); type NextNewSession = (); @@ -609,11 +618,10 @@ pub mod pallet { /// A mapping from still-bonded eras to the first session index of that era. /// /// Must contains information for eras for the range: - /// `[active_era - bounding_duration; active_era]` + /// `[active_era - bonding_duration; active_era]` #[pallet::storage] - #[pallet::unbounded] pub(crate) type BondedEras = - StorageValue<_, Vec<(EraIndex, SessionIndex)>, ValueQuery>; + StorageValue<_, BoundedVec<(EraIndex, SessionIndex), T::MaxBondedEras>, ValueQuery>; /// All slashing events on validators, mapped by era to the highest slash proportion /// and slash value of the era. From 3ab45d91c5a59a7ecf08fc420fe8c94e5e788d6d Mon Sep 17 00:00:00 2001 From: giuseppere Date: Wed, 27 Nov 2024 18:31:00 +0100 Subject: [PATCH 030/101] Add migration for `BondedEras` --- substrate/frame/staking/src/migrations.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/substrate/frame/staking/src/migrations.rs b/substrate/frame/staking/src/migrations.rs index a45e33f14d56..db60bdcb1c45 100644 --- a/substrate/frame/staking/src/migrations.rs +++ b/substrate/frame/staking/src/migrations.rs @@ -80,6 +80,17 @@ pub mod v17 { }, } + let old_bonded_eras = v16::BondedEras::::get(); + // BoundedVec with MaxBondedEras limit, this should always work + let bonded_eras_maybe = BoundedVec::try_from(old_bonded_eras); + match bonded_eras_maybe { + Ok(bonded_eras) => BondedEras::::set(bonded_eras), + Err(_) => { + log!(warn, "Migration failed for BondedEras from v16 to v17."); + migration_errors = true; + }, + } + let old_invulnerables = v16::Invulnerables::::get(); // BoundedVec with MaxWinners limit, this should always work let invulnerables_maybe = BoundedVec::try_from(old_invulnerables); @@ -161,6 +172,10 @@ pub mod v16 { pub(crate) type Invulnerables = StorageValue, Vec<::AccountId>, ValueQuery>; + #[frame_support::storage_alias] + pub(crate) type BondedEras = + StorageValue, Vec<(EraIndex, SessionIndex)>, ValueQuery>; + #[derive(PartialEq, Encode, Decode, RuntimeDebug, TypeInfo)] pub struct EraRewardPoints { pub total: u32, From a980daaa9dfa2c07ea0b0039f38ab3953a536b2d Mon Sep 17 00:00:00 2001 From: giuseppere Date: Wed, 27 Nov 2024 18:34:48 +0100 Subject: [PATCH 031/101] fix tests attempt --- substrate/frame/staking/src/tests.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index d3b935651eee..a2aa666933d4 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -4411,7 +4411,7 @@ fn test_page_count_and_size() { assert_eq!(EraInfo::::get_paged_exposure(2, &11, 3).unwrap().others().len(), 4); // now lets decrease page size even more - MaxExposurePageSize::set(5); + MaxExposurePageSize::set(20); mock::start_active_era(3); // now we expect the max 20 pages (100/5). From df8e56780a4eeafa5ea5cb6a994fcb680f0747dd Mon Sep 17 00:00:00 2001 From: giuseppere Date: Fri, 29 Nov 2024 18:18:26 +0100 Subject: [PATCH 032/101] bound `ClaimedRewards` --- polkadot/runtime/test-runtime/src/lib.rs | 1 + polkadot/runtime/westend/src/lib.rs | 1 + substrate/bin/node/runtime/src/lib.rs | 1 + substrate/frame/staking/src/lib.rs | 7 +++++-- substrate/frame/staking/src/migrations.rs | 25 +++++++++++++++++++++++ substrate/frame/staking/src/mock.rs | 1 + substrate/frame/staking/src/pallet/mod.rs | 12 +++++++++-- substrate/frame/staking/src/tests.rs | 11 +++++++--- 8 files changed, 52 insertions(+), 7 deletions(-) diff --git a/polkadot/runtime/test-runtime/src/lib.rs b/polkadot/runtime/test-runtime/src/lib.rs index ceaa0f9cb540..6e3ce1214918 100644 --- a/polkadot/runtime/test-runtime/src/lib.rs +++ b/polkadot/runtime/test-runtime/src/lib.rs @@ -399,6 +399,7 @@ impl pallet_staking::Config for Runtime { type WeightInfo = (); type DisablingStrategy = pallet_staking::UpToLimitWithReEnablingDisablingStrategy; type MaxInvulnerables = ConstU32<20>; + type MaxRewardPagesPerValidator = ConstU32<20>; } parameter_types! { diff --git a/polkadot/runtime/westend/src/lib.rs b/polkadot/runtime/westend/src/lib.rs index b92810a7ef51..5d25e8041954 100644 --- a/polkadot/runtime/westend/src/lib.rs +++ b/polkadot/runtime/westend/src/lib.rs @@ -759,6 +759,7 @@ impl pallet_staking::Config for Runtime { type WeightInfo = weights::pallet_staking::WeightInfo; type DisablingStrategy = pallet_staking::UpToLimitWithReEnablingDisablingStrategy; type MaxInvulnerables = frame_support::traits::ConstU32<20>; + type MaxRewardPagesPerValidator = frame_support::traits::ConstU32<20>; } impl pallet_fast_unstake::Config for Runtime { diff --git a/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs index 624c23478b19..001f0cf2f8a0 100644 --- a/substrate/bin/node/runtime/src/lib.rs +++ b/substrate/bin/node/runtime/src/lib.rs @@ -748,6 +748,7 @@ impl pallet_staking::Config for Runtime { type BenchmarkingConfig = StakingBenchmarkingConfig; type DisablingStrategy = pallet_staking::UpToLimitWithReEnablingDisablingStrategy; type MaxInvulnerables = ConstU32<20>; + type MaxRewardPagesPerValidator = ConstU32<20>; } impl pallet_fast_unstake::Config for Runtime { diff --git a/substrate/frame/staking/src/lib.rs b/substrate/frame/staking/src/lib.rs index 0e3fc53cbb7c..76eb7ea7a146 100644 --- a/substrate/frame/staking/src/lib.rs +++ b/substrate/frame/staking/src/lib.rs @@ -1177,8 +1177,11 @@ impl EraInfo { return } - // add page to claimed entries - claimed_pages.push(page); + // try to add page to claimed entries + if claimed_pages.try_push(page).is_err() { + defensive!("Limit reached for maximum number of pages."); + return + } ClaimedRewards::::insert(era, validator, claimed_pages); } diff --git a/substrate/frame/staking/src/migrations.rs b/substrate/frame/staking/src/migrations.rs index db60bdcb1c45..ff78ac4083a9 100644 --- a/substrate/frame/staking/src/migrations.rs +++ b/substrate/frame/staking/src/migrations.rs @@ -24,6 +24,7 @@ use frame_support::{ pallet_prelude::{NMapKey, OptionQuery, ValueQuery}, storage_alias, traits::{GetStorageVersion, OnRuntimeUpgrade, UncheckedOnRuntimeUpgrade}, + WeakBoundedVec, }; #[cfg(feature = "try-runtime")] @@ -143,6 +144,19 @@ pub mod v17 { } } + for (era, validator, old_reward_pages) in v16::ClaimedRewards::::iter() { + let reward_pages_maybe = WeakBoundedVec::try_from(old_reward_pages); + match reward_pages_maybe { + Ok(reward_pages) => { + ClaimedRewards::::insert(era, validator, reward_pages); + }, + Err(_) => { + log!(warn, "Migration failed for ClaimedRewards from v16 to v17."); + migration_errors = true; + }, + } + } + if migration_errors { log!(warn, "v17 applied with some errors: state may be not coherent."); } else { @@ -176,6 +190,17 @@ pub mod v16 { pub(crate) type BondedEras = StorageValue, Vec<(EraIndex, SessionIndex)>, ValueQuery>; + #[frame_support::storage_alias] + pub(crate) type ClaimedRewards = StorageDoubleMap< + Pallet, + Twox64Concat, + EraIndex, + Twox64Concat, + ::AccountId, + Vec, + ValueQuery, + >; + #[derive(PartialEq, Encode, Decode, RuntimeDebug, TypeInfo)] pub struct EraRewardPoints { pub total: u32, diff --git a/substrate/frame/staking/src/mock.rs b/substrate/frame/staking/src/mock.rs index dd439b629c48..629033634d86 100644 --- a/substrate/frame/staking/src/mock.rs +++ b/substrate/frame/staking/src/mock.rs @@ -289,6 +289,7 @@ impl crate::pallet::pallet::Config for Test { type DisablingStrategy = pallet_staking::UpToLimitWithReEnablingDisablingStrategy; type MaxInvulnerables = ConstU32<20>; + type MaxRewardPagesPerValidator = ConstU32<20>; } pub struct WeightedNominationsQuota; diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs index 4a7a774cf2ef..cf295715ba83 100644 --- a/substrate/frame/staking/src/pallet/mod.rs +++ b/substrate/frame/staking/src/pallet/mod.rs @@ -235,6 +235,13 @@ pub mod pallet { #[pallet::constant] type MaxExposurePageSize: Get; + /// The maximum number of nominators reward pages per nominator. + /// + /// Note: `MaxRewardPagesPerValidator` is used to bound the number of pages in + /// `ClaimedRewards` and is unsafe to reduce without handling it in a migration. + #[pallet::constant] + type MaxRewardPagesPerValidator: Get; + /// Something that provides a best-effort sorted list of voters aka electing nominators, /// used for NPoS election. /// @@ -353,6 +360,7 @@ pub mod pallet { type EventListeners = (); type DisablingStrategy = crate::UpToLimitDisablingStrategy; type MaxInvulnerables = ConstU32<20>; + type MaxRewardPagesPerValidator = ConstU32<20>; #[cfg(feature = "std")] type BenchmarkingConfig = crate::TestBenchmarkingConfig; type WeightInfo = (); @@ -539,7 +547,7 @@ pub mod pallet { EraIndex, Twox64Concat, T::AccountId, - Vec, + WeakBoundedVec, ValueQuery, >; @@ -1012,7 +1020,7 @@ pub mod pallet { pub fn claimed_rewards( era_index: EncodeLikeEraIndex, account_id: EncodeLikeAccountId, - ) -> Vec + ) -> WeakBoundedVec where EncodeLikeEraIndex: codec::EncodeLike, EncodeLikeAccountId: codec::EncodeLike, diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index a2aa666933d4..334795dfec98 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -235,6 +235,9 @@ fn basic_setup_works() { // New era is not being forced assert_eq!(ForceEra::::get(), Forcing::NotForcing); + + // MaxBondedEras must be coherent with BondingDuration + assert_eq!(MaxBondedEras::get(), (BondingDuration::get() as u32) + 1); }); } @@ -6612,7 +6615,9 @@ fn should_retain_era_info_only_upto_history_depth() { let validator_stash = 10; for era in 0..4 { - ClaimedRewards::::insert(era, &validator_stash, vec![0, 1, 2]); + let rewards = WeakBoundedVec::try_from(vec![0, 1, 2]); + assert!(rewards.is_ok()); + ClaimedRewards::::insert(era, &validator_stash, rewards.unwrap()); for page in 0..3 { ErasStakersPaged::::insert( (era, &validator_stash, page), @@ -8507,7 +8512,7 @@ mod getters { mock::{self}, pallet::pallet::{Invulnerables, MinimumValidatorCount, ValidatorCount}, slashing, - tests::{MaxWinners, Staking, Test}, + tests::{MaxWinners, Staking, Test, WeakBoundedVec}, ActiveEra, ActiveEraInfo, BalanceOf, BoundedBTreeMap, BoundedVec, CanceledSlashPayout, ClaimedRewards, CurrentEra, CurrentPlannedSession, EraRewardPoints, ErasRewardPoints, ErasStartSessionIndex, ErasTotalStake, ErasValidatorPrefs, ErasValidatorReward, ForceEra, @@ -8656,7 +8661,7 @@ mod getters { // given let era: EraIndex = 12; let account_id: mock::AccountId = 1; - let rewards = Vec::::new(); + let rewards = WeakBoundedVec::force_from(vec![], None); ClaimedRewards::::insert(era, account_id, rewards.clone()); // when From c066632bb4e302c191cbefbdd6a56e5c363f07f6 Mon Sep 17 00:00:00 2001 From: giuseppere Date: Fri, 29 Nov 2024 18:31:09 +0100 Subject: [PATCH 033/101] Use `WeakBoundedVec` for `EraStakersPaged` paged exposures --- substrate/frame/staking/src/pallet/mod.rs | 2 +- substrate/primitives/staking/src/lib.rs | 13 ++++++++----- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs index cf295715ba83..947f4dd3c3c8 100644 --- a/substrate/frame/staking/src/pallet/mod.rs +++ b/substrate/frame/staking/src/pallet/mod.rs @@ -684,7 +684,7 @@ pub mod pallet { #[pallet::storage] pub type DisabledValidators = StorageValue< _, - BoundedVec< + WeakBoundedVec< (u32, OffenceSeverity), ::MaxWinners, >, diff --git a/substrate/primitives/staking/src/lib.rs b/substrate/primitives/staking/src/lib.rs index 7c1b8e75eede..fe7895ab5bc3 100644 --- a/substrate/primitives/staking/src/lib.rs +++ b/substrate/primitives/staking/src/lib.rs @@ -29,7 +29,7 @@ use core::ops::Sub; use scale_info::TypeInfo; use sp_runtime::{ traits::{AtLeast32BitUnsigned, Get, Zero}, - BoundedVec, DispatchError, DispatchResult, Perbill, RuntimeDebug, Saturating, + DispatchError, DispatchResult, Perbill, RuntimeDebug, Saturating, WeakBoundedVec, }; pub mod offence; @@ -397,10 +397,10 @@ impl, MaxExposurePageSize, - > = BoundedVec::new(); + > = WeakBoundedVec::force_from(vec![], None); for individual in chunk.iter() { page_total.saturating_accrue(individual.value); let _ = others.try_push(IndividualExposure { @@ -438,12 +438,15 @@ pub struct ExposurePage< #[codec(compact)] pub page_total: Balance, /// The portions of nominators stashes that are exposed. - pub others: BoundedVec, MaxExposurePageSize>, + pub others: WeakBoundedVec, MaxExposurePageSize>, } impl> Default for ExposurePage { fn default() -> Self { - ExposurePage { page_total: Default::default(), others: BoundedVec::new() } + ExposurePage { + page_total: Default::default(), + others: WeakBoundedVec::force_from(vec![], None), + } } } From 686b6b3da13fe10c83bc3bedbf4cf9ac047df5a8 Mon Sep 17 00:00:00 2001 From: giuseppere Date: Fri, 29 Nov 2024 18:43:58 +0100 Subject: [PATCH 034/101] Turn more `BoundedVec` into `WeakBoundedVec` --- substrate/frame/staking/src/lib.rs | 2 +- substrate/frame/staking/src/migrations.rs | 4 ++-- substrate/frame/staking/src/pallet/mod.rs | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/substrate/frame/staking/src/lib.rs b/substrate/frame/staking/src/lib.rs index 76eb7ea7a146..6c8edd505bd1 100644 --- a/substrate/frame/staking/src/lib.rs +++ b/substrate/frame/staking/src/lib.rs @@ -760,7 +760,7 @@ impl< /// Create a new instance of `PagedExposure` from legacy clipped exposures. pub fn from_clipped(exposure: Exposure) -> Self { let old_exposures = exposure.others.len(); - let others = BoundedVec::try_from(exposure.others).unwrap_or_default(); + let others = WeakBoundedVec::try_from(exposure.others).unwrap_or_default(); defensive_assert!(old_exposures == others.len(), "Too many exposures for a page"); Self { exposure_metadata: PagedExposureMetadata { diff --git a/substrate/frame/staking/src/migrations.rs b/substrate/frame/staking/src/migrations.rs index ff78ac4083a9..57b04abaff45 100644 --- a/substrate/frame/staking/src/migrations.rs +++ b/substrate/frame/staking/src/migrations.rs @@ -72,7 +72,7 @@ pub mod v17 { let old_disabled_validators = v16::DisabledValidators::::get(); // BoundedVec with MaxWinners limit, this should always work - let disabled_validators_maybe = BoundedVec::try_from(old_disabled_validators); + let disabled_validators_maybe = WeakBoundedVec::try_from(old_disabled_validators); match disabled_validators_maybe { Ok(disabled_validators) => DisabledValidators::::set(disabled_validators), Err(_) => { @@ -124,7 +124,7 @@ pub mod v17 { } for ((era, validator, page), old_exposure_page) in v16::ErasStakersPaged::::iter() { - let individual_exposures_maybe = BoundedVec::try_from(old_exposure_page.others); + let individual_exposures_maybe = WeakBoundedVec::try_from(old_exposure_page.others); match individual_exposures_maybe { Ok(individual_exposures) => { let exposure_page = ExposurePage::< diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs index 947f4dd3c3c8..80f2978c5bf4 100644 --- a/substrate/frame/staking/src/pallet/mod.rs +++ b/substrate/frame/staking/src/pallet/mod.rs @@ -702,7 +702,7 @@ pub mod pallet { pub struct GenesisConfig { pub validator_count: u32, pub minimum_validator_count: u32, - pub invulnerables: Vec, + pub invulnerables: BoundedVec, pub force_era: Forcing, pub slash_reward_fraction: Perbill, pub canceled_payout: BalanceOf, @@ -723,7 +723,7 @@ pub mod pallet { self.invulnerables.len() as u32 <= T::MaxInvulnerables::get(), "Too many invulnerable validators at genesis." ); - >::put(BoundedVec::truncate_from(self.invulnerables.clone())); + >::put(&self.invulnerables); ForceEra::::put(self.force_era); CanceledSlashPayout::::put(self.canceled_payout); SlashRewardFraction::::put(self.slash_reward_fraction); From ca881ac5eb1951eb7dd736f7aa2970e69b8a6527 Mon Sep 17 00:00:00 2001 From: giuseppere Date: Mon, 2 Dec 2024 17:13:02 +0100 Subject: [PATCH 035/101] add import --- substrate/frame/staking/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrate/frame/staking/src/lib.rs b/substrate/frame/staking/src/lib.rs index 6c8edd505bd1..33f269eea93a 100644 --- a/substrate/frame/staking/src/lib.rs +++ b/substrate/frame/staking/src/lib.rs @@ -315,7 +315,7 @@ use frame_support::{ ConstU32, Currency, Defensive, DefensiveMax, DefensiveSaturating, Get, LockIdentifier, }, weights::Weight, - BoundedVec, CloneNoBound, EqNoBound, PartialEqNoBound, RuntimeDebugNoBound, + BoundedVec, CloneNoBound, EqNoBound, PartialEqNoBound, RuntimeDebugNoBound, WeakBoundedVec, }; use scale_info::TypeInfo; use sp_runtime::{ From e986264b444514a7e9f5bdcfbc47ba401946614d Mon Sep 17 00:00:00 2001 From: giuseppere Date: Mon, 2 Dec 2024 18:54:04 +0100 Subject: [PATCH 036/101] Migrate `MaxValidatorsCount` from storage to dynamic param + fixes --- polkadot/runtime/test-runtime/src/lib.rs | 1 + .../westend/src/genesis_config_presets.rs | 12 ++++-- polkadot/runtime/westend/src/lib.rs | 10 +++++ substrate/bin/node/runtime/src/lib.rs | 1 + substrate/frame/babe/src/mock.rs | 4 +- substrate/frame/beefy/src/mock.rs | 4 +- substrate/frame/delegated-staking/src/mock.rs | 4 +- substrate/frame/grandpa/src/mock.rs | 4 +- substrate/frame/root-offences/src/mock.rs | 4 +- substrate/frame/staking/src/benchmarking.rs | 5 --- substrate/frame/staking/src/migrations.rs | 5 +++ substrate/frame/staking/src/mock.rs | 1 + substrate/frame/staking/src/pallet/mod.rs | 38 ++++++++----------- substrate/frame/staking/src/tests.rs | 11 ------ 14 files changed, 52 insertions(+), 52 deletions(-) diff --git a/polkadot/runtime/test-runtime/src/lib.rs b/polkadot/runtime/test-runtime/src/lib.rs index 6e3ce1214918..f5079a683e11 100644 --- a/polkadot/runtime/test-runtime/src/lib.rs +++ b/polkadot/runtime/test-runtime/src/lib.rs @@ -400,6 +400,7 @@ impl pallet_staking::Config for Runtime { type DisablingStrategy = pallet_staking::UpToLimitWithReEnablingDisablingStrategy; type MaxInvulnerables = ConstU32<20>; type MaxRewardPagesPerValidator = ConstU32<20>; + type MaxValidatorsCount = ConstU32<300>; } parameter_types! { diff --git a/polkadot/runtime/westend/src/genesis_config_presets.rs b/polkadot/runtime/westend/src/genesis_config_presets.rs index b8f7710089e0..7a9d0b9ab964 100644 --- a/polkadot/runtime/westend/src/genesis_config_presets.rs +++ b/polkadot/runtime/westend/src/genesis_config_presets.rs @@ -33,7 +33,7 @@ use sp_consensus_grandpa::AuthorityId as GrandpaId; use sp_core::{crypto::get_public_from_string_or_panic, sr25519}; use sp_genesis_builder::PresetId; use sp_keyring::Sr25519Keyring; -use sp_runtime::Perbill; +use sp_runtime::{BoundedVec, Perbill}; use westend_runtime_constants::currency::UNITS as WND; /// Helper function to generate stash, controller and session key from seed @@ -201,7 +201,10 @@ fn westend_testnet_genesis( .iter() .map(|x| (x.0.clone(), x.0.clone(), STASH, StakerStatus::::Validator)) .collect::>(), - invulnerables: initial_authorities.iter().map(|x| x.0.clone()).collect::>(), + invulnerables: BoundedVec::try_from( + initial_authorities.iter().map(|x| x.0.clone()).collect::>() + ) + .unwrap(), force_era: Forcing::NotForcing, slash_reward_fraction: Perbill::from_percent(10), }, @@ -372,7 +375,10 @@ fn westend_staging_testnet_config_genesis() -> serde_json::Value { .iter() .map(|x| (x.0.clone(), x.0.clone(), STASH, StakerStatus::::Validator)) .collect::>(), - invulnerables: initial_authorities.iter().map(|x| x.0.clone()).collect::>(), + invulnerables: BoundedVec::try_from( + initial_authorities.iter().map(|x| x.0.clone()).collect::>() + ) + .unwrap(), force_era: Forcing::ForceNone, slash_reward_fraction: Perbill::from_percent(10), }, diff --git a/polkadot/runtime/westend/src/lib.rs b/polkadot/runtime/westend/src/lib.rs index 5d25e8041954..5096f95cda68 100644 --- a/polkadot/runtime/westend/src/lib.rs +++ b/polkadot/runtime/westend/src/lib.rs @@ -287,6 +287,14 @@ pub mod dynamic_params { #[codec(index = 4)] pub static UseAuctionSlots: bool = false; } + + #[dynamic_pallet_params] + #[codec(index = 1)] + pub mod staking { + /// Maximum number of validators allowed. + #[codec(index = 0)] + pub static MaxValidatorsCount: u32 = 300; + } } #[cfg(feature = "runtime-benchmarks")] @@ -319,6 +327,7 @@ impl EnsureOriginWithArg for DynamicParamet match key { Inflation(_) => frame_system::ensure_root(origin.clone()), + Staking(_) => frame_system::ensure_root(origin.clone()), } .map_err(|_| origin) } @@ -760,6 +769,7 @@ impl pallet_staking::Config for Runtime { type DisablingStrategy = pallet_staking::UpToLimitWithReEnablingDisablingStrategy; type MaxInvulnerables = frame_support::traits::ConstU32<20>; type MaxRewardPagesPerValidator = frame_support::traits::ConstU32<20>; + type MaxValidatorsCount = dynamic_params::staking::MaxValidatorsCount; } impl pallet_fast_unstake::Config for Runtime { diff --git a/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs index 1588c2b37ee0..1b227d30dedc 100644 --- a/substrate/bin/node/runtime/src/lib.rs +++ b/substrate/bin/node/runtime/src/lib.rs @@ -749,6 +749,7 @@ impl pallet_staking::Config for Runtime { type DisablingStrategy = pallet_staking::UpToLimitWithReEnablingDisablingStrategy; type MaxInvulnerables = ConstU32<20>; type MaxRewardPagesPerValidator = ConstU32<20>; + type MaxValidatorsCount = ConstU32<300>; } impl pallet_fast_unstake::Config for Runtime { diff --git a/substrate/frame/babe/src/mock.rs b/substrate/frame/babe/src/mock.rs index 23857470adc4..5df8ed83f7a5 100644 --- a/substrate/frame/babe/src/mock.rs +++ b/substrate/frame/babe/src/mock.rs @@ -39,7 +39,7 @@ use sp_runtime::{ impl_opaque_keys, testing::{Digest, DigestItem, Header, TestXt}, traits::{Header as _, OpaqueKeys}, - BuildStorage, Perbill, + BoundedVec, BuildStorage, Perbill, }; use sp_staking::{EraIndex, SessionIndex}; @@ -342,7 +342,7 @@ pub fn new_test_ext_raw_authorities(authorities: Vec) -> sp_io::Tes validator_count: 8, force_era: pallet_staking::Forcing::ForceNew, minimum_validator_count: 0, - invulnerables: vec![], + invulnerables: BoundedVec::new(), ..Default::default() }; diff --git a/substrate/frame/beefy/src/mock.rs b/substrate/frame/beefy/src/mock.rs index 7ae41c609180..f21c585ecce1 100644 --- a/substrate/frame/beefy/src/mock.rs +++ b/substrate/frame/beefy/src/mock.rs @@ -36,7 +36,7 @@ use sp_runtime::{ impl_opaque_keys, testing::TestXt, traits::{Header as HeaderT, OpaqueKeys}, - BuildStorage, Perbill, + BoundedVec, BuildStorage, Perbill, }; use sp_staking::{EraIndex, SessionIndex}; use sp_state_machine::BasicExternalities; @@ -303,7 +303,7 @@ impl ExtBuilder { validator_count: 2, force_era: pallet_staking::Forcing::ForceNew, minimum_validator_count: 0, - invulnerables: vec![], + invulnerables: BoundedVec::new(), ..Default::default() }; diff --git a/substrate/frame/delegated-staking/src/mock.rs b/substrate/frame/delegated-staking/src/mock.rs index 811d5739f4e9..3db6e77179fe 100644 --- a/substrate/frame/delegated-staking/src/mock.rs +++ b/substrate/frame/delegated-staking/src/mock.rs @@ -24,7 +24,7 @@ use frame_support::{ PalletId, }; -use sp_runtime::{traits::IdentityLookup, BuildStorage, Perbill}; +use sp_runtime::{traits::IdentityLookup, BoundedVec, BuildStorage, Perbill}; use frame_election_provider_support::{ bounds::{ElectionBounds, ElectionBoundsBuilder}, @@ -217,7 +217,7 @@ impl ExtBuilder { // ideal validator count validator_count: 2, minimum_validator_count: 1, - invulnerables: vec![], + invulnerables: BoundedVec::new(), slash_reward_fraction: Perbill::from_percent(10), min_nominator_bond: ExistentialDeposit::get(), min_validator_bond: ExistentialDeposit::get(), diff --git a/substrate/frame/grandpa/src/mock.rs b/substrate/frame/grandpa/src/mock.rs index 87369c23948c..38832630ebb1 100644 --- a/substrate/frame/grandpa/src/mock.rs +++ b/substrate/frame/grandpa/src/mock.rs @@ -39,7 +39,7 @@ use sp_runtime::{ impl_opaque_keys, testing::{TestXt, UintAuthorityId}, traits::OpaqueKeys, - BuildStorage, DigestItem, Perbill, + BoundedVec, BuildStorage, DigestItem, Perbill, }; use sp_staking::{EraIndex, SessionIndex}; @@ -258,7 +258,7 @@ pub fn new_test_ext_raw_authorities(authorities: AuthorityList) -> sp_io::TestEx validator_count: 8, force_era: pallet_staking::Forcing::ForceNew, minimum_validator_count: 0, - invulnerables: vec![], + invulnerables: BoundedVec::new(), ..Default::default() }; diff --git a/substrate/frame/root-offences/src/mock.rs b/substrate/frame/root-offences/src/mock.rs index a27fb36f64a6..30edd4ba1b4e 100644 --- a/substrate/frame/root-offences/src/mock.rs +++ b/substrate/frame/root-offences/src/mock.rs @@ -188,7 +188,7 @@ impl Default for ExtBuilder { Self { validator_count: 2, minimum_validator_count: 0, - invulnerables: vec![], + invulnerables: BoundedVec::new(), balance_factor: 1, } } @@ -235,7 +235,7 @@ impl ExtBuilder { stakers: stakers.clone(), validator_count: self.validator_count, minimum_validator_count: self.minimum_validator_count, - invulnerables: self.invulnerables, + invulnerables: BoundedVec::force_from(self.invulnerables), slash_reward_fraction: Perbill::from_percent(10), ..Default::default() } diff --git a/substrate/frame/staking/src/benchmarking.rs b/substrate/frame/staking/src/benchmarking.rs index 4d7725e6ad3b..100ae5965a72 100644 --- a/substrate/frame/staking/src/benchmarking.rs +++ b/substrate/frame/staking/src/benchmarking.rs @@ -1021,7 +1021,6 @@ mod benchmarks { ConfigOp::Set(BalanceOf::::max_value()), ConfigOp::Set(BalanceOf::::max_value()), ConfigOp::Set(u32::MAX), - ConfigOp::Set(u32::MAX), ConfigOp::Set(Percent::max_value()), ConfigOp::Set(Perbill::max_value()), ConfigOp::Set(Percent::max_value()), @@ -1030,7 +1029,6 @@ mod benchmarks { assert_eq!(MinNominatorBond::::get(), BalanceOf::::max_value()); assert_eq!(MinValidatorBond::::get(), BalanceOf::::max_value()); assert_eq!(MaxNominatorsCount::::get(), Some(u32::MAX)); - assert_eq!(MaxValidatorsCount::::get(), Some(u32::MAX)); assert_eq!(ChillThreshold::::get(), Some(Percent::from_percent(100))); assert_eq!(MinCommission::::get(), Perbill::from_percent(100)); assert_eq!(MaxStakedRewards::::get(), Some(Percent::from_percent(100))); @@ -1047,13 +1045,11 @@ mod benchmarks { ConfigOp::Remove, ConfigOp::Remove, ConfigOp::Remove, - ConfigOp::Remove, ); assert!(!MinNominatorBond::::exists()); assert!(!MinValidatorBond::::exists()); assert!(!MaxNominatorsCount::::exists()); - assert!(!MaxValidatorsCount::::exists()); assert!(!ChillThreshold::::exists()); assert!(!MinCommission::::exists()); assert!(!MaxStakedRewards::::exists()); @@ -1077,7 +1073,6 @@ mod benchmarks { ConfigOp::Set(BalanceOf::::max_value()), ConfigOp::Set(BalanceOf::::max_value()), ConfigOp::Set(0), - ConfigOp::Set(0), ConfigOp::Set(Percent::from_percent(0)), ConfigOp::Set(Zero::zero()), ConfigOp::Noop, diff --git a/substrate/frame/staking/src/migrations.rs b/substrate/frame/staking/src/migrations.rs index 57b04abaff45..76cd46a91167 100644 --- a/substrate/frame/staking/src/migrations.rs +++ b/substrate/frame/staking/src/migrations.rs @@ -70,6 +70,8 @@ pub mod v17 { fn on_runtime_upgrade() -> Weight { let mut migration_errors = false; + v16::MaxValidatorsCount::::kill(); + let old_disabled_validators = v16::DisabledValidators::::get(); // BoundedVec with MaxWinners limit, this should always work let disabled_validators_maybe = WeakBoundedVec::try_from(old_disabled_validators); @@ -249,6 +251,9 @@ pub mod v16 { OptionQuery, >; + #[frame_support::storage_alias] + pub(crate) type MaxValidatorsCount = StorageValue, u32, OptionQuery>; + pub struct VersionUncheckedMigrateV15ToV16(core::marker::PhantomData); impl UncheckedOnRuntimeUpgrade for VersionUncheckedMigrateV15ToV16 { #[cfg(feature = "try-runtime")] diff --git a/substrate/frame/staking/src/mock.rs b/substrate/frame/staking/src/mock.rs index 629033634d86..4cdf60204295 100644 --- a/substrate/frame/staking/src/mock.rs +++ b/substrate/frame/staking/src/mock.rs @@ -290,6 +290,7 @@ impl crate::pallet::pallet::Config for Test { pallet_staking::UpToLimitWithReEnablingDisablingStrategy; type MaxInvulnerables = ConstU32<20>; type MaxRewardPagesPerValidator = ConstU32<20>; + type MaxValidatorsCount = ConstU32<300>; } pub struct WeightedNominationsQuota; diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs index 80f2978c5bf4..a09b07018a73 100644 --- a/substrate/frame/staking/src/pallet/mod.rs +++ b/substrate/frame/staking/src/pallet/mod.rs @@ -143,6 +143,12 @@ pub mod pallet { #[pallet::no_default_bounds] type NominationsQuota: NominationsQuota>; + /// The maximum validator count before we stop allowing new validators to join. + /// + /// This is a dynamic runtime parameters, so updates do not require storage migrations. + #[pallet::constant] + type MaxValidatorsCount: Get; + /// Number of eras to keep in history. /// /// Following information is kept for eras in `[current_era - @@ -361,6 +367,7 @@ pub mod pallet { type DisablingStrategy = crate::UpToLimitDisablingStrategy; type MaxInvulnerables = ConstU32<20>; type MaxRewardPagesPerValidator = ConstU32<20>; + type MaxValidatorsCount = ConstU32<300>; #[cfg(feature = "std")] type BenchmarkingConfig = crate::TestBenchmarkingConfig; type WeightInfo = (); @@ -427,12 +434,6 @@ pub mod pallet { pub type Validators = CountedStorageMap<_, Twox64Concat, T::AccountId, ValidatorPrefs, ValueQuery>; - /// The maximum validator count before we stop allowing new validators to join. - /// - /// When this value is not set, no limits are enforced. - #[pallet::storage] - pub type MaxValidatorsCount = StorageValue<_, u32, OptionQuery>; - /// The map from nominator stash key to their nomination preferences, namely the validators that /// they wish to support. /// @@ -710,7 +711,6 @@ pub mod pallet { Vec<(T::AccountId, T::AccountId, BalanceOf, crate::StakerStatus)>, pub min_nominator_bond: BalanceOf, pub min_validator_bond: BalanceOf, - pub max_validator_count: Option, pub max_nominator_count: Option, } @@ -729,9 +729,6 @@ pub mod pallet { SlashRewardFraction::::put(self.slash_reward_fraction); MinNominatorBond::::put(self.min_nominator_bond); MinValidatorBond::::put(self.min_validator_bond); - if let Some(x) = self.max_validator_count { - MaxValidatorsCount::::put(x); - } if let Some(x) = self.max_nominator_count { MaxNominatorsCount::::put(x); } @@ -1347,12 +1344,10 @@ pub mod pallet { // If this error is reached, we need to adjust the `MinValidatorBond` and start // calling `chill_other`. Until then, we explicitly block new validators to protect // the runtime. - if let Some(max_validators) = MaxValidatorsCount::::get() { - ensure!( - Validators::::count() < max_validators, - Error::::TooManyValidators - ); - } + ensure!( + Validators::::count() < T::MaxValidatorsCount::get(), + Error::::TooManyValidators, + ); } Self::do_remove_nominator(stash); @@ -1911,7 +1906,6 @@ pub mod pallet { min_nominator_bond: ConfigOp>, min_validator_bond: ConfigOp>, max_nominator_count: ConfigOp, - max_validator_count: ConfigOp, chill_threshold: ConfigOp, min_commission: ConfigOp, max_staked_rewards: ConfigOp, @@ -1931,7 +1925,6 @@ pub mod pallet { config_op_exp!(MinNominatorBond, min_nominator_bond); config_op_exp!(MinValidatorBond, min_validator_bond); config_op_exp!(MaxNominatorsCount, max_nominator_count); - config_op_exp!(MaxValidatorsCount, max_validator_count); config_op_exp!(ChillThreshold, chill_threshold); config_op_exp!(MinCommission, min_commission); config_op_exp!(MaxStakedRewards, max_staked_rewards); @@ -1955,8 +1948,8 @@ pub mod pallet { /// /// * A `ChillThreshold` must be set and checked which defines how close to the max /// nominators or validators we must reach before users can start chilling one-another. - /// * A `MaxNominatorCount` and `MaxValidatorCount` must be set which is used to determine - /// how close we are to the threshold. + /// * A `MaxNominatorCount` must be set which is used to determine how close we are to the + /// threshold. /// * A `MinNominatorBond` and `MinValidatorBond` must be set and checked, which determines /// if this is a person that should be chilled because they have not met the threshold /// bond required. @@ -1984,7 +1977,7 @@ pub mod pallet { // // * A `ChillThreshold` is set which defines how close to the max nominators or // validators we must reach before users can start chilling one-another. - // * A `MaxNominatorCount` and `MaxValidatorCount` which is used to determine how close + // * A `MaxNominatorCount` and `MaxValidatorsCount` which is used to determine how close // we are to the threshold. // * A `MinNominatorBond` and `MinValidatorBond` which is the final condition checked to // determine this is a person that should be chilled because they have not met the @@ -2009,8 +2002,7 @@ pub mod pallet { ); MinNominatorBond::::get() } else if Validators::::contains_key(&stash) { - let max_validator_count = - MaxValidatorsCount::::get().ok_or(Error::::CannotChillOther)?; + let max_validator_count = T::MaxValidatorsCount::get(); let current_validator_count = Validators::::count(); ensure!( threshold * max_validator_count < current_validator_count, diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index 334795dfec98..8f9cb2917294 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -53,7 +53,6 @@ fn set_staking_configs_works() { ConfigOp::Set(1_500), ConfigOp::Set(2_000), ConfigOp::Set(10), - ConfigOp::Set(20), ConfigOp::Set(Percent::from_percent(75)), ConfigOp::Set(Zero::zero()), ConfigOp::Set(Zero::zero()) @@ -61,7 +60,6 @@ fn set_staking_configs_works() { assert_eq!(MinNominatorBond::::get(), 1_500); assert_eq!(MinValidatorBond::::get(), 2_000); assert_eq!(MaxNominatorsCount::::get(), Some(10)); - assert_eq!(MaxValidatorsCount::::get(), Some(20)); assert_eq!(ChillThreshold::::get(), Some(Percent::from_percent(75))); assert_eq!(MinCommission::::get(), Perbill::from_percent(0)); assert_eq!(MaxStakedRewards::::get(), Some(Percent::from_percent(0))); @@ -92,7 +90,6 @@ fn set_staking_configs_works() { assert_eq!(MinNominatorBond::::get(), 0); assert_eq!(MinValidatorBond::::get(), 0); assert_eq!(MaxNominatorsCount::::get(), None); - assert_eq!(MaxValidatorsCount::::get(), None); assert_eq!(ChillThreshold::::get(), None); assert_eq!(MinCommission::::get(), Perbill::from_percent(0)); assert_eq!(MaxStakedRewards::::get(), None); @@ -1813,7 +1810,6 @@ fn max_staked_rewards_works() { ConfigOp::Noop, ConfigOp::Noop, ConfigOp::Noop, - ConfigOp::Noop, ConfigOp::Set(Percent::from_percent(max_staked_rewards)), )); @@ -5711,7 +5707,6 @@ fn chill_other_works() { ConfigOp::Remove, ConfigOp::Remove, ConfigOp::Remove, - ConfigOp::Remove, ConfigOp::Noop, )); @@ -5731,7 +5726,6 @@ fn chill_other_works() { ConfigOp::Noop, ConfigOp::Noop, ConfigOp::Set(10), - ConfigOp::Set(10), ConfigOp::Noop, ConfigOp::Noop, ConfigOp::Noop, @@ -5753,7 +5747,6 @@ fn chill_other_works() { ConfigOp::Noop, ConfigOp::Noop, ConfigOp::Remove, - ConfigOp::Remove, ConfigOp::Noop, ConfigOp::Noop, ConfigOp::Noop, @@ -5775,7 +5768,6 @@ fn chill_other_works() { ConfigOp::Noop, ConfigOp::Noop, ConfigOp::Set(10), - ConfigOp::Set(10), ConfigOp::Set(Percent::from_percent(75)), ConfigOp::Noop, ConfigOp::Noop, @@ -5821,7 +5813,6 @@ fn capped_stakers_works() { ConfigOp::Set(10), ConfigOp::Set(10), ConfigOp::Set(max), - ConfigOp::Set(max), ConfigOp::Remove, ConfigOp::Remove, ConfigOp::Noop, @@ -5892,7 +5883,6 @@ fn capped_stakers_works() { ConfigOp::Noop, ConfigOp::Noop, ConfigOp::Remove, - ConfigOp::Remove, ConfigOp::Noop, ConfigOp::Noop, ConfigOp::Noop, @@ -5929,7 +5919,6 @@ fn min_commission_works() { ConfigOp::Remove, ConfigOp::Remove, ConfigOp::Remove, - ConfigOp::Remove, ConfigOp::Set(Perbill::from_percent(10)), ConfigOp::Noop, )); From ea5938333c03ecb123b60bda35d49f864bf20957 Mon Sep 17 00:00:00 2001 From: giuseppere Date: Mon, 2 Dec 2024 19:07:02 +0100 Subject: [PATCH 037/101] Use `MaxValidatorsCount` to bound `ErasRewardPoints` `BoundedVec` --- substrate/frame/staking/src/benchmarking.rs | 10 ++-------- substrate/frame/staking/src/lib.rs | 10 ++++++---- substrate/frame/staking/src/migrations.rs | 2 +- substrate/frame/staking/src/mock.rs | 4 ++-- substrate/frame/staking/src/pallet/mod.rs | 4 ++-- substrate/frame/staking/src/tests.rs | 2 -- 6 files changed, 13 insertions(+), 19 deletions(-) diff --git a/substrate/frame/staking/src/benchmarking.rs b/substrate/frame/staking/src/benchmarking.rs index 100ae5965a72..509037f16740 100644 --- a/substrate/frame/staking/src/benchmarking.rs +++ b/substrate/frame/staking/src/benchmarking.rs @@ -130,10 +130,7 @@ pub fn create_validator_with_nominators( assert_ok!(reward_map.try_insert(validator, reward)); } // Give Era Points - let reward = EraRewardPoints::< - T::AccountId, - ::MaxWinners, - > { + let reward = EraRewardPoints:: { total: points_total, individual: reward_map, }; @@ -880,10 +877,7 @@ mod benchmarks { assert_ok!(reward_map.try_insert(validator, reward)); } // Give Era Points - let reward = EraRewardPoints::< - T::AccountId, - ::MaxWinners, - > { + let reward = EraRewardPoints:: { total: points_total, individual: reward_map, }; diff --git a/substrate/frame/staking/src/lib.rs b/substrate/frame/staking/src/lib.rs index 33f269eea93a..4fb494d6b079 100644 --- a/substrate/frame/staking/src/lib.rs +++ b/substrate/frame/staking/src/lib.rs @@ -386,15 +386,17 @@ pub struct ActiveEraInfo { /// /// This points will be used to reward validators and their respective nominators. #[derive(PartialEq, Encode, Decode, RuntimeDebug, TypeInfo, MaxEncodedLen)] -#[scale_info(skip_type_params(MaxWinners))] -pub struct EraRewardPoints> { +#[scale_info(skip_type_params(MaxValidatorsCount))] +pub struct EraRewardPoints> { /// Total number of points. Equals the sum of reward points for each validator. pub total: RewardPoint, /// The reward points earned by a given validator. - pub individual: BoundedBTreeMap, + pub individual: BoundedBTreeMap, } -impl> Default for EraRewardPoints { +impl> Default + for EraRewardPoints +{ fn default() -> Self { EraRewardPoints { total: Default::default(), individual: BoundedBTreeMap::new() } } diff --git a/substrate/frame/staking/src/migrations.rs b/substrate/frame/staking/src/migrations.rs index 76cd46a91167..7f999a22233e 100644 --- a/substrate/frame/staking/src/migrations.rs +++ b/substrate/frame/staking/src/migrations.rs @@ -111,7 +111,7 @@ pub mod v17 { Ok(individual_rewards) => { let bounded_era_rewards = EraRewardPoints::< ::AccountId, - <::ElectionProvider as ElectionProviderBase>::MaxWinners, + ::MaxValidatorsCount, > { individual: individual_rewards, total: era_rewards.total, diff --git a/substrate/frame/staking/src/mock.rs b/substrate/frame/staking/src/mock.rs index 4cdf60204295..eacc316c0227 100644 --- a/substrate/frame/staking/src/mock.rs +++ b/substrate/frame/staking/src/mock.rs @@ -342,7 +342,7 @@ impl Default for ExtBuilder { validator_count: 2, minimum_validator_count: 0, balance_factor: 1, - invulnerables: vec![], + invulnerables: BoundedVec::new(), has_stakers: true, initialize_first_session: true, min_nominator_bond: ExistentialDeposit::get(), @@ -376,7 +376,7 @@ impl ExtBuilder { self } pub fn invulnerables(mut self, invulnerables: Vec) -> Self { - self.invulnerables = invulnerables; + self.invulnerables = BoundedVec::force_from(invulnerables).unwrap(); self } pub fn session_per_era(self, length: SessionIndex) -> Self { diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs index a09b07018a73..6a0257544fe4 100644 --- a/substrate/frame/staking/src/pallet/mod.rs +++ b/substrate/frame/staking/src/pallet/mod.rs @@ -582,7 +582,7 @@ pub mod pallet { _, Twox64Concat, EraIndex, - EraRewardPoints::MaxWinners>, + EraRewardPoints, ValueQuery, >; @@ -1050,7 +1050,7 @@ pub mod pallet { /// Get the rewards for the last [`Config::HistoryDepth`] eras. pub fn eras_reward_points( era_index: EncodeLikeEraIndex, - ) -> EraRewardPoints::MaxWinners> + ) -> EraRewardPoints where EncodeLikeEraIndex: codec::EncodeLike, { diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index 8f9cb2917294..61a80460f493 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -72,7 +72,6 @@ fn set_staking_configs_works() { ConfigOp::Noop, ConfigOp::Noop, ConfigOp::Noop, - ConfigOp::Noop, ConfigOp::Noop ))); @@ -84,7 +83,6 @@ fn set_staking_configs_works() { ConfigOp::Remove, ConfigOp::Remove, ConfigOp::Remove, - ConfigOp::Remove, ConfigOp::Remove )); assert_eq!(MinNominatorBond::::get(), 0); From 9a21b8fb1d4342751ee5ff850ca86a3d12e0a0b7 Mon Sep 17 00:00:00 2001 From: giuseppere Date: Tue, 3 Dec 2024 17:34:51 +0100 Subject: [PATCH 038/101] remove unused imports --- substrate/frame/staking/src/benchmarking.rs | 4 +--- substrate/frame/staking/src/migrations.rs | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/substrate/frame/staking/src/benchmarking.rs b/substrate/frame/staking/src/benchmarking.rs index 509037f16740..cd27915f3887 100644 --- a/substrate/frame/staking/src/benchmarking.rs +++ b/substrate/frame/staking/src/benchmarking.rs @@ -22,9 +22,7 @@ use crate::{asset, ConfigOp, Pallet as Staking}; use testing_utils::*; use codec::Decode; -use frame_election_provider_support::{ - bounds::DataProviderBounds, ElectionProviderBase, SortedListProvider, -}; +use frame_election_provider_support::{bounds::DataProviderBounds, SortedListProvider}; use frame_support::{ assert_ok, pallet_prelude::*, diff --git a/substrate/frame/staking/src/migrations.rs b/substrate/frame/staking/src/migrations.rs index 7f999a22233e..c52501cbcef4 100644 --- a/substrate/frame/staking/src/migrations.rs +++ b/substrate/frame/staking/src/migrations.rs @@ -18,7 +18,7 @@ //! [CHANGELOG.md](https://github.com/paritytech/polkadot-sdk/blob/master/substrate/frame/staking/CHANGELOG.md). use super::*; -use frame_election_provider_support::{ElectionProviderBase, SortedListProvider}; +use frame_election_provider_support::SortedListProvider; use frame_support::{ migrations::VersionedMigration, pallet_prelude::{NMapKey, OptionQuery, ValueQuery}, From 50ce1a1e2b0ca9e6c82a2a3a0a5c70ecd3d55bfd Mon Sep 17 00:00:00 2001 From: giuseppere Date: Tue, 3 Dec 2024 17:51:30 +0100 Subject: [PATCH 039/101] Use `MaxDisabledValidators` to bound disabled validators --- polkadot/runtime/test-runtime/src/lib.rs | 1 + polkadot/runtime/westend/src/lib.rs | 1 + substrate/bin/node/runtime/src/lib.rs | 1 + substrate/frame/staking/src/mock.rs | 1 + substrate/frame/staking/src/pallet/mod.rs | 15 +++++++-------- 5 files changed, 11 insertions(+), 8 deletions(-) diff --git a/polkadot/runtime/test-runtime/src/lib.rs b/polkadot/runtime/test-runtime/src/lib.rs index f5079a683e11..f585d2064159 100644 --- a/polkadot/runtime/test-runtime/src/lib.rs +++ b/polkadot/runtime/test-runtime/src/lib.rs @@ -401,6 +401,7 @@ impl pallet_staking::Config for Runtime { type MaxInvulnerables = ConstU32<20>; type MaxRewardPagesPerValidator = ConstU32<20>; type MaxValidatorsCount = ConstU32<300>; + type MaxDisabledValidators = ConstU32<100>; } parameter_types! { diff --git a/polkadot/runtime/westend/src/lib.rs b/polkadot/runtime/westend/src/lib.rs index 5096f95cda68..fc3d24581fbc 100644 --- a/polkadot/runtime/westend/src/lib.rs +++ b/polkadot/runtime/westend/src/lib.rs @@ -770,6 +770,7 @@ impl pallet_staking::Config for Runtime { type MaxInvulnerables = frame_support::traits::ConstU32<20>; type MaxRewardPagesPerValidator = frame_support::traits::ConstU32<20>; type MaxValidatorsCount = dynamic_params::staking::MaxValidatorsCount; + type MaxDisabledValidators = ConstU32<100>; } impl pallet_fast_unstake::Config for Runtime { diff --git a/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs index 1b227d30dedc..14e6f871264a 100644 --- a/substrate/bin/node/runtime/src/lib.rs +++ b/substrate/bin/node/runtime/src/lib.rs @@ -750,6 +750,7 @@ impl pallet_staking::Config for Runtime { type MaxInvulnerables = ConstU32<20>; type MaxRewardPagesPerValidator = ConstU32<20>; type MaxValidatorsCount = ConstU32<300>; + type MaxDisabledValidators = ConstU32<100>; } impl pallet_fast_unstake::Config for Runtime { diff --git a/substrate/frame/staking/src/mock.rs b/substrate/frame/staking/src/mock.rs index eacc316c0227..08ba7efd3918 100644 --- a/substrate/frame/staking/src/mock.rs +++ b/substrate/frame/staking/src/mock.rs @@ -291,6 +291,7 @@ impl crate::pallet::pallet::Config for Test { type MaxInvulnerables = ConstU32<20>; type MaxRewardPagesPerValidator = ConstU32<20>; type MaxValidatorsCount = ConstU32<300>; + type MaxDisabledValidators = ConstU32<100>; } pub struct WeightedNominationsQuota; diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs index 6a0257544fe4..902b4f2bc342 100644 --- a/substrate/frame/staking/src/pallet/mod.rs +++ b/substrate/frame/staking/src/pallet/mod.rs @@ -316,6 +316,10 @@ pub mod pallet { #[pallet::constant] type MaxInvulnerables: Get; + /// Maximum number of disabled validators. + #[pallet::constant] + type MaxDisabledValidators: Get; + /// Some parameters of the benchmarking. #[cfg(feature = "std")] type BenchmarkingConfig: BenchmarkingConfig; @@ -368,6 +372,7 @@ pub mod pallet { type MaxInvulnerables = ConstU32<20>; type MaxRewardPagesPerValidator = ConstU32<20>; type MaxValidatorsCount = ConstU32<300>; + type MaxDisabledValidators = ConstU32<100>; #[cfg(feature = "std")] type BenchmarkingConfig = crate::TestBenchmarkingConfig; type WeightInfo = (); @@ -683,14 +688,8 @@ pub mod pallet { /// Additionally, each disabled validator is associated with an `OffenceSeverity` which /// represents how severe is the offence that got the validator disabled. #[pallet::storage] - pub type DisabledValidators = StorageValue< - _, - WeakBoundedVec< - (u32, OffenceSeverity), - ::MaxWinners, - >, - ValueQuery, - >; + pub type DisabledValidators = + StorageValue<_, BoundedVec<(u32, OffenceSeverity), T::MaxDisabledValidators>, ValueQuery>; /// The threshold for when users can start calling `chill_other` for other validators / /// nominators. The threshold is compared to the actual number of validators / nominators From 40ccdecb8f45954e9246b94ab06fe0e043108442 Mon Sep 17 00:00:00 2001 From: giuseppere Date: Tue, 3 Dec 2024 18:12:39 +0100 Subject: [PATCH 040/101] fix `Vec`/`BoundedVec` --- substrate/frame/staking/src/migrations.rs | 2 +- substrate/frame/staking/src/mock.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/substrate/frame/staking/src/migrations.rs b/substrate/frame/staking/src/migrations.rs index c52501cbcef4..30941eefca1d 100644 --- a/substrate/frame/staking/src/migrations.rs +++ b/substrate/frame/staking/src/migrations.rs @@ -74,7 +74,7 @@ pub mod v17 { let old_disabled_validators = v16::DisabledValidators::::get(); // BoundedVec with MaxWinners limit, this should always work - let disabled_validators_maybe = WeakBoundedVec::try_from(old_disabled_validators); + let disabled_validators_maybe = BoundedVec::try_from(old_disabled_validators); match disabled_validators_maybe { Ok(disabled_validators) => DisabledValidators::::set(disabled_validators), Err(_) => { diff --git a/substrate/frame/staking/src/mock.rs b/substrate/frame/staking/src/mock.rs index 08ba7efd3918..aa4cf003be22 100644 --- a/substrate/frame/staking/src/mock.rs +++ b/substrate/frame/staking/src/mock.rs @@ -325,7 +325,7 @@ pub struct ExtBuilder { nominate: bool, validator_count: u32, minimum_validator_count: u32, - invulnerables: Vec, + invulnerables: BoundedVec::MaxInvulnerables>, has_stakers: bool, initialize_first_session: bool, pub min_nominator_bond: Balance, @@ -377,7 +377,7 @@ impl ExtBuilder { self } pub fn invulnerables(mut self, invulnerables: Vec) -> Self { - self.invulnerables = BoundedVec::force_from(invulnerables).unwrap(); + self.invulnerables = BoundedVec::try_from(invulnerables).unwrap(); self } pub fn session_per_era(self, length: SessionIndex) -> Self { From c3365a6f1fc7f8ce97d57977436a26c766176ac6 Mon Sep 17 00:00:00 2001 From: giuseppere Date: Tue, 3 Dec 2024 18:36:16 +0100 Subject: [PATCH 041/101] Fix `WeakBoundedVec` and `MaxValidatorsCount` --- substrate/frame/beefy/src/mock.rs | 1 - .../test-delegate-stake/src/lib.rs | 1 - .../test-delegate-stake/src/mock.rs | 1 - substrate/frame/root-offences/src/mock.rs | 4 +++- substrate/frame/staking/src/tests.rs | 20 ++++++++++++------- 5 files changed, 16 insertions(+), 11 deletions(-) diff --git a/substrate/frame/beefy/src/mock.rs b/substrate/frame/beefy/src/mock.rs index f21c585ecce1..4fa0fc83d079 100644 --- a/substrate/frame/beefy/src/mock.rs +++ b/substrate/frame/beefy/src/mock.rs @@ -17,7 +17,6 @@ use codec::{Decode, Encode}; use scale_info::TypeInfo; -use std::vec; use frame_election_provider_support::{ bounds::{ElectionBounds, ElectionBoundsBuilder}, diff --git a/substrate/frame/nomination-pools/test-delegate-stake/src/lib.rs b/substrate/frame/nomination-pools/test-delegate-stake/src/lib.rs index cc6335959ab7..3b42e982bb51 100644 --- a/substrate/frame/nomination-pools/test-delegate-stake/src/lib.rs +++ b/substrate/frame/nomination-pools/test-delegate-stake/src/lib.rs @@ -256,7 +256,6 @@ fn pool_chill_e2e() { pallet_staking::ConfigOp::Noop, pallet_staking::ConfigOp::Noop, pallet_staking::ConfigOp::Noop, - pallet_staking::ConfigOp::Noop, )); // members can unbond as long as total stake of the pool is above min nominator bond diff --git a/substrate/frame/nomination-pools/test-delegate-stake/src/mock.rs b/substrate/frame/nomination-pools/test-delegate-stake/src/mock.rs index d1bc4ef8ff28..18033c6a54eb 100644 --- a/substrate/frame/nomination-pools/test-delegate-stake/src/mock.rs +++ b/substrate/frame/nomination-pools/test-delegate-stake/src/mock.rs @@ -329,7 +329,6 @@ pub fn new_test_ext() -> sp_io::TestExternalities { pallet_staking::ConfigOp::Noop, pallet_staking::ConfigOp::Noop, pallet_staking::ConfigOp::Noop, - pallet_staking::ConfigOp::Noop, )); }); diff --git a/substrate/frame/root-offences/src/mock.rs b/substrate/frame/root-offences/src/mock.rs index 30edd4ba1b4e..f300fe6f45fb 100644 --- a/substrate/frame/root-offences/src/mock.rs +++ b/substrate/frame/root-offences/src/mock.rs @@ -28,7 +28,9 @@ use frame_support::{ traits::{ConstU32, ConstU64, Hooks, OneSessionHandler}, }; use pallet_staking::StakerStatus; -use sp_runtime::{curve::PiecewiseLinear, testing::UintAuthorityId, traits::Zero, BuildStorage}; +use sp_runtime::{ + curve::PiecewiseLinear, testing::UintAuthorityId, traits::Zero, BoundedVec, BuildStorage, +}; use sp_staking::{EraIndex, SessionIndex}; type Block = frame_system::mocking::MockBlock; diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index 61a80460f493..94c52f231137 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -2329,7 +2329,8 @@ fn reward_validator_slashing_validator_does_not_overflow() { let exposure = Exposure:: { total: stake, own: stake, others: vec![] }; let mut reward_map = BoundedBTreeMap::new(); assert_ok!(reward_map.try_insert(11, 1)); - let reward = EraRewardPoints:: { total: 1, individual: reward_map }; + let reward = + EraRewardPoints:: { total: 1, individual: reward_map }; // Check reward ErasRewardPoints::::insert(0, reward); @@ -6608,7 +6609,7 @@ fn should_retain_era_info_only_upto_history_depth() { for page in 0..3 { ErasStakersPaged::::insert( (era, &validator_stash, page), - ExposurePage { page_total: 100, others: BoundedVec::new() }, + ExposurePage { page_total: 100, others: WeakBoundedVec::new() }, ); } } @@ -6656,7 +6657,8 @@ fn test_runtime_api_pending_rewards() { assert_ok!(reward_map.try_insert(validator_two, 1)); assert_ok!(reward_map.try_insert(validator_three, 1)); // Add reward points - let reward = EraRewardPoints:: { total: 1, individual: reward_map }; + let reward = + EraRewardPoints:: { total: 1, individual: reward_map }; ErasRewardPoints::::insert(0, reward); // build exposure @@ -8497,7 +8499,9 @@ mod migration_tests { mod getters { use crate::{ mock::{self}, - pallet::pallet::{Invulnerables, MinimumValidatorCount, ValidatorCount}, + pallet::pallet::{ + Invulnerables, MaxValidatorsCount, MinimumValidatorCount, ValidatorCount, + }, slashing, tests::{MaxWinners, Staking, Test, WeakBoundedVec}, ActiveEra, ActiveEraInfo, BalanceOf, BoundedBTreeMap, BoundedVec, CanceledSlashPayout, @@ -8506,7 +8510,7 @@ mod getters { Forcing, Nominations, Nominators, Perbill, SlashRewardFraction, SlashingSpans, ValidatorPrefs, Validators, }; - use sp_staking::{EraIndex, Page, SessionIndex}; + use sp_staking::{EraIndex, SessionIndex}; #[test] fn get_validator_count_returns_value_from_storage() { @@ -8701,8 +8705,10 @@ mod getters { let era: EraIndex = 12; let mut reward_map = BoundedBTreeMap::new(); frame_support::assert_ok!(reward_map.try_insert(11, 1)); - let reward_points = - EraRewardPoints:: { total: 1, individual: reward_map }; + let reward_points = EraRewardPoints:: { + total: 1, + individual: reward_map, + }; ErasRewardPoints::::insert(era, reward_points); // when From 584fe5300b4b41411c3afce130fd3916905bd3d1 Mon Sep 17 00:00:00 2001 From: giuseppere Date: Tue, 3 Dec 2024 18:53:17 +0100 Subject: [PATCH 042/101] fix --- .../test-transfer-stake/src/lib.rs | 1 - .../test-transfer-stake/src/mock.rs | 1 - substrate/frame/staking/src/tests.rs | 32 +++++++++++-------- 3 files changed, 19 insertions(+), 15 deletions(-) diff --git a/substrate/frame/nomination-pools/test-transfer-stake/src/lib.rs b/substrate/frame/nomination-pools/test-transfer-stake/src/lib.rs index cc39cfee91c8..519b94281c1a 100644 --- a/substrate/frame/nomination-pools/test-transfer-stake/src/lib.rs +++ b/substrate/frame/nomination-pools/test-transfer-stake/src/lib.rs @@ -338,7 +338,6 @@ fn pool_chill_e2e() { pallet_staking::ConfigOp::Noop, pallet_staking::ConfigOp::Noop, pallet_staking::ConfigOp::Noop, - pallet_staking::ConfigOp::Noop, )); // members can unbond as long as total stake of the pool is above min nominator bond diff --git a/substrate/frame/nomination-pools/test-transfer-stake/src/mock.rs b/substrate/frame/nomination-pools/test-transfer-stake/src/mock.rs index d913c5fe6948..675c5f2ab14a 100644 --- a/substrate/frame/nomination-pools/test-transfer-stake/src/mock.rs +++ b/substrate/frame/nomination-pools/test-transfer-stake/src/mock.rs @@ -195,7 +195,6 @@ pub fn new_test_ext() -> sp_io::TestExternalities { pallet_staking::ConfigOp::Noop, pallet_staking::ConfigOp::Noop, pallet_staking::ConfigOp::Noop, - pallet_staking::ConfigOp::Noop, )); }); diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index 94c52f231137..113bbf6d6461 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -2329,8 +2329,10 @@ fn reward_validator_slashing_validator_does_not_overflow() { let exposure = Exposure:: { total: stake, own: stake, others: vec![] }; let mut reward_map = BoundedBTreeMap::new(); assert_ok!(reward_map.try_insert(11, 1)); - let reward = - EraRewardPoints:: { total: 1, individual: reward_map }; + let reward = EraRewardPoints::::MaxValidatorsCount> { + total: 1, + individual: reward_map, + }; // Check reward ErasRewardPoints::::insert(0, reward); @@ -6609,7 +6611,10 @@ fn should_retain_era_info_only_upto_history_depth() { for page in 0..3 { ErasStakersPaged::::insert( (era, &validator_stash, page), - ExposurePage { page_total: 100, others: WeakBoundedVec::new() }, + ExposurePage { + page_total: 100, + others: WeakBoundedVec::force_from(vec![], None), + }, ); } } @@ -6657,8 +6662,10 @@ fn test_runtime_api_pending_rewards() { assert_ok!(reward_map.try_insert(validator_two, 1)); assert_ok!(reward_map.try_insert(validator_three, 1)); // Add reward points - let reward = - EraRewardPoints:: { total: 1, individual: reward_map }; + let reward = EraRewardPoints::::MaxValidatorsCount> { + total: 1, + individual: reward_map, + }; ErasRewardPoints::::insert(0, reward); // build exposure @@ -8499,11 +8506,9 @@ mod migration_tests { mod getters { use crate::{ mock::{self}, - pallet::pallet::{ - Invulnerables, MaxValidatorsCount, MinimumValidatorCount, ValidatorCount, - }, + pallet::pallet::{Invulnerables, MinimumValidatorCount, ValidatorCount}, slashing, - tests::{MaxWinners, Staking, Test, WeakBoundedVec}, + tests::{Staking, Test, WeakBoundedVec}, ActiveEra, ActiveEraInfo, BalanceOf, BoundedBTreeMap, BoundedVec, CanceledSlashPayout, ClaimedRewards, CurrentEra, CurrentPlannedSession, EraRewardPoints, ErasRewardPoints, ErasStartSessionIndex, ErasTotalStake, ErasValidatorPrefs, ErasValidatorReward, ForceEra, @@ -8705,10 +8710,11 @@ mod getters { let era: EraIndex = 12; let mut reward_map = BoundedBTreeMap::new(); frame_support::assert_ok!(reward_map.try_insert(11, 1)); - let reward_points = EraRewardPoints:: { - total: 1, - individual: reward_map, - }; + let reward_points = + EraRewardPoints::::MaxValidatorsCount> { + total: 1, + individual: reward_map, + }; ErasRewardPoints::::insert(era, reward_points); // when From 5333a7dec67931fa045de4b1f3d8ac6b4c8dd737 Mon Sep 17 00:00:00 2001 From: giuseppere Date: Tue, 3 Dec 2024 19:09:03 +0100 Subject: [PATCH 043/101] fix --- substrate/frame/root-offences/src/mock.rs | 4 ++-- substrate/frame/staking/src/tests.rs | 6 +----- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/substrate/frame/root-offences/src/mock.rs b/substrate/frame/root-offences/src/mock.rs index f300fe6f45fb..b5fdd56daf6d 100644 --- a/substrate/frame/root-offences/src/mock.rs +++ b/substrate/frame/root-offences/src/mock.rs @@ -181,7 +181,7 @@ impl Config for Test { pub struct ExtBuilder { validator_count: u32, minimum_validator_count: u32, - invulnerables: Vec, + invulnerables: BoundedVec::MaxInvulnerables>, balance_factor: Balance, } @@ -237,7 +237,7 @@ impl ExtBuilder { stakers: stakers.clone(), validator_count: self.validator_count, minimum_validator_count: self.minimum_validator_count, - invulnerables: BoundedVec::force_from(self.invulnerables), + invulnerables: self.invulnerables, slash_reward_fraction: Perbill::from_percent(10), ..Default::default() } diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index 113bbf6d6461..406ba23b1af5 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -8710,11 +8710,7 @@ mod getters { let era: EraIndex = 12; let mut reward_map = BoundedBTreeMap::new(); frame_support::assert_ok!(reward_map.try_insert(11, 1)); - let reward_points = - EraRewardPoints::::MaxValidatorsCount> { - total: 1, - individual: reward_map, - }; + let reward_points = EraRewardPoints::<_, _> { total: 1, individual: reward_map }; ErasRewardPoints::::insert(era, reward_points); // when From 898d469fc1ba73f4539b2fe270e074fd5c4e4da8 Mon Sep 17 00:00:00 2001 From: giuseppere Date: Tue, 3 Dec 2024 22:59:50 +0100 Subject: [PATCH 044/101] `BoundedVec` fix in tests --- .../emulated/chains/relays/westend/src/genesis.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/cumulus/parachains/integration-tests/emulated/chains/relays/westend/src/genesis.rs b/cumulus/parachains/integration-tests/emulated/chains/relays/westend/src/genesis.rs index f8d43cf4648d..5b8d5a0c97ac 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/relays/westend/src/genesis.rs +++ b/cumulus/parachains/integration-tests/emulated/chains/relays/westend/src/genesis.rs @@ -19,7 +19,7 @@ use sp_authority_discovery::AuthorityId as AuthorityDiscoveryId; use sp_consensus_babe::AuthorityId as BabeId; use sp_consensus_beefy::ecdsa_crypto::AuthorityId as BeefyId; use sp_core::storage::Storage; -use sp_runtime::Perbill; +use sp_runtime::{BoundedVec, Perbill}; // Polkadot use polkadot_primitives::{AssignmentId, ValidatorId}; @@ -86,7 +86,13 @@ pub fn genesis() -> Storage { .iter() .map(|x| (x.0.clone(), x.1.clone(), STASH, pallet_staking::StakerStatus::Validator)) .collect(), - invulnerables: validators::initial_authorities().iter().map(|x| x.0.clone()).collect(), + invulnerables: BoundedVec::try_from( + validators::initial_authorities() + .iter() + .map(|x| x.0.clone()) + .collect::>(), + ) + .unwrap(), force_era: pallet_staking::Forcing::ForceNone, slash_reward_fraction: Perbill::from_percent(10), ..Default::default() From 32df05d611eb715968da7dcc6b3888322b492e82 Mon Sep 17 00:00:00 2001 From: giuseppere Date: Wed, 4 Dec 2024 07:17:14 +0100 Subject: [PATCH 045/101] fix --- substrate/bin/node/testing/src/genesis.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/substrate/bin/node/testing/src/genesis.rs b/substrate/bin/node/testing/src/genesis.rs index 7f5364744c66..dcff7ca66ef1 100644 --- a/substrate/bin/node/testing/src/genesis.rs +++ b/substrate/bin/node/testing/src/genesis.rs @@ -24,7 +24,7 @@ use kitchensink_runtime::{ RuntimeGenesisConfig, SessionConfig, SocietyConfig, StakerStatus, StakingConfig, }; use sp_keyring::Ed25519Keyring; -use sp_runtime::Perbill; +use sp_runtime::{BoundedVec, Perbill}; /// Create genesis runtime configuration for tests. pub fn config() -> RuntimeGenesisConfig { @@ -65,7 +65,7 @@ pub fn config_endowed(extra_endowed: Vec) -> RuntimeGenesisConfig { validator_count: 3, minimum_validator_count: 0, slash_reward_fraction: Perbill::from_percent(10), - invulnerables: vec![alice(), bob(), charlie()], + invulnerables: BoundedVec::try_from(vec![alice(), bob(), charlie()]).unwrap(), ..Default::default() }, society: SocietyConfig { pot: 0 }, From 7bc9b981e48f60150d54eca5395c95d0af069a7d Mon Sep 17 00:00:00 2001 From: giuseppere Date: Wed, 4 Dec 2024 18:49:05 +0100 Subject: [PATCH 046/101] Use `MaxValidatorsCount` for limit checks --- substrate/frame/staking/src/pallet/impls.rs | 3 +-- substrate/frame/staking/src/pallet/mod.rs | 15 +++------------ 2 files changed, 4 insertions(+), 14 deletions(-) diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs index dae0d9d0aaa4..601b0ed9caa8 100644 --- a/substrate/frame/staking/src/pallet/impls.rs +++ b/substrate/frame/staking/src/pallet/impls.rs @@ -2081,8 +2081,7 @@ impl Pallet { "wrong external count" ); ensure!( - ValidatorCount::::get() <= - ::MaxWinners::get(), + ValidatorCount::::get() <= T::MaxValidatorsCount::get(), Error::::TooManyValidators ); Ok(()) diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs index 902b4f2bc342..7ed2bcf29e0b 100644 --- a/substrate/frame/staking/src/pallet/mod.rs +++ b/substrate/frame/staking/src/pallet/mod.rs @@ -1534,10 +1534,7 @@ pub mod pallet { ensure_root(origin)?; // ensure new validator count does not exceed maximum winners // support by election provider. - ensure!( - new <= ::MaxWinners::get(), - Error::::TooManyValidators - ); + ensure!(new <= T::MaxValidatorsCount::get(), Error::::TooManyValidators); ValidatorCount::::put(new); Ok(()) } @@ -1558,10 +1555,7 @@ pub mod pallet { ensure_root(origin)?; let old = ValidatorCount::::get(); let new = old.checked_add(additional).ok_or(ArithmeticError::Overflow)?; - ensure!( - new <= ::MaxWinners::get(), - Error::::TooManyValidators - ); + ensure!(new <= T::MaxValidatorsCount::get(), Error::::TooManyValidators); ValidatorCount::::put(new); Ok(()) @@ -1581,10 +1575,7 @@ pub mod pallet { let old = ValidatorCount::::get(); let new = old.checked_add(factor.mul_floor(old)).ok_or(ArithmeticError::Overflow)?; - ensure!( - new <= ::MaxWinners::get(), - Error::::TooManyValidators - ); + ensure!(new <= T::MaxValidatorsCount::get(), Error::::TooManyValidators); ValidatorCount::::put(new); Ok(()) From 536d5c5245e60b17d686bb59b1e618ff26c4e915 Mon Sep 17 00:00:00 2001 From: giuseppere Date: Mon, 9 Dec 2024 11:32:50 +0100 Subject: [PATCH 047/101] undo wrong changes --- substrate/frame/staking/src/pallet/impls.rs | 2 +- substrate/frame/staking/src/pallet/mod.rs | 15 ++++++++++++--- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs index 601b0ed9caa8..d4e038e2a51c 100644 --- a/substrate/frame/staking/src/pallet/impls.rs +++ b/substrate/frame/staking/src/pallet/impls.rs @@ -2081,7 +2081,7 @@ impl Pallet { "wrong external count" ); ensure!( - ValidatorCount::::get() <= T::MaxValidatorsCount::get(), + ValidatorCount::::get() <= ::MaxWinners::get(), Error::::TooManyValidators ); Ok(()) diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs index 7ed2bcf29e0b..902b4f2bc342 100644 --- a/substrate/frame/staking/src/pallet/mod.rs +++ b/substrate/frame/staking/src/pallet/mod.rs @@ -1534,7 +1534,10 @@ pub mod pallet { ensure_root(origin)?; // ensure new validator count does not exceed maximum winners // support by election provider. - ensure!(new <= T::MaxValidatorsCount::get(), Error::::TooManyValidators); + ensure!( + new <= ::MaxWinners::get(), + Error::::TooManyValidators + ); ValidatorCount::::put(new); Ok(()) } @@ -1555,7 +1558,10 @@ pub mod pallet { ensure_root(origin)?; let old = ValidatorCount::::get(); let new = old.checked_add(additional).ok_or(ArithmeticError::Overflow)?; - ensure!(new <= T::MaxValidatorsCount::get(), Error::::TooManyValidators); + ensure!( + new <= ::MaxWinners::get(), + Error::::TooManyValidators + ); ValidatorCount::::put(new); Ok(()) @@ -1575,7 +1581,10 @@ pub mod pallet { let old = ValidatorCount::::get(); let new = old.checked_add(factor.mul_floor(old)).ok_or(ArithmeticError::Overflow)?; - ensure!(new <= T::MaxValidatorsCount::get(), Error::::TooManyValidators); + ensure!( + new <= ::MaxWinners::get(), + Error::::TooManyValidators + ); ValidatorCount::::put(new); Ok(()) From 76469eab5660c520651af783a0f2fee487743ae8 Mon Sep 17 00:00:00 2001 From: giuseppere Date: Mon, 9 Dec 2024 15:10:26 +0100 Subject: [PATCH 048/101] Increase benchmarking `MaxValidators` limit --- substrate/bin/node/runtime/src/lib.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs index 14e6f871264a..2884adf31f0c 100644 --- a/substrate/bin/node/runtime/src/lib.rs +++ b/substrate/bin/node/runtime/src/lib.rs @@ -699,6 +699,7 @@ parameter_types! { pub const RewardCurve: &'static PiecewiseLinear<'static> = &REWARD_CURVE; pub const MaxNominators: u32 = 64; pub const MaxControllersInDeprecationBatch: u32 = 5900; + pub const MaxValidatorsCount: u32 = 1000; pub OffchainRepeat: BlockNumber = 5; pub HistoryDepth: u32 = 84; } @@ -709,7 +710,7 @@ const MAX_QUOTA_NOMINATIONS: u32 = 16; pub struct StakingBenchmarkingConfig; impl pallet_staking::BenchmarkingConfig for StakingBenchmarkingConfig { type MaxNominators = ConstU32<1000>; - type MaxValidators = ConstU32<1000>; + type MaxValidators = MaxValidatorsCount; } impl pallet_staking::Config for Runtime { @@ -749,8 +750,8 @@ impl pallet_staking::Config for Runtime { type DisablingStrategy = pallet_staking::UpToLimitWithReEnablingDisablingStrategy; type MaxInvulnerables = ConstU32<20>; type MaxRewardPagesPerValidator = ConstU32<20>; - type MaxValidatorsCount = ConstU32<300>; - type MaxDisabledValidators = ConstU32<100>; + type MaxValidatorsCount = MaxValidatorsCount; + type MaxDisabledValidators = ConstU32<300>; } impl pallet_fast_unstake::Config for Runtime { From 181fe4dd6528dd18d890effed5c47cbd38f62d04 Mon Sep 17 00:00:00 2001 From: giuseppere Date: Mon, 9 Dec 2024 16:31:14 +0100 Subject: [PATCH 049/101] Remove `MaxValidators` from benchmarking config and use `MaxValidatorsCount` instead --- polkadot/runtime/common/src/lib.rs | 1 - substrate/bin/node/runtime/src/lib.rs | 6 ++---- substrate/frame/staking/src/benchmarking.rs | 7 +++---- substrate/frame/staking/src/lib.rs | 3 --- 4 files changed, 5 insertions(+), 12 deletions(-) diff --git a/polkadot/runtime/common/src/lib.rs b/polkadot/runtime/common/src/lib.rs index 41e1cdbab801..91dd1efa3274 100644 --- a/polkadot/runtime/common/src/lib.rs +++ b/polkadot/runtime/common/src/lib.rs @@ -230,7 +230,6 @@ impl OneSessionHandler /// A reasonable benchmarking config for staking pallet. pub struct StakingBenchmarkingConfig; impl pallet_staking::BenchmarkingConfig for StakingBenchmarkingConfig { - type MaxValidators = ConstU32<1000>; type MaxNominators = ConstU32<1000>; } diff --git a/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs index 2884adf31f0c..dec45b1de711 100644 --- a/substrate/bin/node/runtime/src/lib.rs +++ b/substrate/bin/node/runtime/src/lib.rs @@ -699,7 +699,6 @@ parameter_types! { pub const RewardCurve: &'static PiecewiseLinear<'static> = &REWARD_CURVE; pub const MaxNominators: u32 = 64; pub const MaxControllersInDeprecationBatch: u32 = 5900; - pub const MaxValidatorsCount: u32 = 1000; pub OffchainRepeat: BlockNumber = 5; pub HistoryDepth: u32 = 84; } @@ -710,7 +709,6 @@ const MAX_QUOTA_NOMINATIONS: u32 = 16; pub struct StakingBenchmarkingConfig; impl pallet_staking::BenchmarkingConfig for StakingBenchmarkingConfig { type MaxNominators = ConstU32<1000>; - type MaxValidators = MaxValidatorsCount; } impl pallet_staking::Config for Runtime { @@ -750,8 +748,8 @@ impl pallet_staking::Config for Runtime { type DisablingStrategy = pallet_staking::UpToLimitWithReEnablingDisablingStrategy; type MaxInvulnerables = ConstU32<20>; type MaxRewardPagesPerValidator = ConstU32<20>; - type MaxValidatorsCount = MaxValidatorsCount; - type MaxDisabledValidators = ConstU32<300>; + type MaxValidatorsCount = ConstU32<300>; + type MaxDisabledValidators = ConstU32<100>; } impl pallet_fast_unstake::Config for Runtime { diff --git a/substrate/frame/staking/src/benchmarking.rs b/substrate/frame/staking/src/benchmarking.rs index cd27915f3887..8034b6e498d0 100644 --- a/substrate/frame/staking/src/benchmarking.rs +++ b/substrate/frame/staking/src/benchmarking.rs @@ -44,7 +44,6 @@ const SEED: u32 = 0; const MAX_SPANS: u32 = 100; const MAX_SLASHES: u32 = 1000; -type MaxValidators = <::BenchmarkingConfig as BenchmarkingConfig>::MaxValidators; type MaxNominators = <::BenchmarkingConfig as BenchmarkingConfig>::MaxNominators; // Add slashing spans to a user account. Not relevant for actual use, only to benchmark @@ -570,7 +569,7 @@ mod benchmarks { #[benchmark] fn set_validator_count() { - let validator_count = MaxValidators::::get(); + let validator_count = T::MaxValidatorsCount::get(); #[extrinsic_call] _(RawOrigin::Root, validator_count); @@ -947,7 +946,7 @@ mod benchmarks { #[benchmark] fn get_npos_voters( // number of validator intention. we will iterate all of them. - v: Linear<{ MaxValidators::::get() / 2 }, { MaxValidators::::get() }>, + v: Linear<{ T::MaxValidatorsCount::get() / 2 }, { T::MaxValidatorsCount::::get() }>, // number of nominator intention. we will iterate all of them. n: Linear<{ MaxNominators::::get() / 2 }, { MaxNominators::::get() }>, @@ -980,7 +979,7 @@ mod benchmarks { #[benchmark] fn get_npos_targets( // number of validator intention. - v: Linear<{ MaxValidators::::get() / 2 }, { MaxValidators::::get() }>, + v: Linear<{ T::MaxValidatorsCount::get() / 2 }, { T::MaxValidatorsCount::get() }>, ) -> Result<(), BenchmarkError> { // number of nominator intention. let n = MaxNominators::::get(); diff --git a/substrate/frame/staking/src/lib.rs b/substrate/frame/staking/src/lib.rs index 4fb494d6b079..5c2f47c17e3d 100644 --- a/substrate/frame/staking/src/lib.rs +++ b/substrate/frame/staking/src/lib.rs @@ -1220,8 +1220,6 @@ impl EraInfo { /// Configurations of the benchmarking of the pallet. pub trait BenchmarkingConfig { /// The maximum number of validators to use. - type MaxValidators: Get; - /// The maximum number of nominators to use. type MaxNominators: Get; } @@ -1233,7 +1231,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>; } From 9c002c1ce179fb4e2b6ce968e8efa454966a0694 Mon Sep 17 00:00:00 2001 From: giuseppere Date: Mon, 9 Dec 2024 16:53:04 +0100 Subject: [PATCH 050/101] fix --- substrate/frame/staking/src/benchmarking.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrate/frame/staking/src/benchmarking.rs b/substrate/frame/staking/src/benchmarking.rs index 8034b6e498d0..9ca3d6130dcf 100644 --- a/substrate/frame/staking/src/benchmarking.rs +++ b/substrate/frame/staking/src/benchmarking.rs @@ -946,7 +946,7 @@ mod benchmarks { #[benchmark] fn get_npos_voters( // number of validator intention. we will iterate all of them. - v: Linear<{ T::MaxValidatorsCount::get() / 2 }, { T::MaxValidatorsCount::::get() }>, + v: Linear<{ T::MaxValidatorsCount::get() / 2 }, { T::MaxValidatorsCount::get() }>, // number of nominator intention. we will iterate all of them. n: Linear<{ MaxNominators::::get() / 2 }, { MaxNominators::::get() }>, From 503a7d991c93202755194c9955a40008259437f7 Mon Sep 17 00:00:00 2001 From: giuseppere Date: Mon, 9 Dec 2024 17:51:45 +0100 Subject: [PATCH 051/101] Use `MaxValidatorsCount` for slashing pallet --- .../runtime/parachains/src/disputes/slashing.rs | 17 ----------------- .../src/disputes/slashing/benchmarking.rs | 2 +- polkadot/runtime/rococo/src/lib.rs | 1 - polkadot/runtime/test-runtime/src/lib.rs | 1 - polkadot/runtime/westend/src/lib.rs | 2 -- 5 files changed, 1 insertion(+), 22 deletions(-) diff --git a/polkadot/runtime/parachains/src/disputes/slashing.rs b/polkadot/runtime/parachains/src/disputes/slashing.rs index 2e09ea667f74..4e52180cc93a 100644 --- a/polkadot/runtime/parachains/src/disputes/slashing.rs +++ b/polkadot/runtime/parachains/src/disputes/slashing.rs @@ -80,20 +80,6 @@ const SLASH_FOR_INVALID: Perbill = Perbill::from_percent(100); const SLASH_AGAINST_VALID: Perbill = Perbill::zero(); const DEFENSIVE_PROOF: &'static str = "disputes module should bail on old session"; -#[cfg(feature = "runtime-benchmarks")] -pub mod benchmarking; - -/// The benchmarking configuration. -pub trait BenchmarkingConfiguration { - const MAX_VALIDATORS: u32; -} - -pub struct BenchConfig; - -impl BenchmarkingConfiguration for BenchConfig { - const MAX_VALIDATORS: u32 = M; -} - /// An offence that is filed when a series of validators lost a dispute. #[derive(TypeInfo)] #[cfg_attr(feature = "std", derive(Clone, PartialEq, Eq))] @@ -400,9 +386,6 @@ pub mod pallet { /// Weight information for extrinsics in this pallet. type WeightInfo: WeightInfo; - - /// Benchmarking configuration. - type BenchmarkingConfig: BenchmarkingConfiguration; } #[pallet::pallet] diff --git a/polkadot/runtime/parachains/src/disputes/slashing/benchmarking.rs b/polkadot/runtime/parachains/src/disputes/slashing/benchmarking.rs index b53f98caeea3..d0bc58e70c3f 100644 --- a/polkadot/runtime/parachains/src/disputes/slashing/benchmarking.rs +++ b/polkadot/runtime/parachains/src/disputes/slashing/benchmarking.rs @@ -144,7 +144,7 @@ benchmarks! { // in this setup we have a single `ForInvalid` dispute // submitted for a past session report_dispute_lost { - let n in 4..<::BenchmarkingConfig as BenchmarkingConfiguration>::MAX_VALIDATORS; + let n in 4..<::MaxValidatorsCount; let origin = RawOrigin::None.into(); let (session_index, key_owner_proof, validator_id) = setup_validator_set::(n); diff --git a/polkadot/runtime/rococo/src/lib.rs b/polkadot/runtime/rococo/src/lib.rs index c832ace91c07..6d02d8ea4990 100644 --- a/polkadot/runtime/rococo/src/lib.rs +++ b/polkadot/runtime/rococo/src/lib.rs @@ -1173,7 +1173,6 @@ impl parachains_slashing::Config for Runtime { ReportLongevity, >; type WeightInfo = parachains_slashing::TestWeightInfo; - type BenchmarkingConfig = parachains_slashing::BenchConfig<200>; } parameter_types! { diff --git a/polkadot/runtime/test-runtime/src/lib.rs b/polkadot/runtime/test-runtime/src/lib.rs index 6ece3dfddbe2..71a4580bc56a 100644 --- a/polkadot/runtime/test-runtime/src/lib.rs +++ b/polkadot/runtime/test-runtime/src/lib.rs @@ -556,7 +556,6 @@ impl parachains_slashing::Config for Runtime { ReportLongevity, >; type WeightInfo = parachains_disputes::slashing::TestWeightInfo; - type BenchmarkingConfig = parachains_slashing::BenchConfig<1000>; } impl parachains_paras_inherent::Config for Runtime { diff --git a/polkadot/runtime/westend/src/lib.rs b/polkadot/runtime/westend/src/lib.rs index f2d3b9294268..af1379148f7c 100644 --- a/polkadot/runtime/westend/src/lib.rs +++ b/polkadot/runtime/westend/src/lib.rs @@ -1432,7 +1432,6 @@ impl parachains_slashing::Config for Runtime { ReportLongevity, >; type WeightInfo = weights::polkadot_runtime_parachains_disputes_slashing::WeightInfo; - type BenchmarkingConfig = parachains_slashing::BenchConfig<300>; } parameter_types! { @@ -2713,7 +2712,6 @@ sp_api::impl_runtime_apis! { } impl frame_system_benchmarking::Config for Runtime {} impl pallet_nomination_pools_benchmarking::Config for Runtime {} - impl polkadot_runtime_parachains::disputes::slashing::benchmarking::Config for Runtime {} use xcm::latest::{ AssetId, Fungibility::*, InteriorLocation, Junction, Junctions::*, From 63a18b1bca83872c11d3069f6e59ec845aa1dade Mon Sep 17 00:00:00 2001 From: giuseppere Date: Mon, 9 Dec 2024 18:32:52 +0100 Subject: [PATCH 052/101] Fix migration comments --- substrate/frame/staking/src/migrations.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/substrate/frame/staking/src/migrations.rs b/substrate/frame/staking/src/migrations.rs index 30941eefca1d..35de7b429f30 100644 --- a/substrate/frame/staking/src/migrations.rs +++ b/substrate/frame/staking/src/migrations.rs @@ -73,7 +73,7 @@ pub mod v17 { v16::MaxValidatorsCount::::kill(); let old_disabled_validators = v16::DisabledValidators::::get(); - // BoundedVec with MaxWinners limit, this should always work + // BoundedVec with MaxDisabledValidators limit, this should always work let disabled_validators_maybe = BoundedVec::try_from(old_disabled_validators); match disabled_validators_maybe { Ok(disabled_validators) => DisabledValidators::::set(disabled_validators), @@ -95,7 +95,7 @@ pub mod v17 { } let old_invulnerables = v16::Invulnerables::::get(); - // BoundedVec with MaxWinners limit, this should always work + // BoundedVec with MaxInvulnerables limit, this should always work let invulnerables_maybe = BoundedVec::try_from(old_invulnerables); match invulnerables_maybe { Ok(invulnerables) => Invulnerables::::set(invulnerables), From 49059c09b399d6e4f1be8861d72a78ae10843974 Mon Sep 17 00:00:00 2001 From: giuseppere Date: Tue, 10 Dec 2024 10:14:43 +0100 Subject: [PATCH 053/101] Restore benchmarking for slashing --- polkadot/runtime/parachains/src/disputes/slashing.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/polkadot/runtime/parachains/src/disputes/slashing.rs b/polkadot/runtime/parachains/src/disputes/slashing.rs index 4e52180cc93a..7336256ebfad 100644 --- a/polkadot/runtime/parachains/src/disputes/slashing.rs +++ b/polkadot/runtime/parachains/src/disputes/slashing.rs @@ -80,6 +80,9 @@ const SLASH_FOR_INVALID: Perbill = Perbill::from_percent(100); const SLASH_AGAINST_VALID: Perbill = Perbill::zero(); const DEFENSIVE_PROOF: &'static str = "disputes module should bail on old session"; +#[cfg(feature = "runtime-benchmarks")] +pub mod benchmarking; + /// An offence that is filed when a series of validators lost a dispute. #[derive(TypeInfo)] #[cfg_attr(feature = "std", derive(Clone, PartialEq, Eq))] From 81866807092e46d2442460b51dfc68d0d2a39944 Mon Sep 17 00:00:00 2001 From: giuseppere Date: Tue, 10 Dec 2024 10:37:03 +0100 Subject: [PATCH 054/101] fix --- .../runtime/parachains/src/disputes/slashing/benchmarking.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/polkadot/runtime/parachains/src/disputes/slashing/benchmarking.rs b/polkadot/runtime/parachains/src/disputes/slashing/benchmarking.rs index d0bc58e70c3f..f7d30abf6997 100644 --- a/polkadot/runtime/parachains/src/disputes/slashing/benchmarking.rs +++ b/polkadot/runtime/parachains/src/disputes/slashing/benchmarking.rs @@ -144,7 +144,7 @@ benchmarks! { // in this setup we have a single `ForInvalid` dispute // submitted for a past session report_dispute_lost { - let n in 4..<::MaxValidatorsCount; + let n in 4..::MaxValidatorsCount; let origin = RawOrigin::None.into(); let (session_index, key_owner_proof, validator_id) = setup_validator_set::(n); From 3fb6ca7b882f74511bc4078a03a8acb3b14c7355 Mon Sep 17 00:00:00 2001 From: giuseppere Date: Tue, 10 Dec 2024 10:38:24 +0100 Subject: [PATCH 055/101] fix --- .../runtime/parachains/src/disputes/slashing/benchmarking.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/polkadot/runtime/parachains/src/disputes/slashing/benchmarking.rs b/polkadot/runtime/parachains/src/disputes/slashing/benchmarking.rs index f7d30abf6997..c93202c1e66f 100644 --- a/polkadot/runtime/parachains/src/disputes/slashing/benchmarking.rs +++ b/polkadot/runtime/parachains/src/disputes/slashing/benchmarking.rs @@ -144,7 +144,7 @@ benchmarks! { // in this setup we have a single `ForInvalid` dispute // submitted for a past session report_dispute_lost { - let n in 4..::MaxValidatorsCount; + let n in 4..::MaxValidatorsCount::get(); let origin = RawOrigin::None.into(); let (session_index, key_owner_proof, validator_id) = setup_validator_set::(n); From 66923a4492819ef7adba29da0a19185f55a3d7d6 Mon Sep 17 00:00:00 2001 From: giuseppere Date: Tue, 10 Dec 2024 11:45:15 +0100 Subject: [PATCH 056/101] fix benchmarking config --- polkadot/runtime/westend/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/polkadot/runtime/westend/src/lib.rs b/polkadot/runtime/westend/src/lib.rs index af1379148f7c..80f77545669f 100644 --- a/polkadot/runtime/westend/src/lib.rs +++ b/polkadot/runtime/westend/src/lib.rs @@ -2712,6 +2712,7 @@ sp_api::impl_runtime_apis! { } impl frame_system_benchmarking::Config for Runtime {} impl pallet_nomination_pools_benchmarking::Config for Runtime {} + impl polkadot_runtime_parachains::disputes::slashing::benchmarking::Config for Runtime {} use xcm::latest::{ AssetId, Fungibility::*, InteriorLocation, Junction, Junctions::*, From bec05448f347b5eec8a7797fbb012c29dc33d77a Mon Sep 17 00:00:00 2001 From: giuseppere Date: Tue, 10 Dec 2024 14:44:30 +0100 Subject: [PATCH 057/101] fix --- .../runtime/parachains/src/disputes/slashing/benchmarking.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/polkadot/runtime/parachains/src/disputes/slashing/benchmarking.rs b/polkadot/runtime/parachains/src/disputes/slashing/benchmarking.rs index c93202c1e66f..2b9493dbd982 100644 --- a/polkadot/runtime/parachains/src/disputes/slashing/benchmarking.rs +++ b/polkadot/runtime/parachains/src/disputes/slashing/benchmarking.rs @@ -144,7 +144,7 @@ benchmarks! { // in this setup we have a single `ForInvalid` dispute // submitted for a past session report_dispute_lost { - let n in 4..::MaxValidatorsCount::get(); + let n in 4..T::MaxValidatorsCount::get(); let origin = RawOrigin::None.into(); let (session_index, key_owner_proof, validator_id) = setup_validator_set::(n); From 73af22ae346e37a18fe7cb9cfbf6462bca82c2ae Mon Sep 17 00:00:00 2001 From: giuseppere Date: Tue, 10 Dec 2024 17:52:05 +0100 Subject: [PATCH 058/101] Remove `unbounded` for `ClaimedRewards` --- .../runtime/parachains/src/disputes/slashing/benchmarking.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/polkadot/runtime/parachains/src/disputes/slashing/benchmarking.rs b/polkadot/runtime/parachains/src/disputes/slashing/benchmarking.rs index 2b9493dbd982..5d50d9e07e11 100644 --- a/polkadot/runtime/parachains/src/disputes/slashing/benchmarking.rs +++ b/polkadot/runtime/parachains/src/disputes/slashing/benchmarking.rs @@ -47,7 +47,7 @@ where let balance_factor = 1000; // create validators and set random session keys - for (n, who) in create_validators::(n, balance_factor).unwrap().into_iter().enumerate() { + for (m, who) in create_validators::(n, balance_factor).unwrap().into_iter().enumerate() { use rand::{RngCore, SeedableRng}; let validator = T::Lookup::lookup(who).unwrap(); @@ -62,7 +62,7 @@ where keys_len += 1; } let mut keys = vec![0u8; keys_len]; - let mut rng = rand_chacha::ChaCha12Rng::seed_from_u64(n as u64); + let mut rng = rand_chacha::ChaCha12Rng::seed_from_u64(m as u64); rng.fill_bytes(&mut keys); keys }; From 2bda8eb3952bfa69b526513916d57622d006939d Mon Sep 17 00:00:00 2001 From: command-bot <> Date: Wed, 11 Dec 2024 10:36:50 +0000 Subject: [PATCH 059/101] Update from re-gius running command 'prdoc --bump major --audience runtime_dev' --- prdoc/pr_6445.prdoc | 56 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 prdoc/pr_6445.prdoc diff --git a/prdoc/pr_6445.prdoc b/prdoc/pr_6445.prdoc new file mode 100644 index 000000000000..faa1ca67661b --- /dev/null +++ b/prdoc/pr_6445.prdoc @@ -0,0 +1,56 @@ +title: Add storage bounds for pallet `staking` +doc: +- audience: Runtime Dev + description: |- + This is part of #6289 and necessary for the Asset Hub migration. + + Building on the observations and suggestions from #255 . + + **Changes** + + - Add `MaxInvulnerables` to bound `Invulnerables` Vec -> `BoundedVec`. + - Set to constant 20 in the pallet (must be >= 17 for backward compatibility of runtime `westend`). + - Add `MaxDisabledValidators` to bound `DisabledValidators` Vec -> `BoundedVec` + - Set to constant 100 in the pallet (it should be <= 1/3 * `MaxValidatorsCount` according to the current disabling strategy) + - Remove `ErasStakers` and `ErasStakersClipped` (see #433 ) + - They were deprecated in v14 and could have been removed since staking era 1504 (now it's > 1600) + - Completing the task from #5986 + - Use `MaxExposurePageSize` to bound `ErasStakersPaged` mapping to exposure pages: each `ExposurePage.others` Vec is turned into a `WeakBoundedVec` to allow easy and quick changes to this bound + - Add `MaxBondedEras` to bound `BondedEras` Vec -> `BoundedVec` + - Set to `BondingDuration::get() + 1` everywhere to include both time interval endpoints in [`current_era - BondingDuration::get()`, `current_era`] + - Add `MaxRewardPagesPerValidator` to bound `ClaimedRewards` Vec of pages -> `WeakBoundedVec` + - Set to constant 20 in the pallet. The vector of pages is now a `WeakBoundedVec` to allow easy and quick changes to this parameter + - Remove `MaxValidatorsCount` optional storage item to add `MaxValidatorsCount` mandatory config parameter + - Using it to to bound `EraRewardPoints.individual` BTreeMap -> `BoundedBTreeMap`; + - Set to dynamic parameter in runtime westend so that changing it should not require migrations for it + + **TO DO** + Slashing storage items will be bounded in another PR. + + - `UnappliedSlashes` + - `SlashingSpans` +crates: +- name: pallet-staking + bump: major +- name: westend-runtime + bump: major +- name: sp-staking + bump: major +- name: polkadot-runtime-common + bump: major +- name: pallet-fast-unstake + bump: major +- name: pallet-babe + bump: major +- name: pallet-beefy + bump: major +- name: pallet-delegated-staking + bump: major +- name: pallet-grandpa + bump: major +- name: pallet-root-offences + bump: major +- name: polkadot-runtime-parachains + bump: major +- name: rococo-runtime + bump: major From fe3147bbfbc6414ed14201e9a6020fa9afe06b14 Mon Sep 17 00:00:00 2001 From: giuseppere Date: Wed, 11 Dec 2024 11:43:30 +0100 Subject: [PATCH 060/101] fix prdoc --- prdoc/pr_6445.prdoc | 20 ++++++++++---------- substrate/frame/staking/src/pallet/mod.rs | 1 - 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/prdoc/pr_6445.prdoc b/prdoc/pr_6445.prdoc index faa1ca67661b..df7292938609 100644 --- a/prdoc/pr_6445.prdoc +++ b/prdoc/pr_6445.prdoc @@ -33,24 +33,24 @@ crates: - name: pallet-staking bump: major - name: westend-runtime - bump: major + bump: minor - name: sp-staking bump: major - name: polkadot-runtime-common - bump: major + bump: minor - name: pallet-fast-unstake - bump: major + bump: patch - name: pallet-babe - bump: major + bump: patch - name: pallet-beefy - bump: major + bump: patch - name: pallet-delegated-staking - bump: major + bump: patch - name: pallet-grandpa - bump: major + bump: patch - name: pallet-root-offences - bump: major + bump: patch - name: polkadot-runtime-parachains - bump: major + bump: minor - name: rococo-runtime - bump: major + bump: minor diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs index 902b4f2bc342..7ab2f6479da8 100644 --- a/substrate/frame/staking/src/pallet/mod.rs +++ b/substrate/frame/staking/src/pallet/mod.rs @@ -546,7 +546,6 @@ pub mod pallet { /// /// It is removed after [`Config::HistoryDepth`] eras. #[pallet::storage] - #[pallet::unbounded] pub type ClaimedRewards = StorageDoubleMap< _, Twox64Concat, From cd8a0c3d9d6e3e99c3bebb6d0d066288a0b1770a Mon Sep 17 00:00:00 2001 From: giuseppere Date: Wed, 11 Dec 2024 12:35:43 +0100 Subject: [PATCH 061/101] fix prdoc --- prdoc/pr_6445.prdoc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/prdoc/pr_6445.prdoc b/prdoc/pr_6445.prdoc index df7292938609..79e3e6b7b034 100644 --- a/prdoc/pr_6445.prdoc +++ b/prdoc/pr_6445.prdoc @@ -35,9 +35,9 @@ crates: - name: westend-runtime bump: minor - name: sp-staking - bump: major -- name: polkadot-runtime-common bump: minor +- name: polkadot-runtime-common + bump: patch - name: pallet-fast-unstake bump: patch - name: pallet-babe @@ -51,6 +51,6 @@ crates: - name: pallet-root-offences bump: patch - name: polkadot-runtime-parachains - bump: minor + bump: major - name: rococo-runtime - bump: minor + bump: patch From 5b15e24bb740b3fe1448003e25657542bf3c6932 Mon Sep 17 00:00:00 2001 From: giuseppere Date: Wed, 11 Dec 2024 13:31:15 +0100 Subject: [PATCH 062/101] debug failing benchmark --- .../parachains/src/disputes/slashing/benchmarking.rs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/polkadot/runtime/parachains/src/disputes/slashing/benchmarking.rs b/polkadot/runtime/parachains/src/disputes/slashing/benchmarking.rs index 5d50d9e07e11..ef082d50e41e 100644 --- a/polkadot/runtime/parachains/src/disputes/slashing/benchmarking.rs +++ b/polkadot/runtime/parachains/src/disputes/slashing/benchmarking.rs @@ -47,11 +47,16 @@ where let balance_factor = 1000; // create validators and set random session keys - for (m, who) in create_validators::(n, balance_factor).unwrap().into_iter().enumerate() { + for (m, who) in create_validators::(n, balance_factor) + .expect("Could not create validators") + .into_iter() + .enumerate() + { use rand::{RngCore, SeedableRng}; - let validator = T::Lookup::lookup(who).unwrap(); - let controller = pallet_staking::Pallet::::bonded(&validator).unwrap(); + let validator = T::Lookup::lookup(who).expect("Could not find validator"); + let controller = + pallet_staking::Pallet::::bonded(&validator).expect("Could not find controller"); let keys = { const SESSION_KEY_LEN: usize = 32; From 9d055a87448a658eef604446b4c41c359199b2a9 Mon Sep 17 00:00:00 2001 From: giuseppere Date: Wed, 11 Dec 2024 15:52:01 +0100 Subject: [PATCH 063/101] benchmarking error debug --- .../parachains/src/disputes/slashing/benchmarking.rs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/polkadot/runtime/parachains/src/disputes/slashing/benchmarking.rs b/polkadot/runtime/parachains/src/disputes/slashing/benchmarking.rs index ef082d50e41e..52dece69221b 100644 --- a/polkadot/runtime/parachains/src/disputes/slashing/benchmarking.rs +++ b/polkadot/runtime/parachains/src/disputes/slashing/benchmarking.rs @@ -90,10 +90,15 @@ where let session_index = crate::shared::CurrentSessionIndex::::get(); let session_info = crate::session_info::Sessions::::get(session_index); - let session_info = session_info.unwrap(); - let validator_id = session_info.validators.get(ValidatorIndex::from(0)).unwrap().clone(); + let session_info = session_info.expect("Session info not found"); + let validator_id = session_info + .validators + .get(ValidatorIndex::from(0)) + .expect("Validator not found") + .clone(); let key = (PARACHAIN_KEY_TYPE_ID, validator_id.clone()); - let key_owner_proof = pallet_session::historical::Pallet::::prove(key).unwrap(); + let key_owner_proof = + pallet_session::historical::Pallet::::prove(key).expect("Key owner proof not found"); // rotate a session to make sure `key_owner_proof` is historical initializer::Pallet::::on_initialize(BlockNumberFor::::one()); From 07b021bfbd615ea0cfe2852ee9cd2beed25727fc Mon Sep 17 00:00:00 2001 From: giuseppere Date: Wed, 11 Dec 2024 16:44:00 +0100 Subject: [PATCH 064/101] undo debug changes --- .../src/disputes/slashing/benchmarking.rs | 24 ++++++------------- 1 file changed, 7 insertions(+), 17 deletions(-) diff --git a/polkadot/runtime/parachains/src/disputes/slashing/benchmarking.rs b/polkadot/runtime/parachains/src/disputes/slashing/benchmarking.rs index 52dece69221b..2b9493dbd982 100644 --- a/polkadot/runtime/parachains/src/disputes/slashing/benchmarking.rs +++ b/polkadot/runtime/parachains/src/disputes/slashing/benchmarking.rs @@ -47,16 +47,11 @@ where let balance_factor = 1000; // create validators and set random session keys - for (m, who) in create_validators::(n, balance_factor) - .expect("Could not create validators") - .into_iter() - .enumerate() - { + for (n, who) in create_validators::(n, balance_factor).unwrap().into_iter().enumerate() { use rand::{RngCore, SeedableRng}; - let validator = T::Lookup::lookup(who).expect("Could not find validator"); - let controller = - pallet_staking::Pallet::::bonded(&validator).expect("Could not find controller"); + let validator = T::Lookup::lookup(who).unwrap(); + let controller = pallet_staking::Pallet::::bonded(&validator).unwrap(); let keys = { const SESSION_KEY_LEN: usize = 32; @@ -67,7 +62,7 @@ where keys_len += 1; } let mut keys = vec![0u8; keys_len]; - let mut rng = rand_chacha::ChaCha12Rng::seed_from_u64(m as u64); + let mut rng = rand_chacha::ChaCha12Rng::seed_from_u64(n as u64); rng.fill_bytes(&mut keys); keys }; @@ -90,15 +85,10 @@ where let session_index = crate::shared::CurrentSessionIndex::::get(); let session_info = crate::session_info::Sessions::::get(session_index); - let session_info = session_info.expect("Session info not found"); - let validator_id = session_info - .validators - .get(ValidatorIndex::from(0)) - .expect("Validator not found") - .clone(); + let session_info = session_info.unwrap(); + let validator_id = session_info.validators.get(ValidatorIndex::from(0)).unwrap().clone(); let key = (PARACHAIN_KEY_TYPE_ID, validator_id.clone()); - let key_owner_proof = - pallet_session::historical::Pallet::::prove(key).expect("Key owner proof not found"); + let key_owner_proof = pallet_session::historical::Pallet::::prove(key).unwrap(); // rotate a session to make sure `key_owner_proof` is historical initializer::Pallet::::on_initialize(BlockNumberFor::::one()); From 87e0e46fe2365f0e90c5bb5199a0e255c1694837 Mon Sep 17 00:00:00 2001 From: giuseppere Date: Wed, 11 Dec 2024 16:45:27 +0100 Subject: [PATCH 065/101] debug 1 --- .../src/disputes/slashing/benchmarking.rs | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/polkadot/runtime/parachains/src/disputes/slashing/benchmarking.rs b/polkadot/runtime/parachains/src/disputes/slashing/benchmarking.rs index 2b9493dbd982..a82467deabfa 100644 --- a/polkadot/runtime/parachains/src/disputes/slashing/benchmarking.rs +++ b/polkadot/runtime/parachains/src/disputes/slashing/benchmarking.rs @@ -144,20 +144,9 @@ benchmarks! { // in this setup we have a single `ForInvalid` dispute // submitted for a past session report_dispute_lost { - let n in 4..T::MaxValidatorsCount::get(); - - let origin = RawOrigin::None.into(); - let (session_index, key_owner_proof, validator_id) = setup_validator_set::(n); - let dispute_proof = setup_dispute::(session_index, validator_id); + let _n in 4..T::MaxValidatorsCount::get(); }: { - let result = Pallet::::report_dispute_lost_unsigned( - origin, - Box::new(dispute_proof), - key_owner_proof, - ); + let result = Ok(); assert!(result.is_ok()); - } verify { - let unapplied = >::get(session_index, CANDIDATE_HASH); - assert!(unapplied.is_none()); } } From 473e0ffc32f1999c850ec78fa5208f485a70caa9 Mon Sep 17 00:00:00 2001 From: giuseppere Date: Wed, 11 Dec 2024 16:46:17 +0100 Subject: [PATCH 066/101] debug 1 --- .../runtime/parachains/src/disputes/slashing/benchmarking.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/polkadot/runtime/parachains/src/disputes/slashing/benchmarking.rs b/polkadot/runtime/parachains/src/disputes/slashing/benchmarking.rs index a82467deabfa..e99b553f3903 100644 --- a/polkadot/runtime/parachains/src/disputes/slashing/benchmarking.rs +++ b/polkadot/runtime/parachains/src/disputes/slashing/benchmarking.rs @@ -144,9 +144,9 @@ benchmarks! { // in this setup we have a single `ForInvalid` dispute // submitted for a past session report_dispute_lost { - let _n in 4..T::MaxValidatorsCount::get(); + let _n = T::MaxValidatorsCount::get(); }: { - let result = Ok(); + let result = Ok(()); assert!(result.is_ok()); } } From eb64ffc19550024970d868abea90b6ee51f15975 Mon Sep 17 00:00:00 2001 From: giuseppere Date: Wed, 11 Dec 2024 16:49:44 +0100 Subject: [PATCH 067/101] debug 1 --- .../runtime/parachains/src/disputes/slashing/benchmarking.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/polkadot/runtime/parachains/src/disputes/slashing/benchmarking.rs b/polkadot/runtime/parachains/src/disputes/slashing/benchmarking.rs index e99b553f3903..12ab0d23228c 100644 --- a/polkadot/runtime/parachains/src/disputes/slashing/benchmarking.rs +++ b/polkadot/runtime/parachains/src/disputes/slashing/benchmarking.rs @@ -146,7 +146,6 @@ benchmarks! { report_dispute_lost { let _n = T::MaxValidatorsCount::get(); }: { - let result = Ok(()); - assert!(result.is_ok()); + assert_eq!(0, 0); } } From 74d6c7a9780818e0753e2bdd187e5123bcc73cb0 Mon Sep 17 00:00:00 2001 From: giuseppere Date: Wed, 11 Dec 2024 17:02:45 +0100 Subject: [PATCH 068/101] debug dynamic param --- .../src/disputes/slashing/benchmarking.rs | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/polkadot/runtime/parachains/src/disputes/slashing/benchmarking.rs b/polkadot/runtime/parachains/src/disputes/slashing/benchmarking.rs index 12ab0d23228c..3038183802a3 100644 --- a/polkadot/runtime/parachains/src/disputes/slashing/benchmarking.rs +++ b/polkadot/runtime/parachains/src/disputes/slashing/benchmarking.rs @@ -144,8 +144,20 @@ benchmarks! { // in this setup we have a single `ForInvalid` dispute // submitted for a past session report_dispute_lost { - let _n = T::MaxValidatorsCount::get(); + let n in 4..300; + + let origin = RawOrigin::None.into(); + let (session_index, key_owner_proof, validator_id) = setup_validator_set::(n); + let dispute_proof = setup_dispute::(session_index, validator_id); }: { - assert_eq!(0, 0); + let result = Pallet::::report_dispute_lost_unsigned( + origin, + Box::new(dispute_proof), + key_owner_proof, + ); + assert!(result.is_ok()); + } verify { + let unapplied = >::get(session_index, CANDIDATE_HASH); + assert!(unapplied.is_none()); } } From 94f5b314be000bbd412b3eed50909c45831b19be Mon Sep 17 00:00:00 2001 From: giuseppere Date: Wed, 11 Dec 2024 17:30:16 +0100 Subject: [PATCH 069/101] restore after debugging --- .../runtime/parachains/src/disputes/slashing/benchmarking.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/polkadot/runtime/parachains/src/disputes/slashing/benchmarking.rs b/polkadot/runtime/parachains/src/disputes/slashing/benchmarking.rs index 3038183802a3..c93202c1e66f 100644 --- a/polkadot/runtime/parachains/src/disputes/slashing/benchmarking.rs +++ b/polkadot/runtime/parachains/src/disputes/slashing/benchmarking.rs @@ -144,7 +144,7 @@ benchmarks! { // in this setup we have a single `ForInvalid` dispute // submitted for a past session report_dispute_lost { - let n in 4..300; + let n in 4..::MaxValidatorsCount::get(); let origin = RawOrigin::None.into(); let (session_index, key_owner_proof, validator_id) = setup_validator_set::(n); From 7b1fc5ee72d3087debb3bb208683944fa3475f3e Mon Sep 17 00:00:00 2001 From: giuseppere Date: Thu, 12 Dec 2024 16:32:24 +0100 Subject: [PATCH 070/101] Fix bound comparison to `MaxValidatorsCount` --- substrate/frame/staking/src/pallet/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs index 7ab2f6479da8..bfae3d75cb11 100644 --- a/substrate/frame/staking/src/pallet/mod.rs +++ b/substrate/frame/staking/src/pallet/mod.rs @@ -1343,7 +1343,7 @@ pub mod pallet { // calling `chill_other`. Until then, we explicitly block new validators to protect // the runtime. ensure!( - Validators::::count() < T::MaxValidatorsCount::get(), + Validators::::count() <= T::MaxValidatorsCount::get(), Error::::TooManyValidators, ); } From c2659740b1f084287bbe94dfe948fea0fc45d411 Mon Sep 17 00:00:00 2001 From: giuseppere Date: Mon, 16 Dec 2024 11:03:55 +0100 Subject: [PATCH 071/101] Use `MaxValidatorsCount` limit to check validators --- substrate/frame/staking/src/pallet/mod.rs | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs index bfae3d75cb11..df7f213cec5f 100644 --- a/substrate/frame/staking/src/pallet/mod.rs +++ b/substrate/frame/staking/src/pallet/mod.rs @@ -1531,12 +1531,8 @@ pub mod pallet { #[pallet::compact] new: u32, ) -> DispatchResult { ensure_root(origin)?; - // ensure new validator count does not exceed maximum winners - // support by election provider. - ensure!( - new <= ::MaxWinners::get(), - Error::::TooManyValidators - ); + // ensure new validator count does not exceed maximum number of validators allowed. + ensure!(new <= T::MaxValidatorsCount::get(), Error::::TooManyValidators); ValidatorCount::::put(new); Ok(()) } @@ -1557,10 +1553,7 @@ pub mod pallet { ensure_root(origin)?; let old = ValidatorCount::::get(); let new = old.checked_add(additional).ok_or(ArithmeticError::Overflow)?; - ensure!( - new <= ::MaxWinners::get(), - Error::::TooManyValidators - ); + ensure!(new <= T::MaxValidatorsCount::get(), Error::::TooManyValidators); ValidatorCount::::put(new); Ok(()) @@ -1580,10 +1573,7 @@ pub mod pallet { let old = ValidatorCount::::get(); let new = old.checked_add(factor.mul_floor(old)).ok_or(ArithmeticError::Overflow)?; - ensure!( - new <= ::MaxWinners::get(), - Error::::TooManyValidators - ); + ensure!(new <= T::MaxValidatorsCount::get(), Error::::TooManyValidators); ValidatorCount::::put(new); Ok(()) From 65887146be1a0bc177b5a2b0008100993a5b2822 Mon Sep 17 00:00:00 2001 From: giuseppere Date: Mon, 16 Dec 2024 16:06:13 +0100 Subject: [PATCH 072/101] fix staking tests --- substrate/frame/staking/src/mock.rs | 3 ++- substrate/frame/staking/src/pallet/impls.rs | 4 ++-- substrate/frame/staking/src/pallet/mod.rs | 10 +++------- substrate/frame/staking/src/tests.rs | 6 +++--- 4 files changed, 10 insertions(+), 13 deletions(-) diff --git a/substrate/frame/staking/src/mock.rs b/substrate/frame/staking/src/mock.rs index aa4cf003be22..b10be61f2230 100644 --- a/substrate/frame/staking/src/mock.rs +++ b/substrate/frame/staking/src/mock.rs @@ -116,6 +116,7 @@ parameter_types! { pub static Period: BlockNumber = 5; pub static Offset: BlockNumber = 0; pub static MaxControllersInDeprecationBatch: u32 = 5900; + pub static MaxValidatorsCount: u32 = 300; } #[derive_impl(frame_system::config_preludes::TestDefaultConfig)] @@ -290,7 +291,7 @@ impl crate::pallet::pallet::Config for Test { pallet_staking::UpToLimitWithReEnablingDisablingStrategy; type MaxInvulnerables = ConstU32<20>; type MaxRewardPagesPerValidator = ConstU32<20>; - type MaxValidatorsCount = ConstU32<300>; + type MaxValidatorsCount = MaxValidatorsCount; type MaxDisabledValidators = ConstU32<100>; } diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs index d4e038e2a51c..a8ed37468981 100644 --- a/substrate/frame/staking/src/pallet/impls.rs +++ b/substrate/frame/staking/src/pallet/impls.rs @@ -2069,7 +2069,7 @@ impl Pallet { /// * Number of voters in `VoterList` match that of the number of Nominators and Validators in /// the system (validator is both voter and target). /// * Number of targets in `TargetList` matches the number of validators in the system. - /// * Current validator count is bounded by the election provider's max winners. + /// * Current validator count is bounded by `MaxValidatorsCount`. fn check_count() -> Result<(), TryRuntimeError> { ensure!( ::VoterList::count() == @@ -2081,7 +2081,7 @@ impl Pallet { "wrong external count" ); ensure!( - ValidatorCount::::get() <= ::MaxWinners::get(), + ValidatorCount::::get() <= T::MaxValidatorsCount::get(), Error::::TooManyValidators ); Ok(()) diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs index df7f213cec5f..4a88a4df143d 100644 --- a/substrate/frame/staking/src/pallet/mod.rs +++ b/substrate/frame/staking/src/pallet/mod.rs @@ -759,10 +759,7 @@ pub mod pallet { ), _ => Ok(()), }); - assert!( - ValidatorCount::::get() <= - ::MaxWinners::get() - ); + assert!(ValidatorCount::::get() <= T::MaxValidatorsCount::get()); } // all voters are reported to the `VoterList`. @@ -1537,8 +1534,7 @@ pub mod pallet { Ok(()) } - /// Increments the ideal number of validators up to maximum of - /// `ElectionProviderBase::MaxWinners`. + /// Increments the ideal number of validators up to maximum of `T::MaxValidatorsCount`. /// /// The dispatch origin must be Root. /// @@ -1560,7 +1556,7 @@ pub mod pallet { } /// Scale up the ideal number of validators by a factor up to maximum of - /// `ElectionProviderBase::MaxWinners`. + /// `T::MaxValidatorsCount`. /// /// The dispatch origin must be Root. /// diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index 406ba23b1af5..7111405c625b 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -6461,7 +6461,7 @@ fn reducing_max_unlocking_chunks_abrupt() { #[test] fn cannot_set_unsupported_validator_count() { ExtBuilder::default().build_and_execute(|| { - MaxWinners::set(50); + MaxValidatorsCount::set(50); // set validator count works assert_ok!(Staking::set_validator_count(RuntimeOrigin::root(), 30)); assert_ok!(Staking::set_validator_count(RuntimeOrigin::root(), 50)); @@ -6476,7 +6476,7 @@ fn cannot_set_unsupported_validator_count() { #[test] fn increase_validator_count_errors() { ExtBuilder::default().build_and_execute(|| { - MaxWinners::set(50); + MaxValidatorsCount::set(50); assert_ok!(Staking::set_validator_count(RuntimeOrigin::root(), 40)); // increase works @@ -6494,7 +6494,7 @@ fn increase_validator_count_errors() { #[test] fn scale_validator_count_errors() { ExtBuilder::default().build_and_execute(|| { - MaxWinners::set(50); + MaxValidatorsCount::set(50); assert_ok!(Staking::set_validator_count(RuntimeOrigin::root(), 20)); // scale value works From 76a2d4b7886c6e5fac94b0ecb6994edd1517cdab Mon Sep 17 00:00:00 2001 From: giuseppere Date: Tue, 17 Dec 2024 12:12:32 +0100 Subject: [PATCH 073/101] Fix staking tests --- substrate/frame/staking/src/pallet/mod.rs | 2 +- substrate/frame/staking/src/tests.rs | 75 +++++++---------------- 2 files changed, 24 insertions(+), 53 deletions(-) diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs index 4a88a4df143d..114b4cf6ab7a 100644 --- a/substrate/frame/staking/src/pallet/mod.rs +++ b/substrate/frame/staking/src/pallet/mod.rs @@ -1340,7 +1340,7 @@ pub mod pallet { // calling `chill_other`. Until then, we explicitly block new validators to protect // the runtime. ensure!( - Validators::::count() <= T::MaxValidatorsCount::get(), + Validators::::count() < T::MaxValidatorsCount::get(), Error::::TooManyValidators, ); } diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index 7111405c625b..850a874af3a1 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -4411,7 +4411,7 @@ fn test_page_count_and_size() { assert_eq!(EraInfo::::get_paged_exposure(2, &11, 3).unwrap().others().len(), 4); // now lets decrease page size even more - MaxExposurePageSize::set(20); + MaxExposurePageSize::set(5); mock::start_active_era(3); // now we expect the max 20 pages (100/5). @@ -5722,11 +5722,13 @@ fn chill_other_works() { ); // Add limits, but no threshold + let max = 10; + MaxValidatorsCount::set(max); assert_ok!(Staking::set_staking_configs( RuntimeOrigin::root(), ConfigOp::Noop, ConfigOp::Noop, - ConfigOp::Set(10), + ConfigOp::Set(max), ConfigOp::Noop, ConfigOp::Noop, ConfigOp::Noop, @@ -5809,6 +5811,7 @@ fn capped_stakers_works() { // Change the maximums let max = 10; + MaxValidatorsCount::set(max); assert_ok!(Staking::set_staking_configs( RuntimeOrigin::root(), ConfigOp::Set(10), @@ -5878,7 +5881,8 @@ fn capped_stakers_works() { ValidatorPrefs::default() )); - // No problem when we set to `None` again + // No problem when we set to `None` again and increase MaxValidatorsCount + MaxValidatorsCount::set(2 * MaxValidatorsCount::get()); assert_ok!(Staking::set_staking_configs( RuntimeOrigin::root(), ConfigOp::Noop, @@ -6682,66 +6686,33 @@ fn test_runtime_api_pending_rewards() { // add exposure for validators EraInfo::::set_exposure(0, &validator_one, exposure.clone()); EraInfo::::set_exposure(0, &validator_two, exposure.clone()); - EraInfo::::set_exposure(0, &validator_three, exposure.clone()); // add some reward to be distributed ErasValidatorReward::::insert(0, 1000); - // mark rewards claimed for validator_one in legacy claimed rewards - >::insert( - validator_one, - StakingLedgerInspect { - stash: validator_one, - total: stake, - active: stake, - unlocking: Default::default(), - legacy_claimed_rewards: bounded_vec![0], - }, - ); - - // SCENARIO ONE: rewards already marked claimed in legacy storage. - // runtime api should return false for pending rewards for validator_one. + // SCENARIO: Validator with paged exposure (two pages). + // validators have not claimed rewards, so pending rewards is true. + assert!(EraInfo::::pending_rewards(0, &validator_one)); + assert!(EraInfo::::pending_rewards(0, &validator_two)); + // and payout works + assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), validator_one, 0)); + assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), validator_two, 0)); + // validators have two pages of exposure, so pending rewards is still true. + assert!(EraInfo::::pending_rewards(0, &validator_one)); + assert!(EraInfo::::pending_rewards(0, &validator_two)); + // payout again only for validator one + assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), validator_one, 0)); + // now pending rewards is false for validator one assert!(!EraInfo::::pending_rewards(0, &validator_one)); - // and if we try to pay, we get an error. + // and payout fails for validator one assert_noop!( Staking::payout_stakers(RuntimeOrigin::signed(1337), validator_one, 0), Error::::AlreadyClaimed.with_weight(err_weight) ); - - // SCENARIO TWO: non-paged exposure - // validator two has not claimed rewards, so pending rewards is true. + // while pending reward is true for validator two assert!(EraInfo::::pending_rewards(0, &validator_two)); - // and payout works + // and payout works again for validator two. assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), validator_two, 0)); - // now pending rewards is false. - assert!(!EraInfo::::pending_rewards(0, &validator_two)); - // and payout fails - assert_noop!( - Staking::payout_stakers(RuntimeOrigin::signed(1337), validator_two, 0), - Error::::AlreadyClaimed.with_weight(err_weight) - ); - - // SCENARIO THREE: validator with paged exposure (two pages). - // validator three has not claimed rewards, so pending rewards is true. - assert!(EraInfo::::pending_rewards(0, &validator_three)); - // and payout works - assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), validator_three, 0)); - // validator three has two pages of exposure, so pending rewards is still true. - assert!(EraInfo::::pending_rewards(0, &validator_three)); - // payout again - assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), validator_three, 0)); - // now pending rewards is false. - assert!(!EraInfo::::pending_rewards(0, &validator_three)); - // and payout fails - assert_noop!( - Staking::payout_stakers(RuntimeOrigin::signed(1337), validator_three, 0), - Error::::AlreadyClaimed.with_weight(err_weight) - ); - - // for eras with no exposure, pending rewards is false. - assert!(!EraInfo::::pending_rewards(0, &validator_one)); - assert!(!EraInfo::::pending_rewards(0, &validator_two)); - assert!(!EraInfo::::pending_rewards(0, &validator_three)); }); } From bd28db503262403b9aa13e3d8101d1ca5ef2acac Mon Sep 17 00:00:00 2001 From: giuseppere Date: Tue, 17 Dec 2024 14:43:45 +0100 Subject: [PATCH 074/101] fix benchmark --- .../runtime/parachains/src/disputes/slashing/benchmarking.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/polkadot/runtime/parachains/src/disputes/slashing/benchmarking.rs b/polkadot/runtime/parachains/src/disputes/slashing/benchmarking.rs index c93202c1e66f..335d9e591c2b 100644 --- a/polkadot/runtime/parachains/src/disputes/slashing/benchmarking.rs +++ b/polkadot/runtime/parachains/src/disputes/slashing/benchmarking.rs @@ -144,7 +144,7 @@ benchmarks! { // in this setup we have a single `ForInvalid` dispute // submitted for a past session report_dispute_lost { - let n in 4..::MaxValidatorsCount::get(); + let n in 4..::MaxValidatorsCount::get() - 1; let origin = RawOrigin::None.into(); let (session_index, key_owner_proof, validator_id) = setup_validator_set::(n); From 043b7d616ac255a5403525e5533d7cca7cfc7773 Mon Sep 17 00:00:00 2001 From: giuseppere Date: Tue, 17 Dec 2024 14:45:09 +0100 Subject: [PATCH 075/101] comment nit --- .../runtime/parachains/src/disputes/slashing/benchmarking.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/polkadot/runtime/parachains/src/disputes/slashing/benchmarking.rs b/polkadot/runtime/parachains/src/disputes/slashing/benchmarking.rs index 335d9e591c2b..770ca116fb57 100644 --- a/polkadot/runtime/parachains/src/disputes/slashing/benchmarking.rs +++ b/polkadot/runtime/parachains/src/disputes/slashing/benchmarking.rs @@ -141,8 +141,7 @@ benchmarks! { where T: Config, } - // in this setup we have a single `ForInvalid` dispute - // submitted for a past session + // in this setup we have a single `ForInvalid` dispute submitted for a past session report_dispute_lost { let n in 4..::MaxValidatorsCount::get() - 1; From 68481f43d6538fb87bcd29018ec35054281a1fcd Mon Sep 17 00:00:00 2001 From: giuseppere Date: Tue, 17 Dec 2024 17:14:31 +0100 Subject: [PATCH 076/101] Always link `BondingDuration` to `MaxBondedEras` in tests --- substrate/frame/babe/src/mock.rs | 2 ++ .../election-provider-multi-phase/test-staking-e2e/src/mock.rs | 3 +++ substrate/frame/fast-unstake/src/mock.rs | 2 ++ .../frame/nomination-pools/test-transfer-stake/src/mock.rs | 2 ++ substrate/frame/root-offences/src/mock.rs | 2 ++ 5 files changed, 11 insertions(+) diff --git a/substrate/frame/babe/src/mock.rs b/substrate/frame/babe/src/mock.rs index 5df8ed83f7a5..99fc692a1629 100644 --- a/substrate/frame/babe/src/mock.rs +++ b/substrate/frame/babe/src/mock.rs @@ -141,6 +141,7 @@ pallet_staking_reward_curve::build! { parameter_types! { pub const SessionsPerEra: SessionIndex = 3; pub const BondingDuration: EraIndex = 3; + pub const MaxBondedEras: u32 = (BondingDuration::get() as u32) + 1; pub const RewardCurve: &'static PiecewiseLinear<'static> = &REWARD_CURVE; pub static ElectionsBounds: ElectionBounds = ElectionBoundsBuilder::default().build(); } @@ -160,6 +161,7 @@ impl pallet_staking::Config for Test { type Currency = Balances; type SessionsPerEra = SessionsPerEra; type BondingDuration = BondingDuration; + type MaxBondedEras = MaxBondedEras; type AdminOrigin = frame_system::EnsureRoot; type SessionInterface = Self; type UnixTime = pallet_timestamp::Pallet; diff --git a/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/mock.rs b/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/mock.rs index eaab848c1694..d9e6b7353e71 100644 --- a/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/mock.rs +++ b/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/mock.rs @@ -227,6 +227,7 @@ parameter_types! { pub static BagThresholds: &'static [sp_npos_elections::VoteWeight] = &THRESHOLDS; pub const SessionsPerEra: sp_staking::SessionIndex = 2; pub static BondingDuration: sp_staking::EraIndex = 28; + pub static MaxBondedEras: u32 = (BondingDuration::get() as u32) + 1; pub const SlashDeferDuration: sp_staking::EraIndex = 7; // 1/4 the bonding duration. } @@ -290,6 +291,7 @@ impl pallet_staking::Config for Runtime { type UnixTime = Timestamp; type SessionsPerEra = SessionsPerEra; type BondingDuration = BondingDuration; + type MaxBondedEras = MaxBondedEras; type SlashDeferDuration = SlashDeferDuration; type AdminOrigin = EnsureRoot; // root can cancel slashes type SessionInterface = Self; @@ -437,6 +439,7 @@ impl StakingExtBuilder { } pub fn bonding_duration(self, eras: EraIndex) -> Self { ::set(eras); + ::set(eras + 1); self } } diff --git a/substrate/frame/fast-unstake/src/mock.rs b/substrate/frame/fast-unstake/src/mock.rs index 757052e230a1..c1fbe2209345 100644 --- a/substrate/frame/fast-unstake/src/mock.rs +++ b/substrate/frame/fast-unstake/src/mock.rs @@ -80,6 +80,7 @@ pallet_staking_reward_curve::build! { parameter_types! { pub const RewardCurve: &'static sp_runtime::curve::PiecewiseLinear<'static> = &I_NPOS; pub static BondingDuration: u32 = 3; + pub static MaxBondedEras: u32 = BondingDuration::get() + 1; pub static CurrentEra: u32 = 0; pub static Ongoing: bool = false; pub static MaxWinners: u32 = 100; @@ -109,6 +110,7 @@ impl pallet_staking::Config for Runtime { type UnixTime = pallet_timestamp::Pallet; type AdminOrigin = frame_system::EnsureRoot; type BondingDuration = BondingDuration; + type MaxBondedEras = MaxBondedEras; type EraPayout = pallet_staking::ConvertCurve; type ElectionProvider = MockElection; type GenesisElectionProvider = Self::ElectionProvider; diff --git a/substrate/frame/nomination-pools/test-transfer-stake/src/mock.rs b/substrate/frame/nomination-pools/test-transfer-stake/src/mock.rs index 675c5f2ab14a..e564ae23c27b 100644 --- a/substrate/frame/nomination-pools/test-transfer-stake/src/mock.rs +++ b/substrate/frame/nomination-pools/test-transfer-stake/src/mock.rs @@ -80,6 +80,7 @@ pallet_staking_reward_curve::build! { parameter_types! { pub const RewardCurve: &'static sp_runtime::curve::PiecewiseLinear<'static> = &I_NPOS; pub static BondingDuration: u32 = 3; + pub static MaxBondedEras: u32 = BondingDuration::get() + 1; } #[derive_impl(pallet_staking::config_preludes::TestDefaultConfig)] @@ -88,6 +89,7 @@ impl pallet_staking::Config for Runtime { type UnixTime = pallet_timestamp::Pallet; type AdminOrigin = frame_system::EnsureRoot; type BondingDuration = BondingDuration; + type MaxBondedEras = MaxBondedEras; type EraPayout = pallet_staking::ConvertCurve; type ElectionProvider = frame_election_provider_support::NoElection<(AccountId, BlockNumber, Staking, ())>; diff --git a/substrate/frame/root-offences/src/mock.rs b/substrate/frame/root-offences/src/mock.rs index b5fdd56daf6d..c34e6e0bf237 100644 --- a/substrate/frame/root-offences/src/mock.rs +++ b/substrate/frame/root-offences/src/mock.rs @@ -123,6 +123,7 @@ parameter_types! { pub static SessionsPerEra: SessionIndex = 3; pub static SlashDeferDuration: EraIndex = 0; pub const BondingDuration: EraIndex = 3; + pub const MaxBondedEras: u32 = (BondingDuration::get() as u32) + 1; pub static LedgerSlashPerEra: (BalanceOf, BTreeMap>) = (Zero::zero(), BTreeMap::new()); } @@ -135,6 +136,7 @@ impl pallet_staking::Config for Test { type SlashDeferDuration = SlashDeferDuration; type AdminOrigin = frame_system::EnsureRoot; type BondingDuration = BondingDuration; + type MaxBondedEras = MaxBondedEras; type SessionInterface = Self; type EraPayout = pallet_staking::ConvertCurve; type NextNewSession = Session; From d508f8d70acd9c1a5c74d116c19dee757befa644 Mon Sep 17 00:00:00 2001 From: giuseppere Date: Wed, 18 Dec 2024 10:44:10 +0100 Subject: [PATCH 077/101] Remove old `MaxValidatorCount` from expected default genesis config --- substrate/bin/node/cli/tests/res/default_genesis_config.json | 1 - 1 file changed, 1 deletion(-) diff --git a/substrate/bin/node/cli/tests/res/default_genesis_config.json b/substrate/bin/node/cli/tests/res/default_genesis_config.json index a2e52837d882..17cc618a6f6f 100644 --- a/substrate/bin/node/cli/tests/res/default_genesis_config.json +++ b/substrate/bin/node/cli/tests/res/default_genesis_config.json @@ -30,7 +30,6 @@ "stakers": [], "minNominatorBond": 0, "minValidatorBond": 0, - "maxValidatorCount": null, "maxNominatorCount": null }, "session": { From 17eeef7eb4166c00c6d7907110838ef9ca8bf6cb Mon Sep 17 00:00:00 2001 From: Giuseppe Re Date: Wed, 18 Dec 2024 14:32:20 +0100 Subject: [PATCH 078/101] Update cumulus/parachains/integration-tests/emulated/chains/relays/westend/src/genesis.rs Co-authored-by: Guillaume Thiolliere --- .../emulated/chains/relays/westend/src/genesis.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cumulus/parachains/integration-tests/emulated/chains/relays/westend/src/genesis.rs b/cumulus/parachains/integration-tests/emulated/chains/relays/westend/src/genesis.rs index 5b8d5a0c97ac..9ebb5e210538 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/relays/westend/src/genesis.rs +++ b/cumulus/parachains/integration-tests/emulated/chains/relays/westend/src/genesis.rs @@ -92,7 +92,7 @@ pub fn genesis() -> Storage { .map(|x| x.0.clone()) .collect::>(), ) - .unwrap(), + .expect("Limit for staking invulnerables must be less than initial authorities."), force_era: pallet_staking::Forcing::ForceNone, slash_reward_fraction: Perbill::from_percent(10), ..Default::default() From 21a12d182d08ad0b61e18cb493909e24c0302aca Mon Sep 17 00:00:00 2001 From: giuseppere Date: Wed, 18 Dec 2024 14:41:59 +0100 Subject: [PATCH 079/101] Fix PR title in prdoc and migrations for old deprecated storage items --- prdoc/pr_6445.prdoc | 9 ++------- substrate/frame/staking/src/migrations.rs | 24 +++++++++++++++++++++++ 2 files changed, 26 insertions(+), 7 deletions(-) diff --git a/prdoc/pr_6445.prdoc b/prdoc/pr_6445.prdoc index 79e3e6b7b034..36bb6d00fac2 100644 --- a/prdoc/pr_6445.prdoc +++ b/prdoc/pr_6445.prdoc @@ -1,4 +1,4 @@ -title: Add storage bounds for pallet `staking` +title: Add storage bounds for pallet `staking` and clean up deprecated non paged exposure storages doc: - audience: Runtime Dev description: |- @@ -17,18 +17,13 @@ doc: - Completing the task from #5986 - Use `MaxExposurePageSize` to bound `ErasStakersPaged` mapping to exposure pages: each `ExposurePage.others` Vec is turned into a `WeakBoundedVec` to allow easy and quick changes to this bound - Add `MaxBondedEras` to bound `BondedEras` Vec -> `BoundedVec` - - Set to `BondingDuration::get() + 1` everywhere to include both time interval endpoints in [`current_era - BondingDuration::get()`, `current_era`] + - Set to `BondingDuration::get() + 1` everywhere to include both time interval endpoints in [`current_era - BondingDuration::get()`, `current_era`]. Notice that this was done manually in every test and runtime. - Add `MaxRewardPagesPerValidator` to bound `ClaimedRewards` Vec of pages -> `WeakBoundedVec` - Set to constant 20 in the pallet. The vector of pages is now a `WeakBoundedVec` to allow easy and quick changes to this parameter - Remove `MaxValidatorsCount` optional storage item to add `MaxValidatorsCount` mandatory config parameter - Using it to to bound `EraRewardPoints.individual` BTreeMap -> `BoundedBTreeMap`; - Set to dynamic parameter in runtime westend so that changing it should not require migrations for it - **TO DO** - Slashing storage items will be bounded in another PR. - - - `UnappliedSlashes` - - `SlashingSpans` crates: - name: pallet-staking bump: major diff --git a/substrate/frame/staking/src/migrations.rs b/substrate/frame/staking/src/migrations.rs index 35de7b429f30..7c66f629ce5e 100644 --- a/substrate/frame/staking/src/migrations.rs +++ b/substrate/frame/staking/src/migrations.rs @@ -71,6 +71,8 @@ pub mod v17 { let mut migration_errors = false; v16::MaxValidatorsCount::::kill(); + v16::ErasStakers::::kill(); + v16::ErasStakersClipped::::kill(); let old_disabled_validators = v16::DisabledValidators::::get(); // BoundedVec with MaxDisabledValidators limit, this should always work @@ -254,6 +256,28 @@ pub mod v16 { #[frame_support::storage_alias] pub(crate) type MaxValidatorsCount = StorageValue, u32, OptionQuery>; + #[frame_support::storage_alias] + pub(crate) type ErasStakers = StorageDoubleMap< + Pallet, + Twox64Concat, + EraIndex, + Twox64Concat, + ::AccountId, + Exposure<::AccountId, BalanceOf>, + ValueQuery, + >; + + #[frame_support::storage_alias] + pub(crate) type ErasStakersClipped = StorageDoubleMap< + Pallet, + Twox64Concat, + EraIndex, + Twox64Concat, + ::AccountId, + Exposure<::AccountId, BalanceOf>, + ValueQuery, + >; + pub struct VersionUncheckedMigrateV15ToV16(core::marker::PhantomData); impl UncheckedOnRuntimeUpgrade for VersionUncheckedMigrateV15ToV16 { #[cfg(feature = "try-runtime")] From e2fa0ca4db838d4cdccc25b5d4666dd16e70e0fe Mon Sep 17 00:00:00 2001 From: Giuseppe Re Date: Wed, 18 Dec 2024 14:44:49 +0100 Subject: [PATCH 080/101] Update substrate/frame/staking/src/lib.rs Co-authored-by: Guillaume Thiolliere --- substrate/frame/staking/src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/substrate/frame/staking/src/lib.rs b/substrate/frame/staking/src/lib.rs index 5c2f47c17e3d..89add4796135 100644 --- a/substrate/frame/staking/src/lib.rs +++ b/substrate/frame/staking/src/lib.rs @@ -1062,7 +1062,6 @@ where pub struct EraInfo(core::marker::PhantomData); impl EraInfo { /// Returns true if validator has one or more page of era rewards not claimed yet. - // Also looks at legacy storage that can be cleaned up after #433. pub fn pending_rewards(era: EraIndex, validator: &T::AccountId) -> bool { >::get(&era, validator) .map(|overview| { From 4bf3cd6ebf5956f7c23172917d85347db35c4410 Mon Sep 17 00:00:00 2001 From: giuseppere Date: Wed, 18 Dec 2024 14:47:48 +0100 Subject: [PATCH 081/101] add debug msg --- substrate/bin/node/testing/src/genesis.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/substrate/bin/node/testing/src/genesis.rs b/substrate/bin/node/testing/src/genesis.rs index dcff7ca66ef1..778b39c9d143 100644 --- a/substrate/bin/node/testing/src/genesis.rs +++ b/substrate/bin/node/testing/src/genesis.rs @@ -65,7 +65,8 @@ pub fn config_endowed(extra_endowed: Vec) -> RuntimeGenesisConfig { validator_count: 3, minimum_validator_count: 0, slash_reward_fraction: Perbill::from_percent(10), - invulnerables: BoundedVec::try_from(vec![alice(), bob(), charlie()]).unwrap(), + invulnerables: BoundedVec::try_from(vec![alice(), bob(), charlie()]) + .expect("Too many invulnerable validators!"), ..Default::default() }, society: SocietyConfig { pot: 0 }, From f7c1fe4f113449b14d6323f2543d5a83752d192e Mon Sep 17 00:00:00 2001 From: giuseppere Date: Wed, 18 Dec 2024 15:01:43 +0100 Subject: [PATCH 082/101] fix migrations --- substrate/frame/staking/src/migrations.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/substrate/frame/staking/src/migrations.rs b/substrate/frame/staking/src/migrations.rs index 7c66f629ce5e..0e98a9633022 100644 --- a/substrate/frame/staking/src/migrations.rs +++ b/substrate/frame/staking/src/migrations.rs @@ -71,8 +71,8 @@ pub mod v17 { let mut migration_errors = false; v16::MaxValidatorsCount::::kill(); - v16::ErasStakers::::kill(); - v16::ErasStakersClipped::::kill(); + v16::ErasStakers::::remove_all(None); + v16::ErasStakersClipped::::remove_all(None); let old_disabled_validators = v16::DisabledValidators::::get(); // BoundedVec with MaxDisabledValidators limit, this should always work From c881bb0015cfd0c9248ebd53f751ff267b5ba5d9 Mon Sep 17 00:00:00 2001 From: giuseppere Date: Wed, 18 Dec 2024 15:20:13 +0100 Subject: [PATCH 083/101] fix comments + CR --- substrate/frame/staking/src/benchmarking.rs | 1 - substrate/frame/staking/src/lib.rs | 18 +++++++++--------- substrate/frame/staking/src/pallet/mod.rs | 8 ++++---- 3 files changed, 13 insertions(+), 14 deletions(-) diff --git a/substrate/frame/staking/src/benchmarking.rs b/substrate/frame/staking/src/benchmarking.rs index 9ca3d6130dcf..c9e0fd73bc28 100644 --- a/substrate/frame/staking/src/benchmarking.rs +++ b/substrate/frame/staking/src/benchmarking.rs @@ -602,7 +602,6 @@ mod benchmarks { } #[benchmark] - // Worst case scenario according to the invulnerables limit. fn set_invulnerables(v: Linear<0, { T::MaxInvulnerables::get() }>) { let mut invulnerables = Vec::new(); for i in 0..v { diff --git a/substrate/frame/staking/src/lib.rs b/substrate/frame/staking/src/lib.rs index 89add4796135..5ee0aaea7708 100644 --- a/substrate/frame/staking/src/lib.rs +++ b/substrate/frame/staking/src/lib.rs @@ -759,12 +759,12 @@ impl< MaxExposurePageSize: Get, > PagedExposure { - /// Create a new instance of `PagedExposure` from legacy clipped exposures. - pub fn from_clipped(exposure: Exposure) -> Self { + /// Create a new instance of `PagedExposure` from legacy clipped exposures (now removed). + pub fn from_clipped(exposure: Exposure) -> Result { let old_exposures = exposure.others.len(); let others = WeakBoundedVec::try_from(exposure.others).unwrap_or_default(); defensive_assert!(old_exposures == others.len(), "Too many exposures for a page"); - Self { + Ok(Self { exposure_metadata: PagedExposureMetadata { total: exposure.total, own: exposure.own, @@ -772,7 +772,7 @@ impl< page_count: 1, }, exposure_page: ExposurePage { page_total: exposure.total, others }, - } + }) } /// Returns total exposure of this validator across pages @@ -1119,11 +1119,11 @@ impl EraInfo { let mut others = Vec::with_capacity(overview.nominator_count as usize); for page in 0..overview.page_count { - let nominators = - >::get((era, validator, page)).defensive_unwrap_or_default(); - for nominator_exposure in nominators.others { - others.push(nominator_exposure); - } + let mut nominators_exposures = >::get((era, validator, page)) + .defensive_unwrap_or_default() + .others + .into_inner(); + others.append(&mut nominators_exposures); } Exposure { total: overview.total, own: overview.own, others } diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs index 114b4cf6ab7a..32ca05b57135 100644 --- a/substrate/frame/staking/src/pallet/mod.rs +++ b/substrate/frame/staking/src/pallet/mod.rs @@ -236,15 +236,15 @@ pub mod pallet { /// An `ExposurePage` is weakly bounded to a maximum of `MaxExposurePageSize` /// nominators. /// - /// Note: `MaxExposurePageSize` is used to bound `ClaimedRewards` and is unsafe to reduce - /// without handling it in a migration. + /// Note: `MaxExposurePageSize` is used to (weakly) bound the size of an `ExposurePage` and + /// it may be unsafe to reduce without handling it in a migration. #[pallet::constant] type MaxExposurePageSize: Get; /// The maximum number of nominators reward pages per nominator. /// - /// Note: `MaxRewardPagesPerValidator` is used to bound the number of pages in - /// `ClaimedRewards` and is unsafe to reduce without handling it in a migration. + /// Note: `MaxRewardPagesPerValidator` is used to (weakly) bound the number of pages in + /// `ClaimedRewards` and it may be unsafe to reduce without handling it in a migration. #[pallet::constant] type MaxRewardPagesPerValidator: Get; From 2da736ae7f85445221e9b8995849a7a833487706 Mon Sep 17 00:00:00 2001 From: giuseppere Date: Wed, 18 Dec 2024 15:29:38 +0100 Subject: [PATCH 084/101] Add more debugging `expect(...)` in tests --- polkadot/runtime/westend/src/genesis_config_presets.rs | 4 ++-- substrate/frame/staking/src/mock.rs | 3 ++- substrate/frame/staking/src/tests.rs | 4 +++- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/polkadot/runtime/westend/src/genesis_config_presets.rs b/polkadot/runtime/westend/src/genesis_config_presets.rs index bc9e249e1937..f65c975327e6 100644 --- a/polkadot/runtime/westend/src/genesis_config_presets.rs +++ b/polkadot/runtime/westend/src/genesis_config_presets.rs @@ -205,7 +205,7 @@ fn westend_testnet_genesis( invulnerables: BoundedVec::try_from( initial_authorities.iter().map(|x| x.0.clone()).collect::>() ) - .unwrap(), + .expect("Too many invulnerable validators!"), force_era: Forcing::NotForcing, slash_reward_fraction: Perbill::from_percent(10), }, @@ -379,7 +379,7 @@ fn westend_staging_testnet_config_genesis() -> serde_json::Value { invulnerables: BoundedVec::try_from( initial_authorities.iter().map(|x| x.0.clone()).collect::>() ) - .unwrap(), + .expect("Too many invulnerable validators!"), force_era: Forcing::ForceNone, slash_reward_fraction: Perbill::from_percent(10), }, diff --git a/substrate/frame/staking/src/mock.rs b/substrate/frame/staking/src/mock.rs index b10be61f2230..616aaa0f1ba3 100644 --- a/substrate/frame/staking/src/mock.rs +++ b/substrate/frame/staking/src/mock.rs @@ -378,7 +378,8 @@ impl ExtBuilder { self } pub fn invulnerables(mut self, invulnerables: Vec) -> Self { - self.invulnerables = BoundedVec::try_from(invulnerables).unwrap(); + self.invulnerables = + BoundedVec::try_from(invulnerables).expect("Too many invulnerable validators!"); self } pub fn session_per_era(self, length: SessionIndex) -> Self { diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index 850a874af3a1..1e9a06e8be9d 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -8523,7 +8523,9 @@ mod getters { sp_io::TestExternalities::default().execute_with(|| { // given let v: Vec = vec![1, 2, 3]; - Invulnerables::::put(BoundedVec::try_from(v.clone()).unwrap()); + Invulnerables::::put( + BoundedVec::try_from(v.clone()).expect("Too many invulnerable validators!"), + ); // when let result = Staking::invulnerables(); From 831f1b0675a588655bde4596657f9f0be0eb8df6 Mon Sep 17 00:00:00 2001 From: giuseppere Date: Wed, 18 Dec 2024 15:55:53 +0100 Subject: [PATCH 085/101] fix migrations --- substrate/frame/staking/src/migrations.rs | 32 +++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/substrate/frame/staking/src/migrations.rs b/substrate/frame/staking/src/migrations.rs index 0e98a9633022..c4828054d597 100644 --- a/substrate/frame/staking/src/migrations.rs +++ b/substrate/frame/staking/src/migrations.rs @@ -71,8 +71,36 @@ pub mod v17 { let mut migration_errors = false; v16::MaxValidatorsCount::::kill(); - v16::ErasStakers::::remove_all(None); - v16::ErasStakersClipped::::remove_all(None); + + let mut eras_stakers_keys = + v16::ErasStakers::::iter_keys().map(|(k1, k2)| k1).collect::>(); + eras_stakers_keys.dedup(); + for k in eras_stakers_keys { + let mut removal_result = + v16::ErasStakers::::clear_prefix(k, u32::max_value(), None); + while let Some(next_cursor) = removal_result.maybe_cursor { + removal_result = v16::ErasStakers::::clear_prefix( + k, + u32::max_value(), + Some(&next_cursor[..]), + ); + } + } + + let mut eras_stakers_clipped_keys = + v16::ErasStakersClipped::::iter_keys().map(|(k1, k2)| k1).collect::>(); + eras_stakers_clipped_keys.dedup(); + for k in eras_stakers_clipped_keys { + let mut removal_result = + v16::ErasStakersClipped::::clear_prefix(k, u32::max_value(), None); + while let Some(next_cursor) = removal_result.maybe_cursor { + removal_result = v16::ErasStakersClipped::::clear_prefix( + k, + u32::max_value(), + Some(&next_cursor[..]), + ); + } + } let old_disabled_validators = v16::DisabledValidators::::get(); // BoundedVec with MaxDisabledValidators limit, this should always work From 3702ce5da7e8d7ed4e028c95d4a49ce9c3f61110 Mon Sep 17 00:00:00 2001 From: giuseppere Date: Thu, 19 Dec 2024 10:29:52 +0100 Subject: [PATCH 086/101] prefix with `_` unused variables --- substrate/frame/staking/src/migrations.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/substrate/frame/staking/src/migrations.rs b/substrate/frame/staking/src/migrations.rs index c4828054d597..616aa94fa388 100644 --- a/substrate/frame/staking/src/migrations.rs +++ b/substrate/frame/staking/src/migrations.rs @@ -73,7 +73,7 @@ pub mod v17 { v16::MaxValidatorsCount::::kill(); let mut eras_stakers_keys = - v16::ErasStakers::::iter_keys().map(|(k1, k2)| k1).collect::>(); + v16::ErasStakers::::iter_keys().map(|(k1, _k2)| k1).collect::>(); eras_stakers_keys.dedup(); for k in eras_stakers_keys { let mut removal_result = @@ -87,8 +87,9 @@ pub mod v17 { } } - let mut eras_stakers_clipped_keys = - v16::ErasStakersClipped::::iter_keys().map(|(k1, k2)| k1).collect::>(); + let mut eras_stakers_clipped_keys = v16::ErasStakersClipped::::iter_keys() + .map(|(k1, _k2)| k1) + .collect::>(); eras_stakers_clipped_keys.dedup(); for k in eras_stakers_clipped_keys { let mut removal_result = From 489fc9ddc092f1fad2876551b4a3254096bc29d8 Mon Sep 17 00:00:00 2001 From: giuseppere Date: Thu, 19 Dec 2024 11:10:12 +0100 Subject: [PATCH 087/101] remove unused `page_size` fn arg + fix tests --- substrate/frame/staking/src/lib.rs | 3 +-- substrate/frame/staking/src/tests.rs | 3 ++- substrate/primitives/staking/src/lib.rs | 7 ++++--- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/substrate/frame/staking/src/lib.rs b/substrate/frame/staking/src/lib.rs index 5ee0aaea7708..2bec5eab3fc3 100644 --- a/substrate/frame/staking/src/lib.rs +++ b/substrate/frame/staking/src/lib.rs @@ -1200,8 +1200,7 @@ impl EraInfo { .defensive_saturating_add((page_size as usize).defensive_saturating_sub(1)) .saturating_div(page_size as usize); - let (exposure_metadata, exposure_pages) = - exposure.into_pages::(page_size); + let (exposure_metadata, exposure_pages) = exposure.into_pages::(); defensive_assert!(exposure_pages.len() == expected_page_count, "unexpected page count"); >::insert(era, &validator, &exposure_metadata); diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index 1e9a06e8be9d..8422b355dad4 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -6574,10 +6574,11 @@ fn can_page_exposure() { Exposure { total: total_stake, own: own_stake, others }; // when + MaxExposurePageSize::set(3); let (exposure_metadata, exposure_page): ( PagedExposureMetadata, Vec>, - ) = exposure.clone().into_pages::(3); + ) = exposure.clone().into_pages::(); // then // 7 pages of nominators. diff --git a/substrate/primitives/staking/src/lib.rs b/substrate/primitives/staking/src/lib.rs index fe7895ab5bc3..a9e14dc5858a 100644 --- a/substrate/primitives/staking/src/lib.rs +++ b/substrate/primitives/staking/src/lib.rs @@ -382,15 +382,16 @@ impl { /// Splits an `Exposure` into `PagedExposureMetadata` and multiple chunks of - /// `IndividualExposure` with each chunk having maximum of `page_size` elements. + /// `IndividualExposure` with each chunk having at least 1 element and a maximum of + /// `MaxExposurePageSize::get()` elements. pub fn into_pages( self, - page_size: Page, ) -> (PagedExposureMetadata, Vec>) where MaxExposurePageSize: Get, { - let individual_chunks = self.others.chunks(page_size as usize); + debug_assert!(MaxExposurePageSize::get() >= 1); + let individual_chunks = self.others.chunks(MaxExposurePageSize::get() as usize); let mut exposure_pages: Vec> = Vec::with_capacity(individual_chunks.len()); From a5e98e6e4047c1a7fda755e5bf8b9bdff6ea047f Mon Sep 17 00:00:00 2001 From: giuseppere Date: Thu, 19 Dec 2024 12:56:41 +0100 Subject: [PATCH 088/101] fix merge --- .../runtime/parachains/src/disputes/slashing/benchmarking.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/polkadot/runtime/parachains/src/disputes/slashing/benchmarking.rs b/polkadot/runtime/parachains/src/disputes/slashing/benchmarking.rs index 581d797a63f9..6be9c09dc8d9 100644 --- a/polkadot/runtime/parachains/src/disputes/slashing/benchmarking.rs +++ b/polkadot/runtime/parachains/src/disputes/slashing/benchmarking.rs @@ -31,7 +31,7 @@ const CANDIDATE_HASH: CandidateHash = CandidateHash(Hash::zero()); // Simplify getting the value in the benchmark pub const fn max_validators_for() -> u32 { - ::MaxValidatorsCount::get() - 1 + ::MaxValidatorsCount::get() } pub trait Config: From 7b82520e75f46d50da5892e08dd88a851d6539a2 Mon Sep 17 00:00:00 2001 From: giuseppere Date: Thu, 19 Dec 2024 13:01:30 +0100 Subject: [PATCH 089/101] fix merge --- .../runtime/parachains/src/disputes/slashing/benchmarking.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/polkadot/runtime/parachains/src/disputes/slashing/benchmarking.rs b/polkadot/runtime/parachains/src/disputes/slashing/benchmarking.rs index 6be9c09dc8d9..d5b2dd07e090 100644 --- a/polkadot/runtime/parachains/src/disputes/slashing/benchmarking.rs +++ b/polkadot/runtime/parachains/src/disputes/slashing/benchmarking.rs @@ -30,7 +30,7 @@ use sp_session::MembershipProof; const CANDIDATE_HASH: CandidateHash = CandidateHash(Hash::zero()); // Simplify getting the value in the benchmark -pub const fn max_validators_for() -> u32 { +pub const fn max_validators_for() -> u32 { ::MaxValidatorsCount::get() } From 30520af65c5f33774f12c81994455b693d085b15 Mon Sep 17 00:00:00 2001 From: giuseppere Date: Thu, 19 Dec 2024 13:02:18 +0100 Subject: [PATCH 090/101] fix merge --- .../parachains/src/disputes/slashing/benchmarking.rs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/polkadot/runtime/parachains/src/disputes/slashing/benchmarking.rs b/polkadot/runtime/parachains/src/disputes/slashing/benchmarking.rs index d5b2dd07e090..2ecb3052ac89 100644 --- a/polkadot/runtime/parachains/src/disputes/slashing/benchmarking.rs +++ b/polkadot/runtime/parachains/src/disputes/slashing/benchmarking.rs @@ -29,11 +29,6 @@ use sp_session::MembershipProof; // Candidate hash of the disputed candidate. const CANDIDATE_HASH: CandidateHash = CandidateHash(Hash::zero()); -// Simplify getting the value in the benchmark -pub const fn max_validators_for() -> u32 { - ::MaxValidatorsCount::get() -} - pub trait Config: pallet_session::Config + pallet_session::historical::Config @@ -148,7 +143,9 @@ mod benchmarks { use super::*; #[benchmark] - fn report_dispute_lost_unsigned(n: Linear<4, { max_validators_for::() - 1 }>) { + fn report_dispute_lost_unsigned( + n: Linear<4, { ::MaxValidatorsCount::get() - 1 }>, + ) { let (session_index, key_owner_proof, validator_id) = setup_validator_set::(n); // submit a single `ForInvalid` dispute for a past session. From 0d47dc565fbb24c5e0e44f67b36e3ffff160af6b Mon Sep 17 00:00:00 2001 From: giuseppere Date: Thu, 19 Dec 2024 15:57:23 +0100 Subject: [PATCH 091/101] expand errors msg for invulnerables --- polkadot/runtime/westend/src/genesis_config_presets.rs | 4 ++-- substrate/bin/node/testing/src/genesis.rs | 2 +- substrate/frame/staking/src/mock.rs | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/polkadot/runtime/westend/src/genesis_config_presets.rs b/polkadot/runtime/westend/src/genesis_config_presets.rs index f65c975327e6..b4b3e3427447 100644 --- a/polkadot/runtime/westend/src/genesis_config_presets.rs +++ b/polkadot/runtime/westend/src/genesis_config_presets.rs @@ -205,7 +205,7 @@ fn westend_testnet_genesis( invulnerables: BoundedVec::try_from( initial_authorities.iter().map(|x| x.0.clone()).collect::>() ) - .expect("Too many invulnerable validators!"), + .expect("Too many invulnerable validators: upper limit is MaxInvulnerables from pallet staking config"), force_era: Forcing::NotForcing, slash_reward_fraction: Perbill::from_percent(10), }, @@ -379,7 +379,7 @@ fn westend_staging_testnet_config_genesis() -> serde_json::Value { invulnerables: BoundedVec::try_from( initial_authorities.iter().map(|x| x.0.clone()).collect::>() ) - .expect("Too many invulnerable validators!"), + .expect("Too many invulnerable validators: upper limit is MaxInvulnerables from pallet staking config"), force_era: Forcing::ForceNone, slash_reward_fraction: Perbill::from_percent(10), }, diff --git a/substrate/bin/node/testing/src/genesis.rs b/substrate/bin/node/testing/src/genesis.rs index 778b39c9d143..376c2bf343e5 100644 --- a/substrate/bin/node/testing/src/genesis.rs +++ b/substrate/bin/node/testing/src/genesis.rs @@ -66,7 +66,7 @@ pub fn config_endowed(extra_endowed: Vec) -> RuntimeGenesisConfig { minimum_validator_count: 0, slash_reward_fraction: Perbill::from_percent(10), invulnerables: BoundedVec::try_from(vec![alice(), bob(), charlie()]) - .expect("Too many invulnerable validators!"), + .expect("Too many invulnerable validators: upper limit is MaxInvulnerables from pallet staking config"), ..Default::default() }, society: SocietyConfig { pot: 0 }, diff --git a/substrate/frame/staking/src/mock.rs b/substrate/frame/staking/src/mock.rs index 616aaa0f1ba3..ed90d5584af0 100644 --- a/substrate/frame/staking/src/mock.rs +++ b/substrate/frame/staking/src/mock.rs @@ -378,8 +378,8 @@ impl ExtBuilder { self } pub fn invulnerables(mut self, invulnerables: Vec) -> Self { - self.invulnerables = - BoundedVec::try_from(invulnerables).expect("Too many invulnerable validators!"); + self.invulnerables = BoundedVec::try_from(invulnerables) + .expect("Too many invulnerable validators: upper limit is MaxInvulnerables"); self } pub fn session_per_era(self, length: SessionIndex) -> Self { From 4b58f0ac69cf465a8c5616cae3fe9dacee047b09 Mon Sep 17 00:00:00 2001 From: giuseppere Date: Thu, 19 Dec 2024 16:05:19 +0100 Subject: [PATCH 092/101] using `default()` to create empty `WeakBoundedVec` --- substrate/frame/staking/src/tests.rs | 7 ++----- substrate/primitives/staking/src/lib.rs | 7 ++----- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index 8422b355dad4..aa35d092fbb8 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -6616,10 +6616,7 @@ fn should_retain_era_info_only_upto_history_depth() { for page in 0..3 { ErasStakersPaged::::insert( (era, &validator_stash, page), - ExposurePage { - page_total: 100, - others: WeakBoundedVec::force_from(vec![], None), - }, + ExposurePage { page_total: 100, others: WeakBoundedVec::default() }, ); } } @@ -8631,7 +8628,7 @@ mod getters { // given let era: EraIndex = 12; let account_id: mock::AccountId = 1; - let rewards = WeakBoundedVec::force_from(vec![], None); + let rewards = WeakBoundedVec::default(); ClaimedRewards::::insert(era, account_id, rewards.clone()); // when diff --git a/substrate/primitives/staking/src/lib.rs b/substrate/primitives/staking/src/lib.rs index a9e14dc5858a..82d9b25fecbc 100644 --- a/substrate/primitives/staking/src/lib.rs +++ b/substrate/primitives/staking/src/lib.rs @@ -401,7 +401,7 @@ impl, MaxExposurePageSize, - > = WeakBoundedVec::force_from(vec![], None); + > = WeakBoundedVec::default(); for individual in chunk.iter() { page_total.saturating_accrue(individual.value); let _ = others.try_push(IndividualExposure { @@ -444,10 +444,7 @@ pub struct ExposurePage< impl> Default for ExposurePage { fn default() -> Self { - ExposurePage { - page_total: Default::default(), - others: WeakBoundedVec::force_from(vec![], None), - } + ExposurePage { page_total: Default::default(), others: WeakBoundedVec::default() } } } From 33e59b2f21a8f3afae1dc37af5b90cccd8aba286 Mon Sep 17 00:00:00 2001 From: giuseppere Date: Thu, 19 Dec 2024 16:12:12 +0100 Subject: [PATCH 093/101] migration fix attempt --- substrate/frame/staking/src/migrations.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/substrate/frame/staking/src/migrations.rs b/substrate/frame/staking/src/migrations.rs index 616aa94fa388..8ff426b6ea54 100644 --- a/substrate/frame/staking/src/migrations.rs +++ b/substrate/frame/staking/src/migrations.rs @@ -184,7 +184,8 @@ pub mod v17 { ClaimedRewards::::insert(era, validator, reward_pages); }, Err(_) => { - log!(warn, "Migration failed for ClaimedRewards from v16 to v17."); + let reward_pages = WeakBoundedVec::force_from(old_reward_pages, None); + log!(warn, "Forced migration of ClaimedRewards items from v16 to v17 having {} pages.", old_reward_pages.len()); migration_errors = true; }, } From c889905ff3a11aaa5c6656775ff9e34ec9854294 Mon Sep 17 00:00:00 2001 From: giuseppere Date: Thu, 19 Dec 2024 16:12:56 +0100 Subject: [PATCH 094/101] nit --- substrate/frame/staking/src/migrations.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/substrate/frame/staking/src/migrations.rs b/substrate/frame/staking/src/migrations.rs index 8ff426b6ea54..1195fddd8402 100644 --- a/substrate/frame/staking/src/migrations.rs +++ b/substrate/frame/staking/src/migrations.rs @@ -186,7 +186,6 @@ pub mod v17 { Err(_) => { let reward_pages = WeakBoundedVec::force_from(old_reward_pages, None); log!(warn, "Forced migration of ClaimedRewards items from v16 to v17 having {} pages.", old_reward_pages.len()); - migration_errors = true; }, } } From 300b7f91fe0753ed1a35b818646c2a4ff4af2a90 Mon Sep 17 00:00:00 2001 From: giuseppere Date: Thu, 19 Dec 2024 16:13:34 +0100 Subject: [PATCH 095/101] migration fix --- substrate/frame/staking/src/migrations.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/substrate/frame/staking/src/migrations.rs b/substrate/frame/staking/src/migrations.rs index 1195fddd8402..f3801632f45f 100644 --- a/substrate/frame/staking/src/migrations.rs +++ b/substrate/frame/staking/src/migrations.rs @@ -186,6 +186,7 @@ pub mod v17 { Err(_) => { let reward_pages = WeakBoundedVec::force_from(old_reward_pages, None); log!(warn, "Forced migration of ClaimedRewards items from v16 to v17 having {} pages.", old_reward_pages.len()); + ClaimedRewards::::insert(era, validator, reward_pages); }, } } From fc63dc7ab620194bf3ba2750dd3c94982f67c259 Mon Sep 17 00:00:00 2001 From: giuseppere Date: Fri, 20 Dec 2024 11:09:17 +0100 Subject: [PATCH 096/101] fix migrations --- substrate/frame/staking/src/migrations.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/substrate/frame/staking/src/migrations.rs b/substrate/frame/staking/src/migrations.rs index f3801632f45f..1ffb201e2af9 100644 --- a/substrate/frame/staking/src/migrations.rs +++ b/substrate/frame/staking/src/migrations.rs @@ -178,14 +178,14 @@ pub mod v17 { } for (era, validator, old_reward_pages) in v16::ClaimedRewards::::iter() { - let reward_pages_maybe = WeakBoundedVec::try_from(old_reward_pages); + let reward_pages_maybe = WeakBoundedVec::try_from(old_reward_pages.clone()); match reward_pages_maybe { Ok(reward_pages) => { ClaimedRewards::::insert(era, validator, reward_pages); }, Err(_) => { let reward_pages = WeakBoundedVec::force_from(old_reward_pages, None); - log!(warn, "Forced migration of ClaimedRewards items from v16 to v17 having {} pages.", old_reward_pages.len()); + log!(warn, "Forced migration of ClaimedRewards items from v16 to v17 having {} pages.", reward_pages.len()); ClaimedRewards::::insert(era, validator, reward_pages); }, } From a065a91a59b019ab497e6b9748ed8fc925539f65 Mon Sep 17 00:00:00 2001 From: giuseppere Date: Fri, 20 Dec 2024 12:04:32 +0100 Subject: [PATCH 097/101] Set `MaxValidatorsCount` equal to `MaxAuthorities` --- polkadot/runtime/test-runtime/src/lib.rs | 3 ++- substrate/bin/node/runtime/src/lib.rs | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/polkadot/runtime/test-runtime/src/lib.rs b/polkadot/runtime/test-runtime/src/lib.rs index 71a4580bc56a..62b7c1c8a20c 100644 --- a/polkadot/runtime/test-runtime/src/lib.rs +++ b/polkadot/runtime/test-runtime/src/lib.rs @@ -346,6 +346,7 @@ parameter_types! { pub const RewardCurve: &'static PiecewiseLinear<'static> = &REWARD_CURVE; pub const MaxExposurePageSize: u32 = 64; pub const MaxNominators: u32 = 256; + // This corresponds to the maximum number of validators pub const MaxAuthorities: u32 = 100_000; pub const OnChainMaxWinners: u32 = u32::MAX; // Unbounded number of election targets and voters. @@ -400,7 +401,7 @@ impl pallet_staking::Config for Runtime { type DisablingStrategy = pallet_staking::UpToLimitWithReEnablingDisablingStrategy; type MaxInvulnerables = ConstU32<20>; type MaxRewardPagesPerValidator = ConstU32<20>; - type MaxValidatorsCount = ConstU32<300>; + type MaxValidatorsCount = MaxAuthorities; type MaxDisabledValidators = ConstU32<100>; } diff --git a/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs index dec45b1de711..7a2dc3388ace 100644 --- a/substrate/bin/node/runtime/src/lib.rs +++ b/substrate/bin/node/runtime/src/lib.rs @@ -748,7 +748,7 @@ impl pallet_staking::Config for Runtime { type DisablingStrategy = pallet_staking::UpToLimitWithReEnablingDisablingStrategy; type MaxInvulnerables = ConstU32<20>; type MaxRewardPagesPerValidator = ConstU32<20>; - type MaxValidatorsCount = ConstU32<300>; + type MaxValidatorsCount = MaxAuthorities; type MaxDisabledValidators = ConstU32<100>; } @@ -1485,7 +1485,7 @@ parameter_types! { pub const ImOnlineUnsignedPriority: TransactionPriority = TransactionPriority::max_value(); /// We prioritize im-online heartbeats over election solution submission. pub const StakingUnsignedPriority: TransactionPriority = TransactionPriority::max_value() / 2; - pub const MaxAuthorities: u32 = 100; + pub const MaxAuthorities: u32 = 300; pub const MaxKeys: u32 = 10_000; pub const MaxPeerInHeartbeats: u32 = 10_000; } From 483eb03d6408d7b88cae3c835d2fd1b025f6d1ce Mon Sep 17 00:00:00 2001 From: Giuseppe Re Date: Fri, 20 Dec 2024 13:19:27 +0100 Subject: [PATCH 098/101] Update polkadot/runtime/test-runtime/src/lib.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> --- polkadot/runtime/test-runtime/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/polkadot/runtime/test-runtime/src/lib.rs b/polkadot/runtime/test-runtime/src/lib.rs index 62b7c1c8a20c..232833a4c9e2 100644 --- a/polkadot/runtime/test-runtime/src/lib.rs +++ b/polkadot/runtime/test-runtime/src/lib.rs @@ -340,7 +340,7 @@ parameter_types! { pub storage SessionsPerEra: SessionIndex = 6; // 28 eras for unbonding (7 days). pub storage BondingDuration: sp_staking::EraIndex = 28; - pub storage MaxBondedEras: u32 = (BondingDuration::get() as u32) + 1; + pub const MaxBondedEras: u32 = (BondingDuration::get() as u32) + 1; // 27 eras in which slashes can be cancelled (a bit less than 7 days). pub storage SlashDeferDuration: sp_staking::EraIndex = 27; pub const RewardCurve: &'static PiecewiseLinear<'static> = &REWARD_CURVE; From c51d09b7927f362562cbed1eda15f9bf0e48d285 Mon Sep 17 00:00:00 2001 From: giuseppere Date: Fri, 20 Dec 2024 13:21:32 +0100 Subject: [PATCH 099/101] fix comment --- substrate/frame/staking/src/migrations.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrate/frame/staking/src/migrations.rs b/substrate/frame/staking/src/migrations.rs index 1ffb201e2af9..2a911a65ddcd 100644 --- a/substrate/frame/staking/src/migrations.rs +++ b/substrate/frame/staking/src/migrations.rs @@ -61,7 +61,7 @@ impl Default for ObsoleteReleases { #[storage_alias] type StorageVersion = StorageValue, ObsoleteReleases, ValueQuery>; -/// Migrating all unbounded storage items to bounded +/// Migrating all non-slashing related unbounded storage items to bounded pub mod v17 { use super::*; From 1a9be6b6f8729e1d7acd804eca3162e452653eed Mon Sep 17 00:00:00 2001 From: giuseppere Date: Fri, 20 Dec 2024 13:35:17 +0100 Subject: [PATCH 100/101] fix --- polkadot/runtime/test-runtime/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/polkadot/runtime/test-runtime/src/lib.rs b/polkadot/runtime/test-runtime/src/lib.rs index 232833a4c9e2..5f2f29c9d2ff 100644 --- a/polkadot/runtime/test-runtime/src/lib.rs +++ b/polkadot/runtime/test-runtime/src/lib.rs @@ -339,7 +339,7 @@ parameter_types! { // Six sessions in an era (6 hours). pub storage SessionsPerEra: SessionIndex = 6; // 28 eras for unbonding (7 days). - pub storage BondingDuration: sp_staking::EraIndex = 28; + pub const BondingDuration: sp_staking::EraIndex = 28; pub const MaxBondedEras: u32 = (BondingDuration::get() as u32) + 1; // 27 eras in which slashes can be cancelled (a bit less than 7 days). pub storage SlashDeferDuration: sp_staking::EraIndex = 27; From 235a26094ccd3cb03acf499a8499ce6b865d6157 Mon Sep 17 00:00:00 2001 From: Giuseppe Re Date: Fri, 20 Dec 2024 16:43:43 +0100 Subject: [PATCH 101/101] Update pr_6445.prdoc from semver CI --- prdoc/pr_6445.prdoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/prdoc/pr_6445.prdoc b/prdoc/pr_6445.prdoc index 36bb6d00fac2..8784e4fb22bd 100644 --- a/prdoc/pr_6445.prdoc +++ b/prdoc/pr_6445.prdoc @@ -30,7 +30,7 @@ crates: - name: westend-runtime bump: minor - name: sp-staking - bump: minor + bump: major - name: polkadot-runtime-common bump: patch - name: pallet-fast-unstake