Newer
Older
// Check that amount in staked account is NOT increased.
assert_eq!(Balances::free_balance(11), recorded_stash_balance);
fn validator_payment_prefs_work() {
// Test that validator preferences are correctly honored
// Note: unstake threshold is being directly tested in slashing tests.
// This test will focus on validator payment.
ExtBuilder::default().build_and_execute(|| {
<Validators<Test>>::insert(&11, ValidatorPrefs {
.. Default::default()
// Reward controller so staked ratio doesn't change.
<Payee<Test>>::insert(&11, RewardDestination::Controller);
<Payee<Test>>::insert(&101, RewardDestination::Controller);
mock::start_active_era(1);
mock::make_all_reward_payment(0);
let balance_era_1_10 = Balances::total_balance(&10);
let balance_era_1_100 = Balances::total_balance(&100);
// Compute total payout now for whole duration as other parameter won't change
let total_payout_1 = current_total_payout_for_duration(reward_time_per_era());
let exposure_1 = Staking::eras_stakers(Staking::active_era().unwrap().index, 11);
<Pallet<Test>>::reward_by_ids(vec![(11, 1)]);
mock::start_active_era(2);
let taken_cut = commission * total_payout_1;
let shared_cut = total_payout_1 - taken_cut;
let reward_of_10 = shared_cut * exposure_1.own / exposure_1.total + taken_cut;
let reward_of_100 = shared_cut * exposure_1.others[0].value / exposure_1.total;
assert_eq_error_rate!(Balances::total_balance(&10), balance_era_1_10 + reward_of_10, 2);
assert_eq_error_rate!(Balances::total_balance(&100), balance_era_1_100 + reward_of_100, 2);
#[test]
fn bond_extra_works() {
// Tests that extra `free_balance` in the stash can be added to stake
// NOTE: this tests only verifies `StakingLedger` for correct updates
// See `bond_extra_and_withdraw_unbonded_works` for more details and updates on `Exposure`.
ExtBuilder::default().build_and_execute(|| {
// Check that account 10 is a validator
assert!(<Validators<Test>>::contains_key(11));
// Check that account 10 is bonded to account 11
assert_eq!(Staking::bonded(&11), Some(10));
// Check how much is at stake
assert_eq!(Staking::ledger(&10), Some(StakingLedger {
stash: 11,
total: 1000,
active: 1000,
unlocking: vec![],
// Give account 11 some large free balance greater than total
let _ = Balances::make_free_balance_be(&11, 1000000);
// Call the bond_extra function from controller, add only 100
assert_ok!(Staking::bond_extra(Origin::signed(11), 100));
// There should be 100 more `total` and `active` in the ledger
assert_eq!(Staking::ledger(&10), Some(StakingLedger {
stash: 11,
total: 1000 + 100,
active: 1000 + 100,
unlocking: vec![],
// Call the bond_extra function with a large number, should handle it
assert_ok!(Staking::bond_extra(Origin::signed(11), Balance::max_value()));
// The full amount of the funds should now be in the total and active
assert_eq!(Staking::ledger(&10), Some(StakingLedger {
stash: 11,
total: 1000000,
active: 1000000,
unlocking: vec![],
fn bond_extra_and_withdraw_unbonded_works() {
// * Should test
// * Given an account being bonded [and chosen as a validator](not mandatory)
// * It can add extra funds to the bonded account.
// * it can unbond a portion of its funds from the stash account.
// * Once the unbonding period is done, it can actually take the funds out of the stash.
ExtBuilder::default().nominate(false).build_and_execute(|| {
// Set payee to controller. avoids confusion
assert_ok!(Staking::set_payee(Origin::signed(10), RewardDestination::Controller));
// Give account 11 some large free balance greater than total
let _ = Balances::make_free_balance_be(&11, 1000000);
// check the balance of a validator accounts.
assert_eq!(Balances::total_balance(&10), 1);
// confirm that 10 is a normal validator and gets paid at the end of the era.
mock::start_active_era(1);
assert_eq!(Staking::ledger(&10), Some(StakingLedger {
stash: 11,
total: 1000,
active: 1000,
unlocking: vec![],
assert_eq!(
Staking::eras_stakers(Staking::active_era().unwrap().index, 11),
Exposure { total: 1000, own: 1000, others: vec![] }
);
// deposit the extra 100 units
Staking::bond_extra(Origin::signed(11), 100).unwrap();
assert_eq!(Staking::ledger(&10), Some(StakingLedger {
stash: 11,
total: 1000 + 100,
active: 1000 + 100,
unlocking: vec![],
// Exposure is a snapshot! only updated after the next era update.
assert_ne!(
Staking::eras_stakers(Staking::active_era().unwrap().index, 11),
Exposure { total: 1000 + 100, own: 1000 + 100, others: vec![] }
);
mock::start_active_era(2);
assert_eq!(Staking::ledger(&10), Some(StakingLedger {
stash: 11,
total: 1000 + 100,
active: 1000 + 100,
unlocking: vec![],
assert_eq!(
Staking::eras_stakers(Staking::active_era().unwrap().index, 11),
Exposure { total: 1000 + 100, own: 1000 + 100, others: vec![] }
);
// Unbond almost all of the funds in stash.
Staking::unbond(Origin::signed(10), 1000).unwrap();
assert_eq!(
Staking::ledger(&10),
Some(StakingLedger {
stash: 11,
total: 1000 + 100,
active: 100,
unlocking: vec![UnlockChunk{ value: 1000, era: 2 + 3}],
claimed_rewards: vec![]
}),
// Attempting to free the balances now will fail. 2 eras need to pass.
assert_ok!(Staking::withdraw_unbonded(Origin::signed(10), 0));
assert_eq!(
Staking::ledger(&10),
Some(StakingLedger {
stash: 11,
total: 1000 + 100,
active: 100,
unlocking: vec![UnlockChunk{ value: 1000, era: 2 + 3}],
claimed_rewards: vec![]
}),
);
mock::start_active_era(3);
assert_ok!(Staking::withdraw_unbonded(Origin::signed(10), 0));
assert_eq!(
Staking::ledger(&10),
Some(StakingLedger {
stash: 11,
total: 1000 + 100,
active: 100,
unlocking: vec![UnlockChunk{ value: 1000, era: 2 + 3}],
claimed_rewards: vec![]
}),
);
mock::start_active_era(5);
assert_ok!(Staking::withdraw_unbonded(Origin::signed(10), 0));
// Now the value is free and the staking ledger is updated.
assert_eq!(
Staking::ledger(&10),
Some(StakingLedger {
stash: 11,
total: 100,
active: 100,
unlocking: vec![],
claimed_rewards: vec![]
}),
);
#[test]
fn too_many_unbond_calls_should_not_work() {
ExtBuilder::default().build_and_execute(|| {
// locked at era 0 until 3
for _ in 0..MAX_UNLOCKING_CHUNKS-1 {
assert_ok!(Staking::unbond(Origin::signed(10), 1));
}
mock::start_active_era(1);
assert_ok!(Staking::unbond(Origin::signed(10), 1));
// can't do more.
assert_noop!(Staking::unbond(Origin::signed(10), 1), Error::<Test>::NoMoreChunks);
mock::start_active_era(3);
assert_noop!(Staking::unbond(Origin::signed(10), 1), Error::<Test>::NoMoreChunks);
assert_ok!(Staking::withdraw_unbonded(Origin::signed(10), 0));
// Can add again.
assert_ok!(Staking::unbond(Origin::signed(10), 1));
assert_eq!(Staking::ledger(&10).unwrap().unlocking.len(), 2);
})
}
#[test]
fn rebond_works() {
// * Should test
// * Given an account being bonded [and chosen as a validator](not mandatory)
// * it can unbond a portion of its funds from the stash account.
// * it can re-bond a portion of the funds scheduled to unlock.
ExtBuilder::default()
.nominate(false)
.build()
.execute_with(|| {
// Set payee to controller. avoids confusion
assert_ok!(Staking::set_payee(
Origin::signed(10),
RewardDestination::Controller
));
// Give account 11 some large free balance greater than total
let _ = Balances::make_free_balance_be(&11, 1000000);
// confirm that 10 is a normal validator and gets paid at the end of the era.
mock::start_active_era(1);
// Initial state of 10
assert_eq!(
Staking::ledger(&10),
Some(StakingLedger {
stash: 11,
total: 1000,
active: 1000,
unlocking: vec![],
mock::start_active_era(2);
// Try to rebond some funds. We get an error since no fund is unbonded.
assert_noop!(
Staking::rebond(Origin::signed(10), 500),
Error::<Test>::NoUnlockChunk,
);
// Unbond almost all of the funds in stash.
Staking::unbond(Origin::signed(10), 900).unwrap();
assert_eq!(
Staking::ledger(&10),
Some(StakingLedger {
stash: 11,
total: 1000,
active: 100,
unlocking: vec![UnlockChunk {
value: 900,
})
);
// Re-bond all the funds unbonded.
Staking::rebond(Origin::signed(10), 900).unwrap();
assert_eq!(
Staking::ledger(&10),
Some(StakingLedger {
stash: 11,
total: 1000,
active: 1000,
unlocking: vec![],
})
);
// Unbond almost all of the funds in stash.
Staking::unbond(Origin::signed(10), 900).unwrap();
assert_eq!(
Staking::ledger(&10),
Some(StakingLedger {
stash: 11,
total: 1000,
active: 100,
unlocking: vec![UnlockChunk { value: 900, era: 5 }],
})
);
// Re-bond part of the funds unbonded.
Staking::rebond(Origin::signed(10), 500).unwrap();
assert_eq!(
Staking::ledger(&10),
Some(StakingLedger {
stash: 11,
total: 1000,
active: 600,
unlocking: vec![UnlockChunk { value: 400, era: 5 }],
})
);
// Re-bond the remainder of the funds unbonded.
Staking::rebond(Origin::signed(10), 500).unwrap();
assert_eq!(
Staking::ledger(&10),
Some(StakingLedger {
stash: 11,
total: 1000,
active: 1000,
})
);
// Unbond parts of the funds in stash.
Staking::unbond(Origin::signed(10), 300).unwrap();
Staking::unbond(Origin::signed(10), 300).unwrap();
Staking::unbond(Origin::signed(10), 300).unwrap();
assert_eq!(
Staking::ledger(&10),
Some(StakingLedger {
stash: 11,
total: 1000,
active: 100,
unlocking: vec![
UnlockChunk { value: 300, era: 5 },
UnlockChunk { value: 300, era: 5 },
UnlockChunk { value: 300, era: 5 },
})
);
// Re-bond part of the funds unbonded.
Staking::rebond(Origin::signed(10), 500).unwrap();
assert_eq!(
Staking::ledger(&10),
Some(StakingLedger {
stash: 11,
total: 1000,
active: 600,
unlocking: vec![
UnlockChunk { value: 300, era: 5 },
UnlockChunk { value: 100, era: 5 },
#[test]
fn rebond_is_fifo() {
// Rebond should proceed by reversing the most recent bond operations.
ExtBuilder::default()
.nominate(false)
.build()
.execute_with(|| {
// Set payee to controller. avoids confusion
assert_ok!(Staking::set_payee(
Origin::signed(10),
RewardDestination::Controller
));
// Give account 11 some large free balance greater than total
let _ = Balances::make_free_balance_be(&11, 1000000);
// confirm that 10 is a normal validator and gets paid at the end of the era.
mock::start_active_era(1);
// Initial state of 10
assert_eq!(
Staking::ledger(&10),
Some(StakingLedger {
stash: 11,
total: 1000,
active: 1000,
unlocking: vec![],
mock::start_active_era(2);
// Unbond some of the funds in stash.
Staking::unbond(Origin::signed(10), 400).unwrap();
assert_eq!(
Staking::ledger(&10),
Some(StakingLedger {
stash: 11,
total: 1000,
active: 600,
unlocking: vec![
UnlockChunk { value: 400, era: 2 + 3 },
mock::start_active_era(3);
// Unbond more of the funds in stash.
Staking::unbond(Origin::signed(10), 300).unwrap();
assert_eq!(
Staking::ledger(&10),
Some(StakingLedger {
stash: 11,
total: 1000,
active: 300,
unlocking: vec![
UnlockChunk { value: 400, era: 2 + 3 },
UnlockChunk { value: 300, era: 3 + 3 },
mock::start_active_era(4);
// Unbond yet more of the funds in stash.
Staking::unbond(Origin::signed(10), 200).unwrap();
assert_eq!(
Staking::ledger(&10),
Some(StakingLedger {
stash: 11,
total: 1000,
active: 100,
unlocking: vec![
UnlockChunk { value: 400, era: 2 + 3 },
UnlockChunk { value: 300, era: 3 + 3 },
UnlockChunk { value: 200, era: 4 + 3 },
})
);
// Re-bond half of the unbonding funds.
Staking::rebond(Origin::signed(10), 400).unwrap();
assert_eq!(
Staking::ledger(&10),
Some(StakingLedger {
stash: 11,
total: 1000,
active: 500,
unlocking: vec![
UnlockChunk { value: 400, era: 2 + 3 },
UnlockChunk { value: 100, era: 3 + 3 },
})
);
})
}
ExtBuilder::default().nominate(false).fair(false).build_and_execute(|| {
// Confirm validator count is 2
assert_eq!(Staking::validator_count(), 2);
// Confirm account 10 and 20 are validators
assert!(<Validators<Test>>::contains_key(&11) && <Validators<Test>>::contains_key(&21));
assert_eq!(Staking::eras_stakers(Staking::active_era().unwrap().index, 11).total, 1000);
assert_eq!(Staking::eras_stakers(Staking::active_era().unwrap().index, 21).total, 2000);
// Give the man some money.
let _ = Balances::make_free_balance_be(&10, 1000);
let _ = Balances::make_free_balance_be(&20, 1000);
// Bypass logic and change current exposure
ErasStakers::<Test>::insert(0, 21, Exposure { total: 69, own: 69, others: vec![] });
// Now lets lower account 20 stake
assert_eq!(Staking::eras_stakers(Staking::active_era().unwrap().index, 21).total, 69);
<Ledger<Test>>::insert(&20, StakingLedger { stash: 21, total: 69, active: 69, unlocking: vec![], claimed_rewards: vec![] });
// Compute total payout now for whole duration as other parameter won't change
let total_payout_0 = current_total_payout_for_duration(reward_time_per_era());
<Pallet<Test>>::reward_by_ids(vec![(11, 1)]);
<Pallet<Test>>::reward_by_ids(vec![(21, 1)]);
// New era --> rewards are paid --> stakes are changed
mock::start_active_era(1);
assert_eq!(Staking::eras_stakers(Staking::active_era().unwrap().index, 11).total, 1000);
assert_eq!(Staking::eras_stakers(Staking::active_era().unwrap().index, 21).total, 69);
let _11_balance = Balances::free_balance(&11);
assert_eq!(_11_balance, 1000 + total_payout_0 / 2);
// Trigger another new era as the info are frozen before the era start.
mock::start_active_era(2);
// -- new infos
assert_eq!(Staking::eras_stakers(Staking::active_era().unwrap().index, 11).total, 1000 + total_payout_0 / 2);
assert_eq!(Staking::eras_stakers(Staking::active_era().unwrap().index, 21).total, 69 + total_payout_0 / 2);
#[test]
fn on_free_balance_zero_stash_removes_validator() {
// Tests that validator storage items are cleaned up when stash is empty
// Tests that storage items are untouched when controller is empty
ExtBuilder::default().existential_deposit(10).build_and_execute(|| {
// Check the balance of the validator account
assert_eq!(Balances::free_balance(10), 256);
// Check the balance of the stash account
assert_eq!(Balances::free_balance(11), 256000);
// Check these two accounts are bonded
assert_eq!(Staking::bonded(&11), Some(10));
// Set some storage items which we expect to be cleaned up
// Set payee information
assert_ok!(Staking::set_payee(Origin::signed(10), RewardDestination::Stash));
// Check storage items that should be cleaned up
assert!(<Ledger<Test>>::contains_key(&10));
assert!(<Bonded<Test>>::contains_key(&11));
assert!(<Validators<Test>>::contains_key(&11));
assert!(<Payee<Test>>::contains_key(&11));
// Reduce free_balance of controller to 0
let _ = Balances::slash(&10, Balance::max_value());
// Check the balance of the stash account has not been touched
assert_eq!(Balances::free_balance(11), 256000);
// Check these two accounts are still bonded
assert_eq!(Staking::bonded(&11), Some(10));
// Check storage items have not changed
assert!(<Ledger<Test>>::contains_key(&10));
assert!(<Bonded<Test>>::contains_key(&11));
assert!(<Validators<Test>>::contains_key(&11));
assert!(<Payee<Test>>::contains_key(&11));
// Reduce free_balance of stash to 0
let _ = Balances::slash(&11, Balance::max_value());
assert_eq!(Balances::total_balance(&11), 10);
assert_ok!(Staking::reap_stash(Origin::none(), 11, 0));
// Check storage items do not exist
assert!(!<Ledger<Test>>::contains_key(&10));
assert!(!<Bonded<Test>>::contains_key(&11));
assert!(!<Validators<Test>>::contains_key(&11));
assert!(!<Nominators<Test>>::contains_key(&11));
assert!(!<Payee<Test>>::contains_key(&11));
});
}
#[test]
fn on_free_balance_zero_stash_removes_nominator() {
// Tests that nominator storage items are cleaned up when stash is empty
// Tests that storage items are untouched when controller is empty
ExtBuilder::default().existential_deposit(10).build_and_execute(|| {
// Make 10 a nominator
assert_ok!(Staking::nominate(Origin::signed(10), vec![20]));
// Check that account 10 is a nominator
assert!(<Nominators<Test>>::contains_key(11));
// Check the balance of the nominator account
assert_eq!(Balances::free_balance(10), 256);
// Check the balance of the stash account
assert_eq!(Balances::free_balance(11), 256000);
// Set payee information
assert_ok!(Staking::set_payee(Origin::signed(10), RewardDestination::Stash));
// Check storage items that should be cleaned up
assert!(<Ledger<Test>>::contains_key(&10));
assert!(<Bonded<Test>>::contains_key(&11));
assert!(<Nominators<Test>>::contains_key(&11));
assert!(<Payee<Test>>::contains_key(&11));
// Reduce free_balance of controller to 0
let _ = Balances::slash(&10, Balance::max_value());
// Check total balance of account 10
assert_eq!(Balances::total_balance(&10), 0);
// Check the balance of the stash account has not been touched
assert_eq!(Balances::free_balance(11), 256000);
// Check these two accounts are still bonded
assert_eq!(Staking::bonded(&11), Some(10));
// Check storage items have not changed
assert!(<Ledger<Test>>::contains_key(&10));
assert!(<Bonded<Test>>::contains_key(&11));
assert!(<Nominators<Test>>::contains_key(&11));
assert!(<Payee<Test>>::contains_key(&11));
// Reduce free_balance of stash to 0
let _ = Balances::slash(&11, Balance::max_value());
assert_eq!(Balances::total_balance(&11), 10);
assert_ok!(Staking::reap_stash(Origin::none(), 11, 0));
// Check storage items do not exist
assert!(!<Ledger<Test>>::contains_key(&10));
assert!(!<Bonded<Test>>::contains_key(&11));
assert!(!<Validators<Test>>::contains_key(&11));
assert!(!<Nominators<Test>>::contains_key(&11));
assert!(!<Payee<Test>>::contains_key(&11));
}
#[test]
fn switching_roles() {
// Test that it should be possible to switch between roles (nominator, validator, idle) with minimal overhead.
ExtBuilder::default().nominate(false).build_and_execute(|| {
// Reset reward destination
for i in &[10, 20] { assert_ok!(Staking::set_payee(Origin::signed(*i), RewardDestination::Controller)); }
assert_eq_uvec!(validator_controllers(), vec![20, 10]);
// put some money in account that we'll use.
for i in 1..7 { let _ = Balances::deposit_creating(&i, 5000); }
assert_ok!(Staking::bond(Origin::signed(1), 2, 2000, RewardDestination::Controller));
assert_ok!(Staking::nominate(Origin::signed(2), vec![11, 5]));
assert_ok!(Staking::bond(Origin::signed(3), 4, 500, RewardDestination::Controller));
assert_ok!(Staking::nominate(Origin::signed(4), vec![21, 1]));
// add a new validator candidate
assert_ok!(Staking::bond(Origin::signed(5), 6, 1000, RewardDestination::Controller));
assert_ok!(Staking::validate(Origin::signed(6), ValidatorPrefs::default()));
mock::start_active_era(1);
// with current nominators 10 and 5 have the most stake
assert_eq_uvec!(validator_controllers(), vec![6, 10]);
// 2 decides to be a validator. Consequences:
assert_ok!(Staking::validate(Origin::signed(2), ValidatorPrefs::default()));
// new stakes:
// 10: 1000 self vote
// 6 : 1000 self vote
// Winners: 20 and 2
mock::start_active_era(2);
assert_eq_uvec!(validator_controllers(), vec![2, 20]);
});
}
#[test]
fn wrong_vote_is_null() {
ExtBuilder::default().nominate(false).validator_pool(true).build_and_execute(|| {
assert_eq_uvec!(validator_controllers(), vec![40, 30]);
// put some money in account that we'll use.
for i in 1..3 { let _ = Balances::deposit_creating(&i, 5000); }
// add 1 nominators
assert_ok!(Staking::bond(Origin::signed(1), 2, 2000, RewardDestination::default()));
assert_ok!(Staking::nominate(Origin::signed(2), vec![
1, 2, 15, 1000, 25 // crap votes. No effect.
]));
mock::start_active_era(1);
assert_eq_uvec!(validator_controllers(), vec![20, 10]);
});
}
#[test]
fn bond_with_no_staked_value() {
// Behavior when someone bonds with no staked value.
// Particularly when she votes and the candidate is elected.
ExtBuilder::default()
.validator_count(3)
.existential_deposit(5)
.nominate(false)
.minimum_validator_count(1)
.build()
.execute_with(|| {
// Can't bond with 1
assert_noop!(
Staking::bond(Origin::signed(1), 2, 1, RewardDestination::Controller),
Error::<Test>::InsufficientValue,
);
// bonded with absolute minimum value possible.
assert_ok!(Staking::bond(Origin::signed(1), 2, 5, RewardDestination::Controller));
assert_eq!(Balances::locks(&1)[0].amount, 5);
// unbonding even 1 will cause all to be unbonded.
assert_ok!(Staking::unbond(Origin::signed(2), 1));
assert_eq!(
Staking::ledger(2),
Some(StakingLedger {
stash: 1,
active: 0,
total: 5,
mock::start_active_era(1);
mock::start_active_era(2);
assert_ok!(Staking::withdraw_unbonded(Origin::signed(2), 0));
assert!(Staking::ledger(2).is_some());
assert_eq!(Balances::locks(&1)[0].amount, 5);
mock::start_active_era(3);
// poof. Account 1 is removed from the staking system.
assert_ok!(Staking::withdraw_unbonded(Origin::signed(2), 0));
assert!(Staking::ledger(2).is_none());
assert_eq!(Balances::locks(&1).len(), 0);
});
ExtBuilder::default()
.validator_count(3)
.nominate(false)
.minimum_validator_count(1)
.build()
.execute_with(|| {
// setup
assert_ok!(Staking::chill(Origin::signed(30)));
assert_ok!(Staking::set_payee(Origin::signed(10), RewardDestination::Controller));
let init_balance_2 = Balances::free_balance(&2);
let init_balance_10 = Balances::free_balance(&10);
// Stingy validator.
assert_ok!(Staking::bond(Origin::signed(1), 2, 1, RewardDestination::Controller));
assert_ok!(Staking::validate(Origin::signed(2), ValidatorPrefs::default()));
// 1 era worth of reward. BUT, we set the timestamp after on_initialize, so outdated by
// one block.
let total_payout_0 = current_total_payout_for_duration(reward_time_per_era());
reward_all_elected();
mock::start_active_era(1);
// 2 is elected.
assert_eq_uvec!(validator_controllers(), vec![20, 10, 2]);
assert_eq!(Staking::eras_stakers(active_era(), 2).total, 0);
// Old ones are rewarded.
assert_eq_error_rate!(Balances::free_balance(10), init_balance_10 + total_payout_0 / 3, 1);
// no rewards paid to 2. This was initial election.
assert_eq!(Balances::free_balance(2), init_balance_2);
// reward era 2
let total_payout_1 = current_total_payout_for_duration(reward_time_per_era());
reward_all_elected();
mock::start_active_era(2);
assert_eq_uvec!(validator_controllers(), vec![20, 10, 2]);
assert_eq!(Staking::eras_stakers(active_era(), 2).total, 0);
// 2 is now rewarded.
assert_eq_error_rate!(Balances::free_balance(2), init_balance_2 + total_payout_1 / 3, 1);
assert_eq_error_rate!(
Balances::free_balance(&10),
init_balance_10 + total_payout_0 / 3 + total_payout_1 / 3,
fn bond_with_duplicate_vote_should_be_ignored_by_election_provider() {
ExtBuilder::default()
.validator_count(2)
.nominate(false)
.minimum_validator_count(1)
.build()
.execute_with(|| {
// disable the nominator
assert_ok!(Staking::chill(Origin::signed(100)));
// make stakes equal.
assert_ok!(Staking::bond_extra(Origin::signed(31), 999));
// ensure all have equal stake.
assert_eq!(
<Validators<Test>>::iter()
.map(|(v, _)| (v, Staking::ledger(v - 1).unwrap().total))
.collect::<Vec<_>>(),
vec![(31, 1000), (21, 1000), (11, 1000)],
);
// no nominators shall exist.
assert!(<Nominators<Test>>::iter().map(|(n, _)| n).collect::<Vec<_>>().is_empty());
// give the man some money.
let initial_balance = 1000;
for i in [1, 2, 3, 4].iter() {
let _ = Balances::make_free_balance_be(i, initial_balance);
}
assert_ok!(Staking::bond(Origin::signed(1), 2, 1000, RewardDestination::Controller));
assert_ok!(Staking::nominate(Origin::signed(2), vec![11, 11, 11, 21, 31]));
assert_ok!(Staking::bond(Origin::signed(3), 4, 1000, RewardDestination::Controller));
assert_ok!(Staking::nominate(Origin::signed(4), vec![21, 31]));
// winners should be 21 and 31. Otherwise this election is taking duplicates into
// account.
let supports = <Test as Config>::ElectionProvider::elect().unwrap().0;
assert_eq!(
supports,
vec![
(21, Support { total: 1800, voters: vec![(21, 1000), (3, 400), (1, 400)] }),
(31, Support { total: 2200, voters: vec![(31, 1000), (3, 600), (1, 600)] })
],
);
});
}
#[test]
fn bond_with_duplicate_vote_should_be_ignored_by_election_provider_elected() {
// same as above but ensures that even when the duple is being elected, everything is sane.
ExtBuilder::default()
.validator_count(2)
.nominate(false)
.minimum_validator_count(1)
.build()
.execute_with(|| {
// disable the nominator
assert_ok!(Staking::chill(Origin::signed(100)));
// 31/30 will have less stake
assert_ok!(Staking::bond_extra(Origin::signed(31), 99));
// ensure all have equal stake.
assert_eq!(
<Validators<Test>>::iter()
.map(|(v, _)| (v, Staking::ledger(v - 1).unwrap().total))
.collect::<Vec<_>>(),
vec![(31, 100), (21, 1000), (11, 1000)],
);
// no nominators shall exist.
assert!(<Nominators<Test>>::iter().map(|(n, _)| n).collect::<Vec<_>>().is_empty());
// give the man some money.
let initial_balance = 1000;
for i in [1, 2, 3, 4,].iter() {
let _ = Balances::make_free_balance_be(i, initial_balance);
}
assert_ok!(Staking::bond(Origin::signed(1), 2, 1000, RewardDestination::Controller));
assert_ok!(Staking::nominate(Origin::signed(2), vec![11, 11, 11, 21, 31]));
assert_ok!(Staking::bond(Origin::signed(3), 4, 1000, RewardDestination::Controller));
assert_ok!(Staking::nominate(Origin::signed(4), vec![21, 31]));
// winners should be 21 and 11.
let supports = <Test as Config>::ElectionProvider::elect().unwrap().0;
assert_eq!(
supports,
vec![
(11, Support { total: 1500, voters: vec![(11, 1000), (1, 500)] }),
(21, Support { total: 2500, voters: vec![(21, 1000), (3, 1000), (1, 500)] })
],
);
});
}
fn new_era_elects_correct_number_of_validators() {
ExtBuilder::default()
.nominate(true)
.validator_pool(true)
.build()
.execute_with(|| {
assert_eq!(Staking::validator_count(), 1);
assert_eq!(validator_controllers().len(), 1);
Session::on_initialize(System::block_number());
assert_eq!(validator_controllers().len(), 1);
})
Kian Peymani
committed
#[test]
fn phragmen_should_not_overflow() {
ExtBuilder::default().nominate(false).build_and_execute(|| {
// This is the maximum value that we can have as the outcome of CurrencyToVote.
type Votes = u64;
Kian Peymani
committed
let _ = Staking::chill(Origin::signed(10));
let _ = Staking::chill(Origin::signed(20));
bond_validator(3, 2, Votes::max_value() as Balance);
bond_validator(5, 4, Votes::max_value() as Balance);
Kian Peymani
committed
bond_nominator(7, 6, Votes::max_value() as Balance, vec![3, 5]);
bond_nominator(9, 8, Votes::max_value() as Balance, vec![3, 5]);
Kian Peymani
committed
mock::start_active_era(1);
Kian Peymani
committed
assert_eq_uvec!(validator_controllers(), vec![4, 2]);
// We can safely convert back to values within [u64, u128].
assert!(Staking::eras_stakers(active_era(), 3).total > Votes::max_value() as Balance);
assert!(Staking::eras_stakers(active_era(), 5).total > Votes::max_value() as Balance);
Kian Peymani
committed
})
}
#[test]
fn reward_validator_slashing_validator_does_not_overflow() {
ExtBuilder::default().build_and_execute(|| {
let stake = u64::max_value() as Balance * 2;
let reward_slash = u64::max_value() as Balance * 2;
// Assert multiplication overflows in balance arithmetic.
assert!(stake.checked_mul(reward_slash).is_none());
// Set staker
let _ = Balances::make_free_balance_be(&11, stake);
let exposure = Exposure::<AccountId, Balance> { total: stake, own: stake, others: vec![] };
let reward = EraRewardPoints::<AccountId> {
total: 1,
individual: vec![(11, 1)].into_iter().collect(),
};
// Check reward
ErasRewardPoints::<Test>::insert(0, reward);
ErasStakers::<Test>::insert(0, 11, &exposure);
ErasStakersClipped::<Test>::insert(0, 11, exposure);
ErasValidatorReward::<Test>::insert(0, stake);
assert_ok!(Staking::payout_stakers(Origin::signed(1337), 11, 0));
assert_eq!(Balances::total_balance(&11), stake * 2);
// Set staker
let _ = Balances::make_free_balance_be(&11, stake);
let _ = Balances::make_free_balance_be(&2, stake);
// only slashes out of bonded stake are applied. without this line,
// it is 0.
Staking::bond(Origin::signed(2), 20000, stake - 1, RewardDestination::default()).unwrap();
// Override exposure of 11
ErasStakers::<Test>::insert(0, 11, Exposure {
total: stake,
own: 1,
others: vec![ IndividualExposure { who: 2, value: stake - 1 }]
});