Newer
Older
ExtBuilder::default()
.existential_deposit(10)
.build_and_execute(|| {
// initial stuff.
assert_eq!(
Staking::ledger(&20).unwrap(),
StakingLedger {
stash: 21,
total: 10 * 1000,
active: 10 * 1000,
unlocking: Default::default(),
claimed_rewards: vec![]
}
);
// unbond all of it. must be chilled first.
assert_ok!(Staking::chill(Origin::signed(20)));
assert_ok!(Staking::unbond(Origin::signed(20), 10 * 1000));
assert_eq!(
Staking::ledger(&20).unwrap(),
StakingLedger {
stash: 21,
active: 0,
unlocking: bounded_vec![UnlockChunk { value: 10 * 1000, era: 3 }],
claimed_rewards: vec![]
}
);
// now bond a wee bit more
assert_noop!(Staking::rebond(Origin::signed(20), 5), Error::<Test>::InsufficientBond);
})
}
#[test]
fn cannot_bond_extra_to_lower_than_ed() {
ExtBuilder::default()
.existential_deposit(10)
.build_and_execute(|| {
// initial stuff.
assert_eq!(
Staking::ledger(&20).unwrap(),
StakingLedger {
stash: 21,
total: 10 * 1000,
active: 10 * 1000,
unlocking: Default::default(),
claimed_rewards: vec![]
}
);
// unbond all of it. must be chilled first.
assert_ok!(Staking::chill(Origin::signed(20)));
assert_ok!(Staking::unbond(Origin::signed(20), 10 * 1000));
assert_eq!(
Staking::ledger(&20).unwrap(),
StakingLedger {
stash: 21,
active: 0,
unlocking: bounded_vec![UnlockChunk { value: 10 * 1000, era: 3 }],
claimed_rewards: vec![]
}
);
// now bond a wee bit more
assert_noop!(
Staking::bond_extra(Origin::signed(21), 5),
Error::<Test>::InsufficientBond,
);
})
}
#[test]
fn do_not_die_when_active_is_ed() {
let ed = 10;
ExtBuilder::default()
.existential_deposit(ed)
.build_and_execute(|| {
assert_eq!(
Staking::ledger(&20).unwrap(),
StakingLedger {
stash: 21,
total: 1000 * ed,
active: 1000 * ed,
unlocking: Default::default(),
claimed_rewards: vec![]
}
);
// when unbond all of it except ed.
assert_ok!(Staking::unbond(Origin::signed(20), 999 * ed));
start_active_era(3);
assert_ok!(Staking::withdraw_unbonded(Origin::signed(20), 100));
assert_eq!(
Staking::ledger(&20).unwrap(),
StakingLedger {
stash: 21,
total: ed,
active: ed,
unlocking: Default::default(),
claimed_rewards: vec![]
}
);
})
}
#[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) >= 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) <
2 * frame_support::weights::constants::WEIGHT_PER_SECOND
{
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;
// we assume the worse case: each validator also has a slashing span.
let slashing_spans = validators;
let mut nominators = 1000;
while <Test as Config>::WeightInfo::get_npos_voters(validators, nominators, slashing_spans) <
2 * frame_support::weights::constants::WEIGHT_PER_SECOND
{
nominators += 1;
}
println!(
"Can create a snapshot of {} nominators [{} validators, each 1 slashing] in 2sec block",
nominators, validators
);
}
#[test]
fn voters_include_self_vote() {
ExtBuilder::default().nominate(false).build_and_execute(|| {
assert!(<Validators<Test>>::iter().map(|(x, _)| x).all(|v| Staking::electing_voters(
None
)
.unwrap()
.into_iter()
.any(|(w, _, t)| { v == w && t[0] == w })))
})
}
#[test]
fn voters_exclude_slashed() {
ExtBuilder::default().build_and_execute(|| {
assert_eq!(Staking::nominators(101).unwrap().targets, vec![11, 21]);
assert_eq!(
<Staking as ElectionDataProvider>::electing_voters(None)
.iter()
.find(|x| x.0 == 101)
.unwrap()
.2,
vec![11, 21]
);
start_active_era(1);
add_slash(&11);
// 11 is gone.
start_active_era(2);
assert_eq!(
<Staking as ElectionDataProvider>::electing_voters(None)
.iter()
.find(|x| x.0 == 101)
.unwrap()
.2,
vec![21]
);
// resubmit and it is back
assert_ok!(Staking::nominate(Origin::signed(100), vec![11, 21]));
assert_eq!(
<Staking as ElectionDataProvider>::electing_voters(None)
.iter()
.find(|x| x.0 == 101)
.unwrap()
.2,
vec![11, 21]
);
})
}
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).
Kian Paimani
committed
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"
);
});
}
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]
Kian Paimani
committed
fn only_iterates_max_2_times_max_allowed_len() {
ExtBuilder::default()
Kian Paimani
committed
.nominate(false)
// the other nominators only nominate 21
.add_staker(61, 60, 2_000, StakerStatus::<AccountId>::Nominator(vec![21]))
.add_staker(71, 70, 2_000, StakerStatus::<AccountId>::Nominator(vec![21]))
.add_staker(81, 80, 2_000, StakerStatus::<AccountId>::Nominator(vec![21]))
.build_and_execute(|| {
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]
);
run_to_block(25);
// slash 21, the only validator nominated by our first 3 nominators
add_slash(&21);
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!(
Kian Paimani
committed
Staking::electing_voters(Some(2))
.unwrap()
.iter()
.map(|(stash, _, _)| stash)
.copied()
.collect::<Vec<_>>(),
Kian Paimani
committed
vec![11],
);
});
}
// Even if some of the higher staked nominators are slashed, we still get up to max len voters
// by adding more lower staked nominators. In other words, we assert that we keep on adding
// valid nominators until we reach max len voters; which is opposed to simply stopping after we
// have iterated max len voters, but not adding all of them to voters due to some nominators not
// having valid targets.
#[test]
fn get_max_len_voters_even_if_some_nominators_are_slashed() {
ExtBuilder::default()
Kian Paimani
committed
.nominate(false)
.add_staker(61, 60, 20, StakerStatus::<AccountId>::Nominator(vec![21]))
.add_staker(71, 70, 10, StakerStatus::<AccountId>::Nominator(vec![11, 21]))
Kian Paimani
committed
.add_staker(81, 80, 10, StakerStatus::<AccountId>::Nominator(vec![11, 21]))
.build_and_execute(|| {
Kian Paimani
committed
// given our voters ordered by stake,
assert_eq!(
Kian Paimani
committed
<Test as Config>::VoterList::iter().collect::<Vec<_>>(),
vec![11, 21, 31, 61, 71, 81]
);
Kian Paimani
committed
// we take 4 voters
assert_eq!(
Kian Paimani
committed
Staking::electing_voters(Some(4))
.unwrap()
.iter()
.map(|(stash, _, _)| stash)
.copied()
.collect::<Vec<_>>(),
Kian Paimani
committed
vec![11, 21, 31, 61],
);
// roll to session 5
run_to_block(25);
Kian Paimani
committed
// slash 21, the only validator nominated by 61.
add_slash(&21);
Kian Paimani
committed
// we take 4 voters; 71 and 81 are replacing the ejected ones.
assert_eq!(
Staking::electing_voters(Some(4))
.unwrap()
.iter()
.map(|(stash, _, _)| stash)
.copied()
.collect::<Vec<_>>(),
Kian Paimani
committed
vec![11, 31, 71, 81],
);
});
#[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(Origin::root()).unwrap();
assert_eq!(Staking::next_election_prediction(System::block_number()), u64::MAX);
thiolliere
committed
Staking::force_new_era_always(Origin::root()).unwrap();
assert_eq!(Staking::next_election_prediction(System::block_number()), 45 + 5);
Staking::force_new_era(Origin::root()).unwrap();
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(), 6);
Gavin Wood
committed
assert_eq!(*staking_events().last().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,
},
4402
4403
4404
4405
4406
4407
4408
4409
4410
4411
4412
4413
4414
4415
4416
4417
4418
4419
4420
4421
4422
);
})
}
#[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(Origin::signed(3), 4, 500, RewardDestination::Controller));
assert_noop!(
Staking::nominate(Origin::signed(4), vec![1]),
Error::<Test>::InsufficientBond
);
assert_noop!(
Staking::validate(Origin::signed(4), ValidatorPrefs::default()),
Error::<Test>::InsufficientBond,
// 1000 is enough for nominator
assert_ok!(Staking::bond_extra(Origin::signed(3), 500));
assert_ok!(Staking::nominate(Origin::signed(4), vec![1]));
assert_noop!(
Staking::validate(Origin::signed(4), ValidatorPrefs::default()),
Error::<Test>::InsufficientBond,
);
// 1500 is enough for validator
assert_ok!(Staking::bond_extra(Origin::signed(3), 500));
assert_ok!(Staking::nominate(Origin::signed(4), vec![1]));
assert_ok!(Staking::validate(Origin::signed(4), ValidatorPrefs::default()));
// Can't unbond anything as validator
assert_noop!(Staking::unbond(Origin::signed(4), 500), Error::<Test>::InsufficientBond);
// Once they are a nominator, they can unbond 500
assert_ok!(Staking::nominate(Origin::signed(4), vec![1]));
assert_ok!(Staking::unbond(Origin::signed(4), 500));
assert_noop!(Staking::unbond(Origin::signed(4), 500), Error::<Test>::InsufficientBond);
// Once they are chilled they can unbond everything
assert_ok!(Staking::chill(Origin::signed(4)));
assert_ok!(Staking::unbond(Origin::signed(4), 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();
4462
4463
4464
4465
4466
4467
4468
4469
4470
4471
4472
4473
4474
4475
4476
4477
4478
4479
4480
4481
4482
4483
4484
4485
4486
for i in 0..15 {
let a = 4 * i;
let b = 4 * i + 1;
let c = 4 * i + 2;
let d = 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);
Balances::make_free_balance_be(&d, 100_000);
// Nominator
assert_ok!(Staking::bond(
Origin::signed(a),
b,
1000,
RewardDestination::Controller
));
assert_ok!(Staking::nominate(Origin::signed(b), vec![1]));
// Validator
assert_ok!(Staking::bond(
Origin::signed(c),
d,
1500,
RewardDestination::Controller
assert_ok!(Staking::validate(Origin::signed(d), 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(Origin::signed(1337), 1),
Error::<Test>::CannotChillOther
);
assert_noop!(
Staking::chill_other(Origin::signed(1337), 3),
Error::<Test>::CannotChillOther
);
// Change the minimum bond... but no limits.
assert_ok!(Staking::set_staking_configs(
Origin::root(),
ConfigOp::Set(1_500),
ConfigOp::Set(2_000),
ConfigOp::Remove,
ConfigOp::Remove,
ConfigOp::Remove,
ConfigOp::Remove
// Still can't chill these users
assert_noop!(
Staking::chill_other(Origin::signed(1337), 1),
Error::<Test>::CannotChillOther
);
assert_noop!(
Staking::chill_other(Origin::signed(1337), 3),
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
));
// Still can't chill these users
assert_noop!(
Staking::chill_other(Origin::signed(1337), 1),
Error::<Test>::CannotChillOther
);
assert_noop!(
Staking::chill_other(Origin::signed(1337), 3),
Error::<Test>::CannotChillOther
);
assert_ok!(Staking::set_staking_configs(
ConfigOp::Noop,
ConfigOp::Noop,
ConfigOp::Remove,
ConfigOp::Remove,
ConfigOp::Noop,
ConfigOp::Noop
// Still can't chill these users
assert_noop!(
Staking::chill_other(Origin::signed(1337), 1),
Error::<Test>::CannotChillOther
);
assert_noop!(
Staking::chill_other(Origin::signed(1337), 3),
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
));
// 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)
for i in 6..15 {
let b = 4 * i + 1;
let d = 4 * i + 3;
assert_ok!(Staking::chill_other(Origin::signed(1337), b));
assert_ok!(Staking::chill_other(Origin::signed(1337), d));
// chill a nominator. Limit is not reached, not chill-able
assert_eq!(Nominators::<Test>::count(), 7);
assert_noop!(
Staking::chill_other(Origin::signed(1337), 1),
Error::<Test>::CannotChillOther
);
// chill a validator. Limit is reached, chill-able.
assert_eq!(Validators::<Test>::count(), 9);
assert_ok!(Staking::chill_other(Origin::signed(1337), 3));
})
}
#[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,
));
// 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,
100,
RewardDestination::Controller,
)
.unwrap();
assert_ok!(Staking::validate(Origin::signed(controller), ValidatorPrefs::default()));
some_existing_validator = controller;
}
// but no more
let (_, last_validator) = testing_utils::create_stash_controller::<Test>(
1337,
100,
RewardDestination::Controller,
)
.unwrap();
assert_noop!(
Staking::validate(Origin::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,
100,
RewardDestination::Controller,
)
.unwrap();
assert_ok!(Staking::nominate(Origin::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::Controller,
)
.unwrap();
assert_noop!(
Staking::nominate(Origin::signed(last_nominator), vec![1]),
Error::<Test>::TooManyNominators
);
// Re-nominate works fine
assert_ok!(Staking::nominate(Origin::signed(some_existing_nominator), vec![1]));
// Re-validate works fine
assert_ok!(Staking::validate(
Origin::signed(some_existing_validator),
ValidatorPrefs::default()
));
// No problem when we set to `None` again
assert_ok!(Staking::set_staking_configs(
Origin::root(),
ConfigOp::Noop,
ConfigOp::Noop,
ConfigOp::Remove,
ConfigOp::Remove,
ConfigOp::Noop,
ConfigOp::Noop,
assert_ok!(Staking::nominate(Origin::signed(last_nominator), vec![1]));
assert_ok!(Staking::validate(Origin::signed(last_validator), ValidatorPrefs::default()));
})
#[test]
fn min_commission_works() {
ExtBuilder::default().build_and_execute(|| {
// account 10 controls the stash from account 11
assert_ok!(Staking::validate(
Origin::signed(10),
ValidatorPrefs { commission: Perbill::from_percent(5), blocked: false }
));
// event emitted should be correct
assert_eq!(
*staking_events().last().unwrap(),
Event::ValidatorPrefsSet(
11,
ValidatorPrefs { commission: Perbill::from_percent(5), blocked: false }
)
);
assert_ok!(Staking::set_staking_configs(
Origin::root(),
ConfigOp::Remove,
ConfigOp::Remove,
ConfigOp::Remove,
ConfigOp::Remove,
ConfigOp::Remove,
ConfigOp::Set(Perbill::from_percent(10)),
4728
4729
4730
4731
4732
4733
4734
4735
4736
4737
4738
4739
4740
4741
4742
4743
4744
4745
4746
4747
4748
4749
4750
4751
));
// can't make it less than 10 now
assert_noop!(
Staking::validate(
Origin::signed(10),
ValidatorPrefs { commission: Perbill::from_percent(5), blocked: false }
),
Error::<Test>::CommissionTooLow
);
// can only change to higher.
assert_ok!(Staking::validate(
Origin::signed(10),
ValidatorPrefs { commission: Perbill::from_percent(10), blocked: false }
));
assert_ok!(Staking::validate(
Origin::signed(10),
ValidatorPrefs { commission: Perbill::from_percent(15), blocked: false }
));
})
}
#[test]
fn change_of_max_nominations() {
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]))
.balance_factor(10)
.build_and_execute(|| {
// pre-condition
assert_eq!(MaxNominations::get(), 16);
assert_eq!(
Nominators::<Test>::iter()
.map(|(k, n)| (k, n.targets.len()))
.collect::<Vec<_>>(),
vec![(70, 3), (101, 2), (60, 1)]
);
// 3 validators and 3 nominators
assert_eq!(Staking::electing_voters(None).unwrap().len(), 3 + 3);
// abrupt change from 16 to 4, everyone should be fine.
MaxNominations::set(4);
assert_eq!(
Nominators::<Test>::iter()
.map(|(k, n)| (k, n.targets.len()))
.collect::<Vec<_>>(),
vec![(70, 3), (101, 2), (60, 1)]
);
assert_eq!(Staking::electing_voters(None).unwrap().len(), 3 + 3);
// abrupt change from 4 to 3, everyone should be fine.
MaxNominations::set(3);
assert_eq!(
Nominators::<Test>::iter()
.map(|(k, n)| (k, n.targets.len()))
.collect::<Vec<_>>(),
vec![(70, 3), (101, 2), (60, 1)]
);
assert_eq!(Staking::electing_voters(None).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);
assert_eq!(
Nominators::<Test>::iter()
.map(|(k, n)| (k, n.targets.len()))
.collect::<Vec<_>>(),
vec![(101, 2), (60, 1)]
);
// 70 is still in storage..
assert!(Nominators::<Test>::contains_key(70));
// but its value cannot be decoded and default is returned.
assert!(Nominators::<Test>::get(70).is_none());
assert_eq!(Staking::electing_voters(None).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);
assert_eq!(
Nominators::<Test>::iter()
.map(|(k, n)| (k, n.targets.len()))
.collect::<Vec<_>>(),
vec![(60, 1)]
);
assert!(Nominators::<Test>::contains_key(70));
assert!(Nominators::<Test>::contains_key(60));
assert!(Nominators::<Test>::get(70).is_none());
assert!(Nominators::<Test>::get(60).is_some());
assert_eq!(Staking::electing_voters(None).unwrap().len(), 3 + 1);
// now one of them can revive themselves by re-nominating to a proper value.
assert_ok!(Staking::nominate(Origin::signed(71), vec![1]));
assert_eq!(
Nominators::<Test>::iter()
.map(|(k, n)| (k, n.targets.len()))
.collect::<Vec<_>>(),
vec![(70, 1), (60, 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(Origin::signed(70), 100));
assert!(!Nominators::<Test>::contains_key(101));
assert!(Nominators::<Test>::get(101).is_none());
})
}
mod sorted_list_provider {
use super::*;
use frame_election_provider_support::SortedListProvider;
#[test]
fn re_nominate_does_not_change_counters_or_list() {
ExtBuilder::default().nominate(true).build_and_execute(|| {
// given
Kian Paimani
committed
let pre_insert_voter_count =
(Nominators::<Test>::count() + Validators::<Test>::count()) as u32;
assert_eq!(<Test as Config>::VoterList::count(), pre_insert_voter_count);
assert_eq!(
<Test as Config>::VoterList::iter().collect::<Vec<_>>(),
vec![11, 21, 31, 101]
);
// when account 101 renominates
assert_ok!(Staking::nominate(Origin::signed(100), vec![41]));
// then counts don't change
Kian Paimani
committed
4867
4868
4869
4870
4871
4872
4873
4874
4875
4876
4877
4878
4879
4880
4881
4882
4883
4884
4885
4886
4887
4888
4889
4890
assert_eq!(<Test as Config>::VoterList::count(), pre_insert_voter_count);
// and the list is the same
assert_eq!(
<Test as Config>::VoterList::iter().collect::<Vec<_>>(),
vec![11, 21, 31, 101]
);
});
}
#[test]
fn re_validate_does_not_change_counters_or_list() {
ExtBuilder::default().nominate(false).build_and_execute(|| {
// given
let pre_insert_voter_count =
(Nominators::<Test>::count() + Validators::<Test>::count()) as u32;
assert_eq!(<Test as Config>::VoterList::count(), pre_insert_voter_count);
assert_eq!(<Test as Config>::VoterList::iter().collect::<Vec<_>>(), vec![11, 21, 31]);
// when account 11 re-validates
assert_ok!(Staking::validate(Origin::signed(10), Default::default()));
// then counts don't change
assert_eq!(<Test as Config>::VoterList::count(), pre_insert_voter_count);
// and the list is the same
Kian Paimani
committed
assert_eq!(<Test as Config>::VoterList::iter().collect::<Vec<_>>(), vec![11, 21, 31]);
});
}
}
4896
4897
4898
4899
4900
4901
4902
4903
4904
4905
4906
4907
4908
4909
4910
4911
4912
4913
4914
4915
4916
4917
4918
4919
4920
4921
4922
4923
4924
4925
4926
4927
4928
4929
4930
#[test]
fn force_apply_min_commission_works() {
let prefs = |c| ValidatorPrefs { commission: Perbill::from_percent(c), blocked: false };
let validators = || Validators::<Test>::iter().collect::<Vec<_>>();
ExtBuilder::default().build_and_execute(|| {
assert_ok!(Staking::validate(Origin::signed(30), prefs(10)));
assert_ok!(Staking::validate(Origin::signed(20), prefs(5)));
// Given
assert_eq!(validators(), vec![(31, prefs(10)), (21, prefs(5)), (11, prefs(0))]);
MinCommission::<Test>::set(Perbill::from_percent(5));
// When applying to a commission greater than min
assert_ok!(Staking::force_apply_min_commission(Origin::signed(1), 31));
// Then the commission is not changed
assert_eq!(validators(), vec![(31, prefs(10)), (21, prefs(5)), (11, prefs(0))]);
// When applying to a commission that is equal to min
assert_ok!(Staking::force_apply_min_commission(Origin::signed(1), 21));
// Then the commission is not changed
assert_eq!(validators(), vec![(31, prefs(10)), (21, prefs(5)), (11, prefs(0))]);
// When applying to a commission that is less than the min
assert_ok!(Staking::force_apply_min_commission(Origin::signed(1), 11));
// Then the commission is bumped to the min
assert_eq!(validators(), vec![(31, prefs(10)), (21, prefs(5)), (11, prefs(5))]);
// When applying commission to a validator that doesn't exist then storage is not altered
assert_noop!(
Staking::force_apply_min_commission(Origin::signed(1), 420),
Error::<Test>::NotStash
);
});
}
fn proportional_ledger_slash_works() {
4934
4935
4936
4937
4938
4939
4940
4941
4942
4943
4944
4945
4946
4947
4948
4949
4950
4951
4952
4953
4954
4955
4956
4957
4958
4959
4960
4961
4962
4963
4964
4965
4966
4967
4968
4969
4970
4971
4972
4973
4974
4975
4976
4977
4978
4979
4980
4981
4982
4983
4984
4985
4986
4987
4988
4989
4990
4991
4992
4993
4994
4995
4996
4997
4998
4999
5000
let c = |era, value| UnlockChunk::<Balance> { era, value };
// Given
let mut ledger = StakingLedger::<Test> {
stash: 123,
total: 10,
active: 10,
unlocking: bounded_vec![],
claimed_rewards: vec![],
};
assert_eq!(BondingDuration::get(), 3);
// When we slash a ledger with no unlocking chunks
assert_eq!(ledger.slash(5, 1, 0), 5);
// Then
assert_eq!(ledger.total, 5);
assert_eq!(ledger.active, 5);
assert_eq!(LedgerSlashPerEra::get().0, 5);
assert_eq!(LedgerSlashPerEra::get().1, Default::default());
// When we slash a ledger with no unlocking chunks and the slash amount is greater then the
// total
assert_eq!(ledger.slash(11, 1, 0), 5);
// Then
assert_eq!(ledger.total, 0);
assert_eq!(ledger.active, 0);
assert_eq!(LedgerSlashPerEra::get().0, 0);
assert_eq!(LedgerSlashPerEra::get().1, Default::default());
// Given
ledger.unlocking = bounded_vec![c(4, 10), c(5, 10)];
ledger.total = 2 * 10;
ledger.active = 0;
// When all the chunks overlap with the slash eras
assert_eq!(ledger.slash(20, 0, 0), 20);
// Then
assert_eq!(ledger.unlocking, vec![]);
assert_eq!(ledger.total, 0);
assert_eq!(LedgerSlashPerEra::get().0, 0);
assert_eq!(LedgerSlashPerEra::get().1, BTreeMap::from([(4, 0), (5, 0)]));
// Given
ledger.unlocking = bounded_vec![c(4, 100), c(5, 100), c(6, 100), c(7, 100)];
ledger.total = 4 * 100;
ledger.active = 0;
// When the first 2 chunks don't overlap with the affected range of unlock eras.
assert_eq!(ledger.slash(140, 0, 2), 140);
// Then
assert_eq!(ledger.unlocking, vec![c(4, 100), c(5, 100), c(6, 30), c(7, 30)]);
assert_eq!(ledger.total, 4 * 100 - 140);
assert_eq!(LedgerSlashPerEra::get().0, 0);
assert_eq!(LedgerSlashPerEra::get().1, BTreeMap::from([(6, 30), (7, 30)]));
// Given
ledger.unlocking = bounded_vec![c(4, 40), c(5, 100), c(6, 10), c(7, 250)];
ledger.active = 500;
// 900
ledger.total = 40 + 10 + 100 + 250 + 500;
// When we have a partial slash that touches all chunks
assert_eq!(ledger.slash(900 / 2, 0, 0), 450);
// Then
assert_eq!(ledger.active, 500 / 2);
assert_eq!(ledger.unlocking, vec![c(4, 40 / 2), c(5, 100 / 2), c(6, 10 / 2), c(7, 250 / 2)]);
assert_eq!(ledger.total, 900 / 2);
assert_eq!(LedgerSlashPerEra::get().0, 500 / 2);
assert_eq!(
LedgerSlashPerEra::get().1,