Newer
Older
}
);
})
}
#[test]
fn on_finalize_weight_is_nonzero() {
ExtBuilder::default().build_and_execute(|| {
let on_finalize_weight = <Test as frame_system::Config>::DbWeight::get().reads(1);
assert!(<Staking as Hooks<u64>>::on_initialize(1).all_gte(on_finalize_weight));
mod election_data_provider {
use super::*;
use frame_election_provider_support::ElectionDataProvider;
#[test]
fn targets_2sec_block() {
let mut validators = 1000;
while <Test as Config>::WeightInfo::get_npos_targets(validators).all_lt(Weight::from_parts(
2u64 * frame_support::weights::constants::WEIGHT_REF_TIME_PER_SECOND,
u64::MAX,
)) {
validators += 1;
}
println!("Can create a snapshot of {} validators in 2sec block", validators);
}
#[test]
fn voters_2sec_block() {
// we assume a network only wants up to 1000 validators in most cases, thus having 2000
// candidates is as high as it gets.
let validators = 2000;
let mut nominators = 1000;
while <Test as Config>::WeightInfo::get_npos_voters(validators, nominators).all_lt(
Weight::from_parts(
2u64 * frame_support::weights::constants::WEIGHT_REF_TIME_PER_SECOND,
u64::MAX,
nominators += 1;
}
println!(
"Can create a snapshot of {} nominators [{} validators, each 1 slashing] in 2sec block",
nominators, validators
);
}
#[test]
fn set_minimum_active_stake_is_correct() {
ExtBuilder::default()
.nominate(false)
.add_staker(61, 61, 2_000, StakerStatus::<AccountId>::Nominator(vec![21]))
.add_staker(71, 71, 10, StakerStatus::<AccountId>::Nominator(vec![21]))
.add_staker(81, 81, 50, StakerStatus::<AccountId>::Nominator(vec![21]))
.build_and_execute(|| {
// 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.
let bounds = ElectionBoundsBuilder::default().voters_count(5.into()).build();
assert_ok!(<Staking as ElectionDataProvider>::electing_voters(bounds.voters));
assert_eq!(MinimumActiveStake::<Test>::get(), 50);
});
}
#[test]
Gonçalo Pestana
committed
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()
));
Gonçalo Pestana
committed
assert_eq!(<Test as Config>::VoterList::count(), 0);
assert_eq!(MinimumActiveStake::<Test>::get(), 0);
});
Gonçalo Pestana
committed
// lower non-zero active stake below `MinNominatorBond` is the minimum active stake if
// it is selected as part of the npos voters.
ExtBuilder::default().has_stakers(true).nominate(true).build_and_execute(|| {
assert_eq!(MinNominatorBond::<Test>::get(), 1);
assert_eq!(<Test as Config>::VoterList::count(), 4);
assert_ok!(Staking::bond(RuntimeOrigin::signed(4), 5, RewardDestination::Staked,));
Gonçalo Pestana
committed
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(DataProviderBounds::default())
.unwrap();
Gonçalo Pestana
committed
assert_eq!(MinimumActiveStake::<Test>::get(), 5);
// update minimum nominator bond.
MinNominatorBond::<Test>::set(10);
assert_eq!(MinNominatorBond::<Test>::get(), 10);
// voter list still considers nominator 4 for voting, even though its active stake is
// lower than `MinNominatorBond`.
assert_eq!(<Test as Config>::VoterList::count(), 5);
let voters =
<Staking as ElectionDataProvider>::electing_voters(DataProviderBounds::default())
.unwrap();
Gonçalo Pestana
committed
assert_eq!(voters_before, voters);
// minimum active stake is lower than `MinNominatorBond`.
assert_eq!(MinimumActiveStake::<Test>::get(), 5);
});
}
#[test]
fn set_minimum_active_bond_corrupt_state() {
ExtBuilder::default()
.has_stakers(true)
.nominate(true)
.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(
DataProviderBounds::default(),
)
.unwrap();
Gonçalo Pestana
committed
assert_eq!(voters.len(), 5);
assert_eq!(MinimumActiveStake::<Test>::get(), 500);
assert_ok!(Staking::unbond(RuntimeOrigin::signed(101), 200));
start_active_era(10);
assert_ok!(Staking::unbond(RuntimeOrigin::signed(101), 100));
start_active_era(20);
// corrupt ledger state by lowering max unlocking chunks bounds.
MaxUnlockingChunks::set(1);
let voters = <Staking as ElectionDataProvider>::electing_voters(
DataProviderBounds::default(),
)
.unwrap();
Gonçalo Pestana
committed
// number of returned voters decreases since ledger entry of stash 101 is now
// corrupt.
assert_eq!(voters.len(), 4);
// minimum active stake does not take into consideration the corrupt entry.
assert_eq!(MinimumActiveStake::<Test>::get(), 2_000);
// voter weight of corrupted ledger entry is 0.
assert_eq!(Staking::weight_of(&101), 0);
// reset max unlocking chunks for try_state to pass.
MaxUnlockingChunks::set(32);
})
#[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(
DataProviderBounds::default()
)
.unwrap()
.into_iter()
.any(|(w, _, t)| { v == w && t[0] == w })))
})
}
Kian Paimani
committed
// 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]
Kian Paimani
committed
fn only_iterates_max_2_times_max_allowed_len() {
ExtBuilder::default()
Kian Paimani
committed
.nominate(false)
// the best way to invalidate a bunch of nominators is to have them nominate a lot of
// ppl, but then lower the MaxNomination limit.
.add_staker(
61,
61,
2_000,
StakerStatus::<AccountId>::Nominator(vec![21, 22, 23, 24, 25]),
)
.add_staker(
71,
71,
2_000,
StakerStatus::<AccountId>::Nominator(vec![21, 22, 23, 24, 25]),
)
.add_staker(
81,
81,
2_000,
StakerStatus::<AccountId>::Nominator(vec![21, 22, 23, 24, 25]),
)
.build_and_execute(|| {
let bounds_builder = ElectionBoundsBuilder::default();
Kian Paimani
committed
// all voters ordered by stake,
assert_eq!(
Kian Paimani
committed
<Test as Config>::VoterList::iter().collect::<Vec<_>>(),
vec![61, 71, 81, 11, 21, 31]
);
AbsoluteMaxNominations::set(2);
Kian Paimani
committed
// we want 2 voters now, and in maximum we allow 4 iterations. This is what happens:
// 61 is pruned;
// 71 is pruned;
// 81 is pruned;
// 11 is taken;
// we finish since the 2x limit is reached.
assert_eq!(
Staking::electing_voters(bounds_builder.voters_count(2.into()).build().voters)
.unwrap()
.iter()
.map(|(stash, _, _)| stash)
.copied()
.collect::<Vec<_>>(),
Kian Paimani
committed
vec![11],
);
});
}
5229
5230
5231
5232
5233
5234
5235
5236
5237
5238
5239
5240
5241
5242
5243
5244
5245
5246
5247
5248
5249
5250
5251
5252
5253
5254
5255
5256
5257
5258
5259
5260
5261
5262
5263
5264
5265
5266
5267
5268
5269
5270
5271
5272
5273
5274
5275
5276
5277
5278
5279
5280
5281
5282
5283
5284
5285
5286
5287
5288
5289
5290
5291
5292
5293
5294
5295
5296
5297
5298
5299
5300
5301
5302
5303
5304
5305
5306
5307
5308
5309
5310
5311
5312
5313
5314
5315
5316
5317
5318
5319
5320
5321
5322
5323
5324
5325
5326
5327
5328
5329
5330
5331
5332
5333
5334
5335
5336
5337
5338
5339
5340
5341
5342
5343
5344
5345
5346
5347
5348
5349
5350
5351
5352
5353
5354
5355
5356
5357
5358
5359
5360
5361
5362
5363
5364
5365
5366
5367
5368
5369
5370
5371
5372
5373
5374
5375
5376
5377
5378
5379
5380
5381
5382
5383
5384
5385
5386
5387
5388
5389
5390
5391
5392
5393
5394
5395
5396
5397
5398
5399
5400
5401
5402
5403
5404
5405
5406
5407
5408
5409
5410
5411
#[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(|| {
// first session is always length 0.
for b in 1..20 {
run_to_block(b);
assert_eq!(Staking::next_election_prediction(System::block_number()), 20);
}
// election
run_to_block(20);
assert_eq!(Staking::next_election_prediction(System::block_number()), 45);
assert_eq!(staking_events().len(), 1);
Gavin Wood
committed
assert_eq!(*staking_events().last().unwrap(), Event::StakersElected);
for b in 21..45 {
run_to_block(b);
assert_eq!(Staking::next_election_prediction(System::block_number()), 45);
}
// election
run_to_block(45);
assert_eq!(Staking::next_election_prediction(System::block_number()), 70);
assert_eq!(staking_events().len(), 3);
Gavin Wood
committed
assert_eq!(*staking_events().last().unwrap(), Event::StakersElected);
thiolliere
committed
Staking::force_no_eras(RuntimeOrigin::root()).unwrap();
assert_eq!(Staking::next_election_prediction(System::block_number()), u64::MAX);
thiolliere
committed
Staking::force_new_era_always(RuntimeOrigin::root()).unwrap();
thiolliere
committed
assert_eq!(Staking::next_election_prediction(System::block_number()), 45 + 5);
Staking::force_new_era(RuntimeOrigin::root()).unwrap();
thiolliere
committed
assert_eq!(Staking::next_election_prediction(System::block_number()), 45 + 5);
// Do a fail election
MinimumValidatorCount::<Test>::put(1000);
run_to_block(50);
// Election: failed, next session is a new election
assert_eq!(Staking::next_election_prediction(System::block_number()), 50 + 5);
// The new era is still forced until a new era is planned.
assert_eq!(ForceEra::<Test>::get(), Forcing::ForceNew);
MinimumValidatorCount::<Test>::put(2);
run_to_block(55);
assert_eq!(Staking::next_election_prediction(System::block_number()), 55 + 25);
assert_eq!(staking_events().len(), 10);
assert_eq!(
*staking_events().last().unwrap(),
Event::ForceEra { mode: Forcing::NotForcing }
);
assert_eq!(
*staking_events().get(staking_events().len() - 2).unwrap(),
Event::StakersElected
);
thiolliere
committed
// The new era has been planned, forcing is changed from `ForceNew` to `NotForcing`.
assert_eq!(ForceEra::<Test>::get(), Forcing::NotForcing);
#[test]
#[should_panic]
fn count_check_works() {
ExtBuilder::default().build_and_execute(|| {
// We should never insert into the validators or nominators map directly as this will
// not keep track of the count. This test should panic as we verify the count is accurate
// after every test using the `post_checks` in `mock`.
Validators::<Test>::insert(987654321, ValidatorPrefs::default());
Nominators::<Test>::insert(
987654321,
Nominations {
targets: Default::default(),
submitted_in: Default::default(),
suppressed: false,
},
5492
5493
5494
5495
5496
5497
5498
5499
5500
5501
5502
5503
5504
5505
5506
5507
5508
5509
5510
5511
5512
5513
#[test]
#[should_panic = "called `Result::unwrap()` on an `Err` value: Other(\"number of entries in payee storage items does not match the number of bonded ledgers\")"]
fn check_payee_invariant1_works() {
// A bonded ledger should always have an assigned `Payee` This test should panic as we verify
// that a bad state will panic due to the `try_state` checks in the `post_checks` in `mock`.
ExtBuilder::default().build_and_execute(|| {
let rogue_ledger = StakingLedger::<Test>::new(123456, 20);
Ledger::<Test>::insert(123456, rogue_ledger);
})
}
#[test]
#[should_panic = "called `Result::unwrap()` on an `Err` value: Other(\"number of entries in payee storage items does not match the number of bonded ledgers\")"]
fn check_payee_invariant2_works() {
// The number of entries in both `Payee` and of bonded staking ledgers should match. This test
// should panic as we verify that a bad state will panic due to the `try_state` checks in the
// `post_checks` in `mock`.
ExtBuilder::default().build_and_execute(|| {
Payee::<Test>::insert(1111, RewardDestination::Staked);
})
}
#[test]
fn min_bond_checks_work() {
ExtBuilder::default()
.existential_deposit(100)
.balance_factor(100)
.min_nominator_bond(1_000)
.min_validator_bond(1_500)
.build_and_execute(|| {
// 500 is not enough for any role
assert_ok!(Staking::bond(RuntimeOrigin::signed(3), 500, RewardDestination::Stash));
Staking::nominate(RuntimeOrigin::signed(3), vec![1]),
Error::<Test>::InsufficientBond
);
assert_noop!(
Staking::validate(RuntimeOrigin::signed(3), ValidatorPrefs::default()),
assert_ok!(Staking::bond_extra(RuntimeOrigin::signed(3), 500));
assert_ok!(Staking::nominate(RuntimeOrigin::signed(3), vec![1]));
Staking::validate(RuntimeOrigin::signed(3), ValidatorPrefs::default()),
Error::<Test>::InsufficientBond,
);
assert_ok!(Staking::bond_extra(RuntimeOrigin::signed(3), 500));
assert_ok!(Staking::nominate(RuntimeOrigin::signed(3), vec![1]));
assert_ok!(Staking::validate(RuntimeOrigin::signed(3), ValidatorPrefs::default()));
// Can't unbond anything as validator
Staking::unbond(RuntimeOrigin::signed(3), 500),
Error::<Test>::InsufficientBond
);
// Once they are a nominator, they can unbond 500
assert_ok!(Staking::nominate(RuntimeOrigin::signed(3), vec![1]));
assert_ok!(Staking::unbond(RuntimeOrigin::signed(3), 500));
Staking::unbond(RuntimeOrigin::signed(3), 500),
Error::<Test>::InsufficientBond
);
// Once they are chilled they can unbond everything
assert_ok!(Staking::chill(RuntimeOrigin::signed(3)));
assert_ok!(Staking::unbond(RuntimeOrigin::signed(3), 1000));
#[test]
fn chill_other_works() {
ExtBuilder::default()
.existential_deposit(100)
.balance_factor(100)
.min_nominator_bond(1_000)
.min_validator_bond(1_500)
.build_and_execute(|| {
let initial_validators = Validators::<Test>::count();
let initial_nominators = Nominators::<Test>::count();
for i in 0..15 {
let a = 4 * i;
let b = 4 * i + 2;
let c = 4 * i + 3;
Balances::make_free_balance_be(&a, 100_000);
Balances::make_free_balance_be(&b, 100_000);
Balances::make_free_balance_be(&c, 100_000);
// Nominator
assert_ok!(Staking::bond(RuntimeOrigin::signed(a), 1000, RewardDestination::Stash));
assert_ok!(Staking::nominate(RuntimeOrigin::signed(a), vec![1]));
assert_ok!(Staking::bond(RuntimeOrigin::signed(b), 1500, RewardDestination::Stash));
assert_ok!(Staking::validate(RuntimeOrigin::signed(b), ValidatorPrefs::default()));
// To chill other users, we need to:
// * Set a minimum bond amount
// * Set a limit
// * Set a threshold
//
// If any of these are missing, we do not have enough information to allow the
// `chill_other` to succeed from one user to another.
// Can't chill these users
assert_noop!(
Staking::chill_other(RuntimeOrigin::signed(1337), 0),
Error::<Test>::CannotChillOther
);
assert_noop!(
Staking::chill_other(RuntimeOrigin::signed(1337), 2),
Error::<Test>::CannotChillOther
);
// Change the minimum bond... but no limits.
assert_ok!(Staking::set_staking_configs(
ConfigOp::Set(1_500),
ConfigOp::Set(2_000),
ConfigOp::Remove,
ConfigOp::Remove,
ConfigOp::Remove,
ConfigOp::Remove,
ConfigOp::Noop,
// Still can't chill these users
assert_noop!(
Staking::chill_other(RuntimeOrigin::signed(1337), 0),
Error::<Test>::CannotChillOther
);
assert_noop!(
Staking::chill_other(RuntimeOrigin::signed(1337), 2),
Error::<Test>::CannotChillOther
);
// Add limits, but no threshold
assert_ok!(Staking::set_staking_configs(
ConfigOp::Noop,
ConfigOp::Noop,
ConfigOp::Set(10),
ConfigOp::Set(10),
ConfigOp::Noop,
ConfigOp::Noop,
ConfigOp::Noop,
));
// Still can't chill these users
assert_noop!(
Staking::chill_other(RuntimeOrigin::signed(1337), 0),
Error::<Test>::CannotChillOther
);
assert_noop!(
Staking::chill_other(RuntimeOrigin::signed(1337), 2),
Error::<Test>::CannotChillOther
);
assert_ok!(Staking::set_staking_configs(
ConfigOp::Noop,
ConfigOp::Noop,
ConfigOp::Remove,
ConfigOp::Remove,
ConfigOp::Noop,
ConfigOp::Noop,
ConfigOp::Noop,
// Still can't chill these users
assert_noop!(
Staking::chill_other(RuntimeOrigin::signed(1337), 0),
Error::<Test>::CannotChillOther
);
assert_noop!(
Staking::chill_other(RuntimeOrigin::signed(1337), 2),
Error::<Test>::CannotChillOther
);
// Add threshold and limits
assert_ok!(Staking::set_staking_configs(
ConfigOp::Noop,
ConfigOp::Noop,
ConfigOp::Set(10),
ConfigOp::Set(10),
ConfigOp::Set(Percent::from_percent(75)),
ConfigOp::Noop,
ConfigOp::Noop,
));
// 16 people total because tests start with 2 active one
assert_eq!(Nominators::<Test>::count(), 15 + initial_nominators);
assert_eq!(Validators::<Test>::count(), 15 + initial_validators);
// Users can now be chilled down to 7 people, so we try to remove 9 of them (starting
// with 16)
let b = 4 * i;
let d = 4 * i + 2;
assert_ok!(Staking::chill_other(RuntimeOrigin::signed(1337), b));
assert_ok!(Staking::chill_other(RuntimeOrigin::signed(1337), d));
// chill a nominator. Limit is not reached, not chill-able
assert_eq!(Nominators::<Test>::count(), 7);
Staking::chill_other(RuntimeOrigin::signed(1337), 0),
Error::<Test>::CannotChillOther
);
// chill a validator. Limit is reached, chill-able.
assert_eq!(Validators::<Test>::count(), 9);
assert_ok!(Staking::chill_other(RuntimeOrigin::signed(1337), 2));
})
}
#[test]
fn capped_stakers_works() {
ExtBuilder::default().build_and_execute(|| {
let validator_count = Validators::<Test>::count();
let nominator_count = Nominators::<Test>::count();
assert_eq!(nominator_count, 1);
// Change the maximums
let max = 10;
assert_ok!(Staking::set_staking_configs(
ConfigOp::Set(10),
ConfigOp::Set(10),
ConfigOp::Set(max),
ConfigOp::Set(max),
ConfigOp::Remove,
ConfigOp::Remove,
ConfigOp::Noop,
));
// can create `max - validator_count` validators
let mut some_existing_validator = AccountId::default();
for i in 0..max - validator_count {
let (_, controller) = testing_utils::create_stash_controller::<Test>(
i + 10_000_000,
RewardDestination::Stash,
assert_ok!(Staking::validate(
RuntimeOrigin::signed(controller),
ValidatorPrefs::default()
));
some_existing_validator = controller;
}
let (_, last_validator) =
testing_utils::create_stash_controller::<Test>(1337, 100, RewardDestination::Stash)
.unwrap();
Staking::validate(RuntimeOrigin::signed(last_validator), ValidatorPrefs::default()),
Error::<Test>::TooManyValidators,
);
// same with nominators
let mut some_existing_nominator = AccountId::default();
for i in 0..max - nominator_count {
let (_, controller) = testing_utils::create_stash_controller::<Test>(
i + 20_000_000,
RewardDestination::Stash,
assert_ok!(Staking::nominate(RuntimeOrigin::signed(controller), vec![1]));
some_existing_nominator = controller;
}
// one more is too many.
let (_, last_nominator) = testing_utils::create_stash_controller::<Test>(
30_000_000,
100,
RewardDestination::Stash,
)
.unwrap();
assert_noop!(
Staking::nominate(RuntimeOrigin::signed(last_nominator), vec![1]),
Error::<Test>::TooManyNominators
);
assert_ok!(Staking::nominate(RuntimeOrigin::signed(some_existing_nominator), vec![1]));
// Re-validate works fine
assert_ok!(Staking::validate(
RuntimeOrigin::signed(some_existing_validator),
ValidatorPrefs::default()
));
// No problem when we set to `None` again
assert_ok!(Staking::set_staking_configs(
ConfigOp::Noop,
ConfigOp::Noop,
ConfigOp::Remove,
ConfigOp::Remove,
ConfigOp::Noop,
ConfigOp::Noop,
ConfigOp::Noop,
assert_ok!(Staking::nominate(RuntimeOrigin::signed(last_nominator), vec![1]));
assert_ok!(Staking::validate(
RuntimeOrigin::signed(last_validator),
ValidatorPrefs::default()
));
#[test]
fn min_commission_works() {
ExtBuilder::default().build_and_execute(|| {
// account 11 controls the stash of itself.
assert_ok!(Staking::validate(
RuntimeOrigin::signed(11),
ValidatorPrefs { commission: Perbill::from_percent(5), blocked: false }
));
// event emitted should be correct
assert_eq!(
*staking_events().last().unwrap(),
Event::ValidatorPrefsSet {
stash: 11,
prefs: ValidatorPrefs { commission: Perbill::from_percent(5), blocked: false }
}
assert_ok!(Staking::set_staking_configs(
ConfigOp::Remove,
ConfigOp::Remove,
ConfigOp::Remove,
ConfigOp::Remove,
ConfigOp::Remove,
ConfigOp::Set(Perbill::from_percent(10)),
ConfigOp::Noop,
));
// can't make it less than 10 now
assert_noop!(
Staking::validate(
RuntimeOrigin::signed(11),
ValidatorPrefs { commission: Perbill::from_percent(5), blocked: false }
),
Error::<Test>::CommissionTooLow
);
// can only change to higher.
assert_ok!(Staking::validate(
RuntimeOrigin::signed(11),
ValidatorPrefs { commission: Perbill::from_percent(10), blocked: false }
));
assert_ok!(Staking::validate(
RuntimeOrigin::signed(11),
ValidatorPrefs { commission: Perbill::from_percent(15), blocked: false }
));
})
}
#[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]))
.add_staker(71, 71, 10, StakerStatus::Nominator(vec![1, 2, 3]))
.balance_factor(10)
.build_and_execute(|| {
// pre-condition
assert_eq!(AbsoluteMaxNominations::get(), 16);
assert_eq!(
Nominators::<Test>::iter()
.map(|(k, n)| (k, n.targets.len()))
.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(bounds).unwrap().len(), 3 + 3);
// abrupt change from 16 to 4, everyone should be fine.
AbsoluteMaxNominations::set(4);
assert_eq!(
Nominators::<Test>::iter()
.map(|(k, n)| (k, n.targets.len()))
.collect::<Vec<_>>(),
vec![(101, 2), (71, 3), (61, 1)]
assert_eq!(Staking::electing_voters(bounds).unwrap().len(), 3 + 3);
// abrupt change from 4 to 3, everyone should be fine.
AbsoluteMaxNominations::set(3);
assert_eq!(
Nominators::<Test>::iter()
.map(|(k, n)| (k, n.targets.len()))
.collect::<Vec<_>>(),
vec![(101, 2), (71, 3), (61, 1)]
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.
AbsoluteMaxNominations::set(2);
assert_eq!(
Nominators::<Test>::iter()
.map(|(k, n)| (k, n.targets.len()))
.collect::<Vec<_>>(),
vec![(101, 2), (61, 1)]
);
// 70 is still in storage..
assert!(Nominators::<Test>::contains_key(71));
// but its value cannot be decoded and default is returned.
assert!(Nominators::<Test>::get(71).is_none());
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.
AbsoluteMaxNominations::set(1);
assert_eq!(
Nominators::<Test>::iter()
.map(|(k, n)| (k, n.targets.len()))
.collect::<Vec<_>>(),
vec![(61, 1)]
assert!(Nominators::<Test>::contains_key(71));
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(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]));
assert_eq!(
Nominators::<Test>::iter()
.map(|(k, n)| (k, n.targets.len()))
.collect::<Vec<_>>(),
vec![(71, 1), (61, 1)]
);
// or they can be chilled by any account.
assert!(Nominators::<Test>::contains_key(101));
assert!(Nominators::<Test>::get(101).is_none());
assert_ok!(Staking::chill_other(RuntimeOrigin::signed(71), 101));
assert!(!Nominators::<Test>::contains_key(101));
assert!(Nominators::<Test>::get(101).is_none());
})
}
5963
5964
5965
5966
5967
5968
5969
5970
5971
5972
5973
5974
5975
5976
5977
5978
5979
5980
5981
5982
5983
5984
5985
5986
5987
5988
5989
5990
5991
5992
5993
5994
5995
5996
5997
5998
#[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::*;