mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-14 15:41:02 +00:00
[NPoS] Implements dynamic number of nominators (#12970)
* Implements dynamic nominations per nominator * Adds SnapshotBounds and ElectionSizeTracker * Changes the ElectionDataProvider interface to receive ElectionBounds as input * Implements get_npos_voters with ElectionBounds * Implements get_npos_targets with ElectionBounds * Adds comments * tests * Truncates nomninations that exceed nominations quota; Old tests passing * Uses DataProviderBounds and ElectionBounds (to continue) * Finishes conversions - tests passing * Refactor staking in babe mocks * Replaces MaxElectableTargets and MaxElectingVoters with ElectionBounds; Adds more tests * Fixes nits; node compiling * bechmarks * removes nomination_quota extrinsic to request the nomination quota * Lazy quota check, ie. at nominate time only * remove non-working test (for now) * tests lazy nominations quota when quota is lower than current number of nominated targets * Adds runtime API and custom RPC call for clients to query the nominations quota for a given balance * removes old rpc * Cosmetic touches * All mocks working * Fixes benchmarking mocks * nits * more tests * renames trait methods * nit * ".git/.scripts/commands/fmt/fmt.sh" * Fix V2 PoV benchmarking (#13485) * Bump default 'additional_trie_layers' to two The default here only works for extremely small runtimes, which have no more than 16 storage prefices. This is changed to a "sane" default of 2, which is save for runtimes with up to 4096 storage prefices (eg StorageValue). Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> * Update tests and test weights Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> * Fix PoV weights Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> * ".git/.scripts/commands/bench/bench.sh" pallet dev pallet_balances * ".git/.scripts/commands/bench/bench.sh" pallet dev pallet_message_queue * ".git/.scripts/commands/bench/bench.sh" pallet dev pallet_glutton * ".git/.scripts/commands/bench/bench.sh" pallet dev pallet_glutton * Fix sanity check >0 would also do as a check, but let's try this. Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> --------- Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> Co-authored-by: command-bot <> * Move BEEFY code to consensus (#13484) * Move beefy primitives to consensus dir * Move beefy gadget to client consensus folder * Rename beefy crates * chore: move genesis block builder to chain-spec crate. (#13427) * chore: move genesis block builder to block builder crate. * add missing file * chore: move genesis block builder to sc-chain-spec * Update client/chain-spec/src/genesis.rs Co-authored-by: Bastian Köcher <git@kchr.de> * Update test-utils/runtime/src/genesismap.rs Co-authored-by: Bastian Köcher <git@kchr.de> * Update test-utils/runtime/client/src/lib.rs * fix warnings * fix warnings --------- Co-authored-by: Bastian Köcher <git@kchr.de> * Speed up storage iteration from within the runtime (#13479) * Speed up storage iteration from within the runtime * Move the cached iterator into an `Option` * Use `RefCell` in no_std * Simplify the code slightly * Use `Option::replace` * Update doc comment for `next_storage_key_slow` * Make unbounded channels size warning exact (part 1) (#13490) * Replace `futures-channel` with `async-channel` in `out_events` * Apply suggestions from code review Co-authored-by: Koute <koute@users.noreply.github.com> * Also print the backtrace of `send()` call * Switch from `backtrace` crate to `std::backtrace` * Remove outdated `backtrace` dependency * Remove `backtrace` from `Cargo.lock` --------- Co-authored-by: Koute <koute@users.noreply.github.com> * Removal of Prometheus alerting rules deployment in cloud-infra (#13499) * sp-consensus: remove unused error variants (#13495) * Expose `ChargedAmount` (#13488) * Expose `ChargedAmount` * Fix imports * sc-consensus-beefy: fix metrics: use correct names (#13494) Signed-off-by: acatangiu <adrian@parity.io> * clippy fix * removes NominationsQuotaExceeded event * Update frame/staking/src/lib.rs Co-authored-by: Ross Bulat <ross@parity.io> * adds back the npos_max_iter * remove duplicate imports added after merge * fmt * Adds comment in public struct; Refactors CountBound and SizeCount to struct * addresses various pr comments * PR comment reviews * Fixes on-chain election bounds and related code * EPM checks the size of the voter list returned by the data provider * cosmetic changes * updates e2e tests mock * Adds more tests for size tracker and refactors code * Adds back only_iterates_max_2_times_max_allowed_len test * Refactor * removes unecessary dependency * empty commit -- restart all stuck CI jobs * restarts ci jobs * Renames ElectionBounds -> Bounds in benchmarking mocks et al * updates mocks * Update frame/election-provider-support/src/lib.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * Update frame/staking/src/pallet/impls.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * Update frame/election-provider-support/src/lib.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * Update frame/staking/src/tests.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * more checks in api_nominations_quota in tests * Improves docs * fixes e2e tests * Uses size_hint rather than mem::size_of in size tracker; Refactor size tracker to own module * nits from reviews * Refactors bounds to own module; improves docs * More tests and docs * fixes docs * Fixes benchmarks * Fixes rust docs * fixes bags-list remote-ext-tests * Simplify bound checks in create_snapshot_external * Adds target size check in get_npos_targets * ".git/.scripts/commands/fmt/fmt.sh" * restart ci * rust doc fixes and cosmetic nits * rollback upgrade on parity-scale-codec version (unecessary) * reset cargo lock, no need to update it --------- Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> Signed-off-by: acatangiu <adrian@parity.io> Co-authored-by: command-bot <> Co-authored-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> Co-authored-by: Davide Galassi <davxy@datawok.net> Co-authored-by: yjh <yjh465402634@gmail.com> Co-authored-by: Bastian Köcher <git@kchr.de> Co-authored-by: Koute <koute@users.noreply.github.com> Co-authored-by: Dmitry Markin <dmitry@markin.tech> Co-authored-by: Anthony Lazam <lazam@users.noreply.github.com> Co-authored-by: André Silva <123550+andresilva@users.noreply.github.com> Co-authored-by: Piotr Mikołajczyk <piomiko41@gmail.com> Co-authored-by: Adrian Catangiu <adrian@parity.io> Co-authored-by: Ross Bulat <ross@parity.io> Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com>
This commit is contained in:
@@ -18,7 +18,10 @@
|
||||
//! Tests for the module.
|
||||
|
||||
use super::{ConfigOp, Event, *};
|
||||
use frame_election_provider_support::{ElectionProvider, SortedListProvider, Support};
|
||||
use frame_election_provider_support::{
|
||||
bounds::{DataProviderBounds, ElectionBoundsBuilder},
|
||||
ElectionProvider, SortedListProvider, Support,
|
||||
};
|
||||
use frame_support::{
|
||||
assert_noop, assert_ok, assert_storage_noop, bounded_vec,
|
||||
dispatch::{extract_actual_weight, GetDispatchInfo, WithPostDispatchInfo},
|
||||
@@ -4508,12 +4511,16 @@ mod election_data_provider {
|
||||
.add_staker(71, 71, 10, StakerStatus::<AccountId>::Nominator(vec![21]))
|
||||
.add_staker(81, 81, 50, StakerStatus::<AccountId>::Nominator(vec![21]))
|
||||
.build_and_execute(|| {
|
||||
assert_ok!(<Staking as ElectionDataProvider>::electing_voters(None));
|
||||
// default bounds are unbounded.
|
||||
assert_ok!(<Staking as ElectionDataProvider>::electing_voters(
|
||||
DataProviderBounds::default()
|
||||
));
|
||||
assert_eq!(MinimumActiveStake::<Test>::get(), 10);
|
||||
|
||||
// remove staker with lower bond by limiting the number of voters and check
|
||||
// `MinimumActiveStake` again after electing voters.
|
||||
assert_ok!(<Staking as ElectionDataProvider>::electing_voters(Some(5)));
|
||||
let bounds = ElectionBoundsBuilder::default().voters_count(5.into()).build();
|
||||
assert_ok!(<Staking as ElectionDataProvider>::electing_voters(bounds.voters));
|
||||
assert_eq!(MinimumActiveStake::<Test>::get(), 50);
|
||||
});
|
||||
}
|
||||
@@ -4522,8 +4529,11 @@ mod election_data_provider {
|
||||
fn set_minimum_active_stake_lower_bond_works() {
|
||||
// if there are no voters, minimum active stake is zero (should not happen).
|
||||
ExtBuilder::default().has_stakers(false).build_and_execute(|| {
|
||||
// default bounds are unbounded.
|
||||
assert_ok!(<Staking as ElectionDataProvider>::electing_voters(
|
||||
DataProviderBounds::default()
|
||||
));
|
||||
assert_eq!(<Test as Config>::VoterList::count(), 0);
|
||||
assert_ok!(<Staking as ElectionDataProvider>::electing_voters(None));
|
||||
assert_eq!(MinimumActiveStake::<Test>::get(), 0);
|
||||
});
|
||||
|
||||
@@ -4537,7 +4547,9 @@ mod election_data_provider {
|
||||
assert_ok!(Staking::nominate(RuntimeOrigin::signed(4), vec![1]));
|
||||
assert_eq!(<Test as Config>::VoterList::count(), 5);
|
||||
|
||||
let voters_before = <Staking as ElectionDataProvider>::electing_voters(None).unwrap();
|
||||
let voters_before =
|
||||
<Staking as ElectionDataProvider>::electing_voters(DataProviderBounds::default())
|
||||
.unwrap();
|
||||
assert_eq!(MinimumActiveStake::<Test>::get(), 5);
|
||||
|
||||
// update minimum nominator bond.
|
||||
@@ -4547,7 +4559,9 @@ mod election_data_provider {
|
||||
// lower than `MinNominatorBond`.
|
||||
assert_eq!(<Test as Config>::VoterList::count(), 5);
|
||||
|
||||
let voters = <Staking as ElectionDataProvider>::electing_voters(None).unwrap();
|
||||
let voters =
|
||||
<Staking as ElectionDataProvider>::electing_voters(DataProviderBounds::default())
|
||||
.unwrap();
|
||||
assert_eq!(voters_before, voters);
|
||||
|
||||
// minimum active stake is lower than `MinNominatorBond`.
|
||||
@@ -4563,7 +4577,10 @@ mod election_data_provider {
|
||||
.add_staker(61, 61, 2_000, StakerStatus::<AccountId>::Nominator(vec![21]))
|
||||
.build_and_execute(|| {
|
||||
assert_eq!(Staking::weight_of(&101), 500);
|
||||
let voters = <Staking as ElectionDataProvider>::electing_voters(None).unwrap();
|
||||
let voters = <Staking as ElectionDataProvider>::electing_voters(
|
||||
DataProviderBounds::default(),
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(voters.len(), 5);
|
||||
assert_eq!(MinimumActiveStake::<Test>::get(), 500);
|
||||
|
||||
@@ -4575,7 +4592,10 @@ mod election_data_provider {
|
||||
// corrupt ledger state by lowering max unlocking chunks bounds.
|
||||
MaxUnlockingChunks::set(1);
|
||||
|
||||
let voters = <Staking as ElectionDataProvider>::electing_voters(None).unwrap();
|
||||
let voters = <Staking as ElectionDataProvider>::electing_voters(
|
||||
DataProviderBounds::default(),
|
||||
)
|
||||
.unwrap();
|
||||
// number of returned voters decreases since ledger entry of stash 101 is now
|
||||
// corrupt.
|
||||
assert_eq!(voters.len(), 4);
|
||||
@@ -4593,8 +4613,9 @@ mod election_data_provider {
|
||||
#[test]
|
||||
fn voters_include_self_vote() {
|
||||
ExtBuilder::default().nominate(false).build_and_execute(|| {
|
||||
// default bounds are unbounded.
|
||||
assert!(<Validators<Test>>::iter().map(|(x, _)| x).all(|v| Staking::electing_voters(
|
||||
None
|
||||
DataProviderBounds::default()
|
||||
)
|
||||
.unwrap()
|
||||
.into_iter()
|
||||
@@ -4602,39 +4623,11 @@ mod election_data_provider {
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn respects_snapshot_len_limits() {
|
||||
ExtBuilder::default()
|
||||
.set_status(41, StakerStatus::Validator)
|
||||
.build_and_execute(|| {
|
||||
// sum of all nominators who'd be voters (1), plus the self-votes (4).
|
||||
assert_eq!(<Test as Config>::VoterList::count(), 5);
|
||||
|
||||
// if limits is less..
|
||||
assert_eq!(Staking::electing_voters(Some(1)).unwrap().len(), 1);
|
||||
|
||||
// if limit is equal..
|
||||
assert_eq!(Staking::electing_voters(Some(5)).unwrap().len(), 5);
|
||||
|
||||
// if limit is more.
|
||||
assert_eq!(Staking::electing_voters(Some(55)).unwrap().len(), 5);
|
||||
|
||||
// if target limit is more..
|
||||
assert_eq!(Staking::electable_targets(Some(6)).unwrap().len(), 4);
|
||||
assert_eq!(Staking::electable_targets(Some(4)).unwrap().len(), 4);
|
||||
|
||||
// if target limit is less, then we return an error.
|
||||
assert_eq!(
|
||||
Staking::electable_targets(Some(1)).unwrap_err(),
|
||||
"Target snapshot too big"
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
// Tests the criteria that in `ElectionDataProvider::voters` function, we try to get at most
|
||||
// `maybe_max_len` voters, and if some of them end up being skipped, we iterate at most `2 *
|
||||
// maybe_max_len`.
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn only_iterates_max_2_times_max_allowed_len() {
|
||||
ExtBuilder::default()
|
||||
.nominate(false)
|
||||
@@ -4659,13 +4652,14 @@ mod election_data_provider {
|
||||
StakerStatus::<AccountId>::Nominator(vec![21, 22, 23, 24, 25]),
|
||||
)
|
||||
.build_and_execute(|| {
|
||||
let bounds_builder = ElectionBoundsBuilder::default();
|
||||
// all voters ordered by stake,
|
||||
assert_eq!(
|
||||
<Test as Config>::VoterList::iter().collect::<Vec<_>>(),
|
||||
vec![61, 71, 81, 11, 21, 31]
|
||||
);
|
||||
|
||||
MaxNominations::set(2);
|
||||
AbsoluteMaxNominations::set(2);
|
||||
|
||||
// we want 2 voters now, and in maximum we allow 4 iterations. This is what happens:
|
||||
// 61 is pruned;
|
||||
@@ -4674,7 +4668,7 @@ mod election_data_provider {
|
||||
// 11 is taken;
|
||||
// we finish since the 2x limit is reached.
|
||||
assert_eq!(
|
||||
Staking::electing_voters(Some(2))
|
||||
Staking::electing_voters(bounds_builder.voters_count(2.into()).build().voters)
|
||||
.unwrap()
|
||||
.iter()
|
||||
.map(|(stash, _, _)| stash)
|
||||
@@ -4685,6 +4679,189 @@ mod election_data_provider {
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn respects_snapshot_count_limits() {
|
||||
ExtBuilder::default()
|
||||
.set_status(41, StakerStatus::Validator)
|
||||
.build_and_execute(|| {
|
||||
// sum of all nominators who'd be voters (1), plus the self-votes (4).
|
||||
assert_eq!(<Test as Config>::VoterList::count(), 5);
|
||||
|
||||
let bounds_builder = ElectionBoundsBuilder::default();
|
||||
|
||||
// if voter count limit is less..
|
||||
assert_eq!(
|
||||
Staking::electing_voters(bounds_builder.voters_count(1.into()).build().voters)
|
||||
.unwrap()
|
||||
.len(),
|
||||
1
|
||||
);
|
||||
|
||||
// if voter count limit is equal..
|
||||
assert_eq!(
|
||||
Staking::electing_voters(bounds_builder.voters_count(5.into()).build().voters)
|
||||
.unwrap()
|
||||
.len(),
|
||||
5
|
||||
);
|
||||
|
||||
// if voter count limit is more.
|
||||
assert_eq!(
|
||||
Staking::electing_voters(bounds_builder.voters_count(55.into()).build().voters)
|
||||
.unwrap()
|
||||
.len(),
|
||||
5
|
||||
);
|
||||
|
||||
// if target count limit is more..
|
||||
assert_eq!(
|
||||
Staking::electable_targets(
|
||||
bounds_builder.targets_count(6.into()).build().targets
|
||||
)
|
||||
.unwrap()
|
||||
.len(),
|
||||
4
|
||||
);
|
||||
|
||||
// if target count limit is equal..
|
||||
assert_eq!(
|
||||
Staking::electable_targets(
|
||||
bounds_builder.targets_count(4.into()).build().targets
|
||||
)
|
||||
.unwrap()
|
||||
.len(),
|
||||
4
|
||||
);
|
||||
|
||||
// if target limit count is less, then we return an error.
|
||||
assert_eq!(
|
||||
Staking::electable_targets(
|
||||
bounds_builder.targets_count(1.into()).build().targets
|
||||
)
|
||||
.unwrap_err(),
|
||||
"Target snapshot too big"
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn respects_snapshot_size_limits() {
|
||||
ExtBuilder::default().build_and_execute(|| {
|
||||
// voters: set size bounds that allows only for 1 voter.
|
||||
let bounds = ElectionBoundsBuilder::default().voters_size(26.into()).build();
|
||||
let elected = Staking::electing_voters(bounds.voters).unwrap();
|
||||
assert!(elected.encoded_size() == 26 as usize);
|
||||
let prev_len = elected.len();
|
||||
|
||||
// larger size bounds means more quota for voters.
|
||||
let bounds = ElectionBoundsBuilder::default().voters_size(100.into()).build();
|
||||
let elected = Staking::electing_voters(bounds.voters).unwrap();
|
||||
assert!(elected.encoded_size() <= 100 as usize);
|
||||
assert!(elected.len() > 1 && elected.len() > prev_len);
|
||||
|
||||
// targets: set size bounds that allows for only one target to fit in the snapshot.
|
||||
let bounds = ElectionBoundsBuilder::default().targets_size(10.into()).build();
|
||||
let elected = Staking::electable_targets(bounds.targets).unwrap();
|
||||
assert!(elected.encoded_size() == 9 as usize);
|
||||
let prev_len = elected.len();
|
||||
|
||||
// larger size bounds means more space for targets.
|
||||
let bounds = ElectionBoundsBuilder::default().targets_size(100.into()).build();
|
||||
let elected = Staking::electable_targets(bounds.targets).unwrap();
|
||||
assert!(elected.encoded_size() <= 100 as usize);
|
||||
assert!(elected.len() > 1 && elected.len() > prev_len);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn nomination_quota_checks_at_nominate_works() {
|
||||
ExtBuilder::default().nominate(false).build_and_execute(|| {
|
||||
// stash bond of 222 has a nomination quota of 2 targets.
|
||||
bond(61, 222);
|
||||
assert_eq!(Staking::api_nominations_quota(222), 2);
|
||||
|
||||
// nominating with targets below the nomination quota works.
|
||||
assert_ok!(Staking::nominate(RuntimeOrigin::signed(61), vec![11]));
|
||||
assert_ok!(Staking::nominate(RuntimeOrigin::signed(61), vec![11, 12]));
|
||||
|
||||
// nominating with targets above the nomination quota returns error.
|
||||
assert_noop!(
|
||||
Staking::nominate(RuntimeOrigin::signed(61), vec![11, 12, 13]),
|
||||
Error::<Test>::TooManyTargets
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn lazy_quota_npos_voters_works_above_quota() {
|
||||
ExtBuilder::default()
|
||||
.nominate(false)
|
||||
.add_staker(
|
||||
61,
|
||||
60,
|
||||
300, // 300 bond has 16 nomination quota.
|
||||
StakerStatus::<AccountId>::Nominator(vec![21, 22, 23, 24, 25]),
|
||||
)
|
||||
.build_and_execute(|| {
|
||||
// unbond 78 from stash 60 so that it's bonded balance is 222, which has a lower
|
||||
// nomination quota than at nomination time (max 2 targets).
|
||||
assert_ok!(Staking::unbond(RuntimeOrigin::signed(61), 78));
|
||||
assert_eq!(Staking::api_nominations_quota(300 - 78), 2);
|
||||
|
||||
// even through 61 has nomination quota of 2 at the time of the election, all the
|
||||
// nominations (5) will be used.
|
||||
assert_eq!(
|
||||
Staking::electing_voters(DataProviderBounds::default())
|
||||
.unwrap()
|
||||
.iter()
|
||||
.map(|(stash, _, targets)| (*stash, targets.len()))
|
||||
.collect::<Vec<_>>(),
|
||||
vec![(11, 1), (21, 1), (31, 1), (61, 5)],
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn nominations_quota_limits_size_work() {
|
||||
ExtBuilder::default()
|
||||
.nominate(false)
|
||||
.add_staker(
|
||||
71,
|
||||
70,
|
||||
333,
|
||||
StakerStatus::<AccountId>::Nominator(vec![16, 15, 14, 13, 12, 11, 10]),
|
||||
)
|
||||
.build_and_execute(|| {
|
||||
// nominations of controller 70 won't be added due to voter size limit exceeded.
|
||||
let bounds = ElectionBoundsBuilder::default().voters_size(100.into()).build();
|
||||
assert_eq!(
|
||||
Staking::electing_voters(bounds.voters)
|
||||
.unwrap()
|
||||
.iter()
|
||||
.map(|(stash, _, targets)| (*stash, targets.len()))
|
||||
.collect::<Vec<_>>(),
|
||||
vec![(11, 1), (21, 1), (31, 1)],
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
*staking_events().last().unwrap(),
|
||||
Event::SnapshotVotersSizeExceeded { size: 75 }
|
||||
);
|
||||
|
||||
// however, if the election voter size bounds were largers, the snapshot would
|
||||
// include the electing voters of 70.
|
||||
let bounds = ElectionBoundsBuilder::default().voters_size(1_000.into()).build();
|
||||
assert_eq!(
|
||||
Staking::electing_voters(bounds.voters)
|
||||
.unwrap()
|
||||
.iter()
|
||||
.map(|(stash, _, targets)| (*stash, targets.len()))
|
||||
.collect::<Vec<_>>(),
|
||||
vec![(11, 1), (21, 1), (31, 1), (71, 7)],
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn estimate_next_election_works() {
|
||||
ExtBuilder::default().session_per_era(5).period(5).build_and_execute(|| {
|
||||
@@ -5120,7 +5297,8 @@ fn min_commission_works() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn change_of_max_nominations() {
|
||||
#[should_panic]
|
||||
fn change_of_absolute_max_nominations() {
|
||||
use frame_election_provider_support::ElectionDataProvider;
|
||||
ExtBuilder::default()
|
||||
.add_staker(61, 61, 10, StakerStatus::Nominator(vec![1]))
|
||||
@@ -5128,7 +5306,7 @@ fn change_of_max_nominations() {
|
||||
.balance_factor(10)
|
||||
.build_and_execute(|| {
|
||||
// pre-condition
|
||||
assert_eq!(MaxNominations::get(), 16);
|
||||
assert_eq!(AbsoluteMaxNominations::get(), 16);
|
||||
|
||||
assert_eq!(
|
||||
Nominators::<Test>::iter()
|
||||
@@ -5136,11 +5314,15 @@ fn change_of_max_nominations() {
|
||||
.collect::<Vec<_>>(),
|
||||
vec![(101, 2), (71, 3), (61, 1)]
|
||||
);
|
||||
|
||||
// default bounds are unbounded.
|
||||
let bounds = DataProviderBounds::default();
|
||||
|
||||
// 3 validators and 3 nominators
|
||||
assert_eq!(Staking::electing_voters(None).unwrap().len(), 3 + 3);
|
||||
assert_eq!(Staking::electing_voters(bounds).unwrap().len(), 3 + 3);
|
||||
|
||||
// abrupt change from 16 to 4, everyone should be fine.
|
||||
MaxNominations::set(4);
|
||||
AbsoluteMaxNominations::set(4);
|
||||
|
||||
assert_eq!(
|
||||
Nominators::<Test>::iter()
|
||||
@@ -5148,10 +5330,10 @@ fn change_of_max_nominations() {
|
||||
.collect::<Vec<_>>(),
|
||||
vec![(101, 2), (71, 3), (61, 1)]
|
||||
);
|
||||
assert_eq!(Staking::electing_voters(None).unwrap().len(), 3 + 3);
|
||||
assert_eq!(Staking::electing_voters(bounds).unwrap().len(), 3 + 3);
|
||||
|
||||
// abrupt change from 4 to 3, everyone should be fine.
|
||||
MaxNominations::set(3);
|
||||
AbsoluteMaxNominations::set(3);
|
||||
|
||||
assert_eq!(
|
||||
Nominators::<Test>::iter()
|
||||
@@ -5159,11 +5341,11 @@ fn change_of_max_nominations() {
|
||||
.collect::<Vec<_>>(),
|
||||
vec![(101, 2), (71, 3), (61, 1)]
|
||||
);
|
||||
assert_eq!(Staking::electing_voters(None).unwrap().len(), 3 + 3);
|
||||
assert_eq!(Staking::electing_voters(bounds).unwrap().len(), 3 + 3);
|
||||
|
||||
// abrupt change from 3 to 2, this should cause some nominators to be non-decodable, and
|
||||
// thus non-existent unless if they update.
|
||||
MaxNominations::set(2);
|
||||
AbsoluteMaxNominations::set(2);
|
||||
|
||||
assert_eq!(
|
||||
Nominators::<Test>::iter()
|
||||
@@ -5176,12 +5358,12 @@ fn change_of_max_nominations() {
|
||||
// but its value cannot be decoded and default is returned.
|
||||
assert!(Nominators::<Test>::get(71).is_none());
|
||||
|
||||
assert_eq!(Staking::electing_voters(None).unwrap().len(), 3 + 2);
|
||||
assert_eq!(Staking::electing_voters(bounds).unwrap().len(), 3 + 2);
|
||||
assert!(Nominators::<Test>::contains_key(101));
|
||||
|
||||
// abrupt change from 2 to 1, this should cause some nominators to be non-decodable, and
|
||||
// thus non-existent unless if they update.
|
||||
MaxNominations::set(1);
|
||||
AbsoluteMaxNominations::set(1);
|
||||
|
||||
assert_eq!(
|
||||
Nominators::<Test>::iter()
|
||||
@@ -5193,7 +5375,7 @@ fn change_of_max_nominations() {
|
||||
assert!(Nominators::<Test>::contains_key(61));
|
||||
assert!(Nominators::<Test>::get(71).is_none());
|
||||
assert!(Nominators::<Test>::get(61).is_some());
|
||||
assert_eq!(Staking::electing_voters(None).unwrap().len(), 3 + 1);
|
||||
assert_eq!(Staking::electing_voters(bounds).unwrap().len(), 3 + 1);
|
||||
|
||||
// now one of them can revive themselves by re-nominating to a proper value.
|
||||
assert_ok!(Staking::nominate(RuntimeOrigin::signed(71), vec![1]));
|
||||
@@ -5213,6 +5395,42 @@ fn change_of_max_nominations() {
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn nomination_quota_max_changes_decoding() {
|
||||
use frame_election_provider_support::ElectionDataProvider;
|
||||
ExtBuilder::default()
|
||||
.add_staker(60, 61, 10, StakerStatus::Nominator(vec![1]))
|
||||
.add_staker(70, 71, 10, StakerStatus::Nominator(vec![1, 2, 3]))
|
||||
.add_staker(30, 330, 10, StakerStatus::Nominator(vec![1, 2, 3, 4]))
|
||||
.add_staker(50, 550, 10, StakerStatus::Nominator(vec![1, 2, 3, 4]))
|
||||
.balance_factor(10)
|
||||
.build_and_execute(|| {
|
||||
// pre-condition.
|
||||
assert_eq!(MaxNominationsOf::<Test>::get(), 16);
|
||||
|
||||
let unbonded_election = DataProviderBounds::default();
|
||||
|
||||
assert_eq!(
|
||||
Nominators::<Test>::iter()
|
||||
.map(|(k, n)| (k, n.targets.len()))
|
||||
.collect::<Vec<_>>(),
|
||||
vec![(70, 3), (101, 2), (50, 4), (30, 4), (60, 1)]
|
||||
);
|
||||
// 4 validators and 4 nominators
|
||||
assert_eq!(Staking::electing_voters(unbonded_election).unwrap().len(), 4 + 4);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn api_nominations_quota_works() {
|
||||
ExtBuilder::default().build_and_execute(|| {
|
||||
assert_eq!(Staking::api_nominations_quota(10), MaxNominationsOf::<Test>::get());
|
||||
assert_eq!(Staking::api_nominations_quota(333), MaxNominationsOf::<Test>::get());
|
||||
assert_eq!(Staking::api_nominations_quota(222), 2);
|
||||
assert_eq!(Staking::api_nominations_quota(111), 1);
|
||||
})
|
||||
}
|
||||
|
||||
mod sorted_list_provider {
|
||||
use super::*;
|
||||
use frame_election_provider_support::SortedListProvider;
|
||||
|
||||
Reference in New Issue
Block a user