Skip to content
This repository has been archived by the owner on Nov 15, 2023. It is now read-only.

Bounding by MaxActiveValidators #12202

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions bin/node/runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -504,6 +504,7 @@ impl pallet_session::Config for Runtime {
type SessionManager = pallet_session::historical::NoteHistoricalRoot<Self, Staking>;
type SessionHandler = <SessionKeys as OpaqueKeys>::KeyTypeIdProviders;
type Keys = SessionKeys;
type MaxActiveValidators = ConstU32<3072>;
type WeightInfo = pallet_session::weights::SubstrateWeight<Runtime>;
}

Expand Down Expand Up @@ -567,6 +568,7 @@ impl pallet_staking::Config for Runtime {
type VoterList = BagsList;
type MaxUnlockingChunks = ConstU32<32>;
type OnStakerSlash = NominationPools;
type MaxActiveValidators = ConstU32<3072>;
type WeightInfo = pallet_staking::weights::SubstrateWeight<Runtime>;
type BenchmarkingConfig = StakingBenchmarkingConfig;
}
Expand Down
2 changes: 1 addition & 1 deletion frame/session/src/historical/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ pub mod pallet {
#[pallet::storage]
#[pallet::getter(fn historical_root)]
pub type HistoricalSessions<T: Config> =
StorageMap<_, Twox64Concat, SessionIndex, (T::Hash, ValidatorCount), OptionQuery>;
StorageMap<_, Twox64Concat, SessionIndex, (T::Hash, ValidatorCount), OptionQuery>; // Bound this

/// The range of historical sessions we store. [first, last)
#[pallet::storage]
Expand Down
14 changes: 10 additions & 4 deletions frame/session/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -410,6 +410,9 @@ pub mod pallet {
/// The keys.
type Keys: OpaqueKeys + Member + Parameter + MaybeSerializeDeserialize;

/// The maximum number of validators that this pallet can have.
type MaxActiveValidators: Get<u32>;

/// Weight information for extrinsics in this pallet.
type WeightInfo: WeightInfo;
}
Expand Down Expand Up @@ -470,13 +473,15 @@ pub mod pallet {
!initial_validators_0.is_empty(),
"Empty validator set for session 0 in genesis block!"
);
assert!(initial_validators_0.len() as u32 <= T::MaxActiveValidators::get(), "exceeds the current amount of active validators");

let initial_validators_1 = T::SessionManager::new_session_genesis(1)
.unwrap_or_else(|| initial_validators_0.clone());
assert!(
!initial_validators_1.is_empty(),
"Empty validator set for session 1 in genesis block!"
);
assert!(initial_validators_1.len() as u32 <= T::MaxActiveValidators::get(), "exceeds the current amount of active validators");

let queued_keys: Vec<_> = initial_validators_1
.iter()
Expand All @@ -502,7 +507,7 @@ pub mod pallet {
/// The current set of validators.
#[pallet::storage]
#[pallet::getter(fn validators)]
pub type Validators<T: Config> = StorageValue<_, Vec<T::ValidatorId>, ValueQuery>;
pub type Validators<T: Config> = StorageValue<_, Vec<T::ValidatorId>, ValueQuery>; // Bound this

/// Current index of the session.
#[pallet::storage]
Expand All @@ -518,7 +523,7 @@ pub mod pallet {
/// will be used to determine the validator's session keys.
#[pallet::storage]
#[pallet::getter(fn queued_keys)]
pub type QueuedKeys<T: Config> = StorageValue<_, Vec<(T::ValidatorId, T::Keys)>, ValueQuery>;
pub type QueuedKeys<T: Config> = StorageValue<_, Vec<(T::ValidatorId, T::Keys)>, ValueQuery>; // Bound this

/// Indices of disabled validators.
///
Expand All @@ -527,7 +532,7 @@ pub mod pallet {
/// a new set of identities.
#[pallet::storage]
#[pallet::getter(fn disabled_validators)]
pub type DisabledValidators<T> = StorageValue<_, Vec<u32>, ValueQuery>;
pub type DisabledValidators<T> = StorageValue<_, Vec<u32>, ValueQuery>; // Bound this

/// The next session keys for a validator.
#[pallet::storage]
Expand Down Expand Up @@ -662,11 +667,12 @@ impl<T: Config> Pallet<T> {

// Get next validator set.
let maybe_next_validators = T::SessionManager::new_session(session_index + 1);
let (next_validators, next_identities_changed) =
let (next_validators, next_identities_changed) =
if let Some(validators) = maybe_next_validators {
// NOTE: as per the documentation on `OnSessionEnding`, we consider
// the validator set as having changed even if the validators are the
// same as before, as underlying economic conditions may have changed.
debug_assert!(validators.len() as u32 <= T::MaxActiveValidators::get(), "exceeds the current amount of active validators");
(validators, true)
} else {
(Validators::<T>::get(), false)
Expand Down
1 change: 1 addition & 0 deletions frame/session/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,7 @@ impl Config for Test {
type Keys = MockSessionKeys;
type Event = Event;
type NextSessionRotation = ();
type MaxActiveValidators = ConstU32<7>;
type WeightInfo = ();
}

Expand Down
17 changes: 10 additions & 7 deletions frame/staking/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -299,12 +299,12 @@ pub mod weights;

mod pallet;

use codec::{Decode, Encode, HasCompact};
use codec::{Decode, Encode, HasCompact, MaxEncodedLen};
use frame_support::{
parameter_types,
traits::{Currency, Defensive, Get},
weights::Weight,
BoundedVec, EqNoBound, PartialEqNoBound, RuntimeDebugNoBound,
BoundedBTreeMap, BoundedVec, CloneNoBound, EqNoBound, PartialEqNoBound, RuntimeDebugNoBound,
};
use scale_info::TypeInfo;
use sp_runtime::{
Expand Down Expand Up @@ -368,17 +368,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<AccountId: Ord> {
#[derive(Encode, Decode, MaxEncodedLen, TypeInfo, RuntimeDebugNoBound, CloneNoBound)]
#[cfg_attr(feature = "std", derive(frame_support::PartialEqNoBound))]
#[codec(mel_bound(T: Config))]
#[scale_info(skip_type_params(T))]
pub struct EraRewardPoints<T: Config> {
/// 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<AccountId, RewardPoint>,
pub individual: BoundedBTreeMap<T::AccountId, RewardPoint, T::MaxActiveValidators>,
}

impl<AccountId: Ord> Default for EraRewardPoints<AccountId> {
impl<T: Config> Default for EraRewardPoints<T> {
fn default() -> Self {
EraRewardPoints { total: Default::default(), individual: BTreeMap::new() }
EraRewardPoints { total: Default::default(), individual: BoundedBTreeMap::new() }
}
}

Expand Down
8 changes: 5 additions & 3 deletions frame/staking/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,7 @@ impl pallet_session::Config for Test {
type ValidatorId = AccountId;
type ValidatorIdOf = crate::StashOf<Test>;
type NextSessionRotation = pallet_session::PeriodicSessions<Period, Offset>;
type MaxActiveValidators = ConstU32<7>;
type WeightInfo = ();
}

Expand Down Expand Up @@ -301,6 +302,7 @@ impl crate::pallet::pallet::Config for Test {
type MaxUnlockingChunks = ConstU32<32>;
type OnStakerSlash = OnStakerSlashMock<Test>;
type BenchmarkingConfig = TestBenchmarkingConfig;
type MaxActiveValidators = ConstU32<15>;
type WeightInfo = ();
}

Expand All @@ -311,7 +313,7 @@ pub struct ExtBuilder {
nominate: bool,
validator_count: u32,
minimum_validator_count: u32,
invulnerables: Vec<AccountId>,
invulnerables: BoundedVec<AccountId, <Test as Config>::MaxActiveValidators>,
has_stakers: bool,
initialize_first_session: bool,
pub min_nominator_bond: Balance,
Expand All @@ -329,7 +331,7 @@ impl Default for ExtBuilder {
validator_count: 2,
minimum_validator_count: 0,
balance_factor: 1,
invulnerables: vec![],
invulnerables: Default::default(),
has_stakers: true,
initialize_first_session: true,
min_nominator_bond: ExistentialDeposit::get(),
Expand Down Expand Up @@ -362,7 +364,7 @@ impl ExtBuilder {
SLASH_DEFER_DURATION.with(|v| *v.borrow_mut() = eras);
self
}
pub fn invulnerables(mut self, invulnerables: Vec<AccountId>) -> Self {
pub fn invulnerables(mut self, invulnerables: BoundedVec<AccountId, <Test as Config>::MaxActiveValidators>) -> Self {
self.invulnerables = invulnerables;
self
}
Expand Down
55 changes: 39 additions & 16 deletions frame/staking/src/pallet/impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

use frame_election_provider_support::{
data_provider, ElectionDataProvider, ElectionProvider, ScoreProvider, SortedListProvider,
Supports, VoteWeight, VoterOf,
Support, VoteWeight, VoterOf,
};
use frame_support::{
pallet_prelude::*,
Expand All @@ -42,9 +42,9 @@ use sp_staking::{
use sp_std::{collections::btree_map::BTreeMap, prelude::*};

use crate::{
log, slashing, weights::WeightInfo, ActiveEraInfo, BalanceOf, EraPayout, Exposure, ExposureOf,
Forcing, IndividualExposure, Nominations, PositiveImbalanceOf, RewardDestination,
SessionInterface, StakingLedger, ValidatorPrefs,
log, slashing, weights::WeightInfo, ActiveEraInfo, BalanceOf, EraPayout, EraRewardPoints,
Exposure, ExposureOf, Forcing, IndividualExposure, Nominations, PositiveImbalanceOf,
RewardDestination, SessionInterface, StakingLedger, ValidatorPrefs,
};

use super::{pallet::*, STAKING_ID};
Expand Down Expand Up @@ -406,7 +406,10 @@ impl<T: Config> Pallet<T> {
/// Returns the new validator set.
pub fn trigger_new_era(
start_session_index: SessionIndex,
exposures: Vec<(T::AccountId, Exposure<T::AccountId, BalanceOf<T>>)>,
exposures: BoundedVec<
(T::AccountId, Exposure<T::AccountId, BalanceOf<T>>),
T::MaxActiveValidators,
>,
) -> Vec<T::AccountId> {
// Increment or set current era.
let new_planned_era = CurrentEra::<T>::mutate(|s| {
Expand Down Expand Up @@ -434,7 +437,7 @@ impl<T: Config> Pallet<T> {
start_session_index: SessionIndex,
is_genesis: bool,
) -> Option<Vec<T::AccountId>> {
let election_result = if is_genesis {
let election_result: BoundedVec<_, T::MaxActiveValidators> = if is_genesis {
T::GenesisElectionProvider::elect().map_err(|e| {
log!(warn, "genesis election provider failed due to {:?}", e);
Self::deposit_event(Event::StakingElectionFailed);
Expand All @@ -445,6 +448,7 @@ impl<T: Config> Pallet<T> {
Self::deposit_event(Event::StakingElectionFailed);
})
}
.and_then(|er| er.try_into().defensive())
.ok()?;

let exposures = Self::collect_exposures(election_result);
Expand Down Expand Up @@ -481,8 +485,12 @@ impl<T: Config> Pallet<T> {
/// Process the output of the election.
///
/// Store staking information for the new planned era
// TODO: Test case needed
pub fn store_stakers_info(
exposures: Vec<(T::AccountId, Exposure<T::AccountId, BalanceOf<T>>)>,
exposures: BoundedVec<
(T::AccountId, Exposure<T::AccountId, BalanceOf<T>>),
T::MaxActiveValidators,
>,
new_planned_era: EraIndex,
) -> Vec<T::AccountId> {
let elected_stashes = exposures.iter().cloned().map(|(x, _)| x).collect::<Vec<_>>();
Expand Down Expand Up @@ -526,12 +534,13 @@ impl<T: Config> Pallet<T> {
/// Consume a set of [`Supports`] from [`sp_npos_elections`] and collect them into a
/// [`Exposure`].
fn collect_exposures(
supports: Supports<T::AccountId>,
) -> Vec<(T::AccountId, Exposure<T::AccountId, BalanceOf<T>>)> {
supports: BoundedVec<(T::AccountId, Support<T::AccountId>), T::MaxActiveValidators>,
) -> BoundedVec<(T::AccountId, Exposure<T::AccountId, BalanceOf<T>>), T::MaxActiveValidators> {
let total_issuance = T::Currency::total_issuance();
let to_currency = |e: frame_election_provider_support::ExtendedBalance| {
T::CurrencyToVote::to_currency(e, total_issuance)
};
use sp_runtime::traits::TryCollect;

supports
.into_iter()
Expand All @@ -556,7 +565,8 @@ impl<T: Config> Pallet<T> {
let exposure = Exposure { own, others, total };
(validator, exposure)
})
.collect::<Vec<(T::AccountId, Exposure<_, _>)>>()
.try_collect()
.expect("`supports` is bounded, `map` does not change the length of iterator, outcome is bounded; qed.")
}

/// Remove all associated data of a stash account from the staking system.
Expand Down Expand Up @@ -625,12 +635,25 @@ impl<T: Config> Pallet<T> {
/// COMPLEXITY: Complexity is `number_of_validator_to_reward x current_elected_len`.
pub fn reward_by_ids(validators_points: impl IntoIterator<Item = (T::AccountId, u32)>) {
if let Some(active_era) = Self::active_era() {
<ErasRewardPoints<T>>::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;
}
});
<ErasRewardPoints<T>>::mutate(
active_era.index,
|era_rewards: &mut EraRewardPoints<T>| {
for (validator, points) in validators_points.into_iter() {
if let Some(i) = era_rewards.individual.get_mut(&validator) {
*i += points;
era_rewards.total += points;
} else {
let _ = era_rewards
.individual
.try_insert(validator, points)
.map(|_| {
era_rewards.total += points;
})
.defensive();
}
}
},
);
}
}

Expand Down
Loading