Skip to content

Commit

Permalink
Store validator self-vote in bags-list, and allow them to be trimmed …
Browse files Browse the repository at this point in the history
…for election (paritytech#10821)

* Implement the new validator-in-bags-list scenario + migration

* Apply suggestions from code review

Co-authored-by: Zeke Mostov <z.mostov@gmail.com>

* some review comments

* guard the migration

* some review comments

* Fix tests 🤦‍♂️

* Fix build

* fix weight_of_fn

* reformat line width

* make const

* use weight of fn cached

* SortedListProvider -> VoterList

* Fix all build and docs

* check post migration

Co-authored-by: Zeke Mostov <z.mostov@gmail.com>
  • Loading branch information
2 people authored and ark0f committed Feb 27, 2023
1 parent 5389c54 commit cb6f2e3
Show file tree
Hide file tree
Showing 17 changed files with 305 additions and 204 deletions.
4 changes: 1 addition & 3 deletions bin/node/runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -558,9 +558,7 @@ impl pallet_staking::Config for Runtime {
type OffendingValidatorsThreshold = OffendingValidatorsThreshold;
type ElectionProvider = ElectionProviderMultiPhase;
type GenesisElectionProvider = onchain::OnChainSequentialPhragmen<Self>;
// Alternatively, use pallet_staking::UseNominatorsMap<Runtime> to just use the nominators map.
// Note that the aforementioned does not scale to a very large number of nominators.
type SortedListProvider = BagsList;
type VoterList = BagsList;
type MaxUnlockingChunks = ConstU32<32>;
type WeightInfo = pallet_staking::weights::SubstrateWeight<Runtime>;
type BenchmarkingConfig = StakingBenchmarkingConfig;
Expand Down
2 changes: 1 addition & 1 deletion frame/babe/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ impl pallet_staking::Config for Test {
type NextNewSession = Session;
type ElectionProvider = onchain::OnChainSequentialPhragmen<Self>;
type GenesisElectionProvider = Self::ElectionProvider;
type SortedListProvider = pallet_staking::UseNominatorsMap<Self>;
type VoterList = pallet_staking::UseNominatorsAndValidatorsMap<Self>;
type MaxUnlockingChunks = ConstU32<32>;
type BenchmarkingConfig = pallet_staking::TestBenchmarkingConfig;
type WeightInfo = ();
Expand Down
2 changes: 1 addition & 1 deletion frame/bags-list/remote-tests/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ pub fn display_and_check_bags<Runtime: RuntimeT>(currency_unit: u64, currency_na
let min_nominator_bond = <pallet_staking::MinNominatorBond<Runtime>>::get();
log::info!(target: LOG_TARGET, "min nominator bond is {:?}", min_nominator_bond);

let voter_list_count = <Runtime as pallet_staking::Config>::SortedListProvider::count();
let voter_list_count = <Runtime as pallet_staking::Config>::VoterList::count();

// go through every bag to track the total number of voters within bags and log some info about
// how voters are distributed within the bags.
Expand Down
11 changes: 5 additions & 6 deletions frame/bags-list/remote-tests/src/migration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
//! Test to check the migration of the voter bag.

use crate::{RuntimeT, LOG_TARGET};
use frame_election_provider_support::SortedListProvider;
use frame_support::traits::PalletInfoAccess;
use pallet_staking::Nominators;
use remote_externalities::{Builder, Mode, OnlineConfig};
Expand Down Expand Up @@ -45,16 +44,16 @@ pub async fn execute<Runtime: RuntimeT, Block: BlockT + DeserializeOwned>(
let pre_migrate_nominator_count = <Nominators<Runtime>>::iter().count() as u32;
log::info!(target: LOG_TARGET, "Nominator count: {}", pre_migrate_nominator_count);

// run the actual migration,
let moved = <Runtime as pallet_staking::Config>::SortedListProvider::unsafe_regenerate(
use frame_election_provider_support::SortedListProvider;
// run the actual migration
let moved = <Runtime as pallet_staking::Config>::VoterList::unsafe_regenerate(
pallet_staking::Nominators::<Runtime>::iter().map(|(n, _)| n),
pallet_staking::Pallet::<Runtime>::weight_of_fn(),
);
log::info!(target: LOG_TARGET, "Moved {} nominators", moved);

let voter_list_len =
<Runtime as pallet_staking::Config>::SortedListProvider::iter().count() as u32;
let voter_list_count = <Runtime as pallet_staking::Config>::SortedListProvider::count();
let voter_list_len = <Runtime as pallet_staking::Config>::VoterList::iter().count() as u32;
let voter_list_count = <Runtime as pallet_staking::Config>::VoterList::count();
// and confirm it is equal to the length of the `VoterList`.
assert_eq!(pre_migrate_nominator_count, voter_list_len);
assert_eq!(pre_migrate_nominator_count, voter_list_count);
Expand Down
5 changes: 3 additions & 2 deletions frame/bags-list/remote-tests/src/snapshot.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

//! Test to execute the snapshot using the voter bag.

use frame_election_provider_support::SortedListProvider;
use frame_support::traits::PalletInfoAccess;
use remote_externalities::{Builder, Mode, OnlineConfig};
use sp_runtime::{traits::Block as BlockT, DeserializeOwned};
Expand Down Expand Up @@ -48,11 +49,11 @@ pub async fn execute<Runtime: crate::RuntimeT, Block: BlockT + DeserializeOwned>
.unwrap();

ext.execute_with(|| {
use frame_election_provider_support::{ElectionDataProvider, SortedListProvider};
use frame_election_provider_support::ElectionDataProvider;
log::info!(
target: crate::LOG_TARGET,
"{} nodes in bags list.",
<Runtime as pallet_staking::Config>::SortedListProvider::count(),
<Runtime as pallet_staking::Config>::VoterList::count(),
);

let voters =
Expand Down
2 changes: 1 addition & 1 deletion frame/grandpa/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ impl pallet_staking::Config for Test {
type NextNewSession = Session;
type ElectionProvider = onchain::OnChainSequentialPhragmen<Self>;
type GenesisElectionProvider = Self::ElectionProvider;
type SortedListProvider = pallet_staking::UseNominatorsMap<Self>;
type VoterList = pallet_staking::UseNominatorsAndValidatorsMap<Self>;
type MaxUnlockingChunks = ConstU32<32>;
type BenchmarkingConfig = pallet_staking::TestBenchmarkingConfig;
type WeightInfo = ();
Expand Down
2 changes: 1 addition & 1 deletion frame/offences/benchmarking/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ impl pallet_staking::Config for Test {
type OffendingValidatorsThreshold = ();
type ElectionProvider = onchain::OnChainSequentialPhragmen<Self>;
type GenesisElectionProvider = Self::ElectionProvider;
type SortedListProvider = pallet_staking::UseNominatorsMap<Self>;
type VoterList = pallet_staking::UseNominatorsAndValidatorsMap<Self>;
type MaxUnlockingChunks = ConstU32<32>;
type BenchmarkingConfig = pallet_staking::TestBenchmarkingConfig;
type WeightInfo = ();
Expand Down
2 changes: 1 addition & 1 deletion frame/session/benchmarking/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ impl pallet_staking::Config for Test {
type ElectionProvider = onchain::OnChainSequentialPhragmen<Self>;
type GenesisElectionProvider = Self::ElectionProvider;
type MaxUnlockingChunks = ConstU32<32>;
type SortedListProvider = pallet_staking::UseNominatorsMap<Self>;
type VoterList = pallet_staking::UseNominatorsAndValidatorsMap<Self>;
type BenchmarkingConfig = pallet_staking::TestBenchmarkingConfig;
type WeightInfo = ();
}
Expand Down
4 changes: 2 additions & 2 deletions frame/session/src/migrations/v1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ pub fn migrate<T: pallet_session_historical::Config, P: GetStorageVersion + Pall
}

/// Some checks prior to migration. This can be linked to
/// [`frame_support::traits::OnRuntimeUpgrade::pre_upgrade`] for further testing.
/// `frame_support::traits::OnRuntimeUpgrade::pre_upgrade` for further testing.
///
/// Panics if anything goes wrong.
pub fn pre_migrate<
Expand Down Expand Up @@ -123,7 +123,7 @@ pub fn pre_migrate<
}

/// Some checks for after migration. This can be linked to
/// [`frame_support::traits::OnRuntimeUpgrade::post_upgrade`] for further testing.
/// `frame_support::traits::OnRuntimeUpgrade::post_upgrade` for further testing.
///
/// Panics if anything goes wrong.
pub fn post_migrate<
Expand Down
50 changes: 23 additions & 27 deletions frame/staking/src/benchmarking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -155,8 +155,8 @@ impl<T: Config> ListScenario<T> {
/// - the destination bag has at least one node, which will need its next pointer updated.
///
/// NOTE: while this scenario specifically targets a worst case for the bags-list, it should
/// also elicit a worst case for other known `SortedListProvider` implementations; although
/// this may not be true against unknown `SortedListProvider` implementations.
/// also elicit a worst case for other known `VoterList` implementations; although
/// this may not be true against unknown `VoterList` implementations.
fn new(origin_weight: BalanceOf<T>, is_increase: bool) -> Result<Self, &'static str> {
ensure!(!origin_weight.is_zero(), "origin weight must be greater than 0");

Expand Down Expand Up @@ -189,7 +189,7 @@ impl<T: Config> ListScenario<T> {

// find a destination weight that will trigger the worst case scenario
let dest_weight_as_vote =
T::SortedListProvider::score_update_worst_case(&origin_stash1, is_increase);
T::VoterList::score_update_worst_case(&origin_stash1, is_increase);

let total_issuance = T::Currency::total_issuance();

Expand Down Expand Up @@ -316,7 +316,7 @@ benchmarks! {
let scenario = ListScenario::<T>::new(origin_weight, true)?;
let controller = scenario.origin_controller1.clone();
let stash = scenario.origin_stash1.clone();
assert!(T::SortedListProvider::contains(&stash));
assert!(T::VoterList::contains(&stash));

let ed = T::Currency::minimum_balance();
let mut ledger = Ledger::<T>::get(&controller).unwrap();
Expand All @@ -328,28 +328,24 @@ benchmarks! {
}: withdraw_unbonded(RawOrigin::Signed(controller.clone()), s)
verify {
assert!(!Ledger::<T>::contains_key(controller));
assert!(!T::SortedListProvider::contains(&stash));
assert!(!T::VoterList::contains(&stash));
}

validate {
// clean up any existing state.
clear_validators_and_nominators::<T>();

let origin_weight = MinNominatorBond::<T>::get().max(T::Currency::minimum_balance());

// setup a worst case scenario where the user calling validate was formerly a nominator so
// they must be removed from the list.
let scenario = ListScenario::<T>::new(origin_weight, true)?;
let controller = scenario.origin_controller1.clone();
let stash = scenario.origin_stash1.clone();
assert!(T::SortedListProvider::contains(&stash));
let (stash, controller) = create_stash_controller::<T>(
T::MaxNominations::get() - 1,
100,
Default::default(),
)?;
// because it is chilled.
assert!(!T::VoterList::contains(&stash));

let prefs = ValidatorPrefs::default();
whitelist_account!(controller);
}: _(RawOrigin::Signed(controller), prefs)
verify {
assert!(Validators::<T>::contains_key(&stash));
assert!(!T::SortedListProvider::contains(&stash));
assert!(T::VoterList::contains(&stash));
}

kick {
Expand Down Expand Up @@ -434,14 +430,14 @@ benchmarks! {
).unwrap();

assert!(!Nominators::<T>::contains_key(&stash));
assert!(!T::SortedListProvider::contains(&stash));
assert!(!T::VoterList::contains(&stash));

let validators = create_validators::<T>(n, 100).unwrap();
whitelist_account!(controller);
}: _(RawOrigin::Signed(controller), validators)
verify {
assert!(Nominators::<T>::contains_key(&stash));
assert!(T::SortedListProvider::contains(&stash))
assert!(T::VoterList::contains(&stash))
}

chill {
Expand All @@ -455,12 +451,12 @@ benchmarks! {
let scenario = ListScenario::<T>::new(origin_weight, true)?;
let controller = scenario.origin_controller1.clone();
let stash = scenario.origin_stash1.clone();
assert!(T::SortedListProvider::contains(&stash));
assert!(T::VoterList::contains(&stash));

whitelist_account!(controller);
}: _(RawOrigin::Signed(controller))
verify {
assert!(!T::SortedListProvider::contains(&stash));
assert!(!T::VoterList::contains(&stash));
}

set_payee {
Expand Down Expand Up @@ -523,13 +519,13 @@ benchmarks! {
let scenario = ListScenario::<T>::new(origin_weight, true)?;
let controller = scenario.origin_controller1.clone();
let stash = scenario.origin_stash1.clone();
assert!(T::SortedListProvider::contains(&stash));
assert!(T::VoterList::contains(&stash));
add_slashing_spans::<T>(&stash, s);

}: _(RawOrigin::Root, stash.clone(), s)
verify {
assert!(!Ledger::<T>::contains_key(&controller));
assert!(!T::SortedListProvider::contains(&stash));
assert!(!T::VoterList::contains(&stash));
}

cancel_deferred_slash {
Expand Down Expand Up @@ -708,13 +704,13 @@ benchmarks! {
Ledger::<T>::insert(&controller, l);

assert!(Bonded::<T>::contains_key(&stash));
assert!(T::SortedListProvider::contains(&stash));
assert!(T::VoterList::contains(&stash));

whitelist_account!(controller);
}: _(RawOrigin::Signed(controller), stash.clone(), s)
verify {
assert!(!Bonded::<T>::contains_key(&stash));
assert!(!T::SortedListProvider::contains(&stash));
assert!(!T::VoterList::contains(&stash));
}

new_era {
Expand Down Expand Up @@ -899,7 +895,7 @@ benchmarks! {
let scenario = ListScenario::<T>::new(origin_weight, true)?;
let controller = scenario.origin_controller1.clone();
let stash = scenario.origin_stash1.clone();
assert!(T::SortedListProvider::contains(&stash));
assert!(T::VoterList::contains(&stash));

Staking::<T>::set_staking_configs(
RawOrigin::Root.into(),
Expand All @@ -914,7 +910,7 @@ benchmarks! {
let caller = whitelisted_caller();
}: _(RawOrigin::Signed(caller), controller.clone())
verify {
assert!(!T::SortedListProvider::contains(&stash));
assert!(!T::VoterList::contains(&stash));
}

force_apply_min_commission {
Expand Down
3 changes: 2 additions & 1 deletion frame/staking/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -780,7 +780,8 @@ enum Releases {
V5_0_0, // blockable validators.
V6_0_0, // removal of all storage associated with offchain phragmen.
V7_0_0, // keep track of number of nominators / validators in map
V8_0_0, // populate `SortedListProvider`.
V8_0_0, // populate `VoterList`.
V9_0_0, // inject validators into `VoterList` as well.
}

impl Default for Releases {
Expand Down
Loading

0 comments on commit cb6f2e3

Please sign in to comment.