Newer
Older
#[test]
fn cannot_transfer_staked_balance_2() {
// Tests that a stash account cannot transfer funds
// Same test as above but with 20, and more accurate.
// 21 has 2000 free balance but 1000 at stake
ExtBuilder::default().nominate(false).build_and_execute(|| {
// Confirm account 21 is stashed
assert_eq!(Staking::bonded(&21), Some(21));
// Confirm account 21 has some free balance
assert_eq!(Balances::free_balance(21), 2000);
// Confirm account 21 (via controller) is totally staked
assert_eq!(Staking::eras_stakers(active_era(), &21).total, 1000);
// Confirm account 21 can transfer at most 1000
Balances::transfer_allow_death(RuntimeOrigin::signed(21), 21, 1001),
Gavin Wood
committed
TokenError::Frozen,
assert_ok!(Balances::transfer_allow_death(RuntimeOrigin::signed(21), 21, 1000));
fn cannot_reserve_staked_balance() {
// Checks that a bonded account cannot reserve balance from free balance
ExtBuilder::default().build_and_execute(|| {
assert_eq!(Staking::bonded(&11), Some(11));
// Confirm account 11 has some free balance
assert_eq!(Balances::free_balance(11), 1000);
// Confirm account 11 (via controller 10) is totally staked
assert_eq!(Staking::eras_stakers(active_era(), &11).own, 1000);
// Confirm account 11 cannot reserve as a result
assert_noop!(Balances::reserve(&11, 1), BalancesError::<Test, _>::LiquidityRestrictions);
// Give account 11 extra free balance
let _ = Balances::make_free_balance_be(&11, 10000);
// Confirm account 11 can now reserve balance
assert_ok!(Balances::reserve(&11, 1));
#[test]
fn reward_destination_works() {
// Rewards go to the correct destination as determined in Payee
ExtBuilder::default().nominate(false).build_and_execute(|| {
// Check that account 11 is a validator
// Check the balance of the validator account
assert_eq!(Balances::free_balance(10), 1);
// Check the balance of the stash account
assert_eq!(Balances::free_balance(11), 1000);
Staking::ledger(11.into()).unwrap(),
StakingLedgerInspect {
stash: 11,
total: 1000,
active: 1000,
unlocking: Default::default(),
legacy_claimed_rewards: bounded_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)]);
mock::start_active_era(1);
// Check that RewardDestination is Staked
assert_eq!(Staking::payee(11.into()), Some(RewardDestination::Staked));
// Check that reward went to the stash account of validator
assert_eq!(Balances::free_balance(11), 1000 + total_payout_0);
// Check that amount at stake increased accordingly
Staking::ledger(11.into()).unwrap(),
StakingLedgerInspect {
stash: 11,
total: 1000 + total_payout_0,
active: 1000 + total_payout_0,
unlocking: Default::default(),
legacy_claimed_rewards: bounded_vec![],
// (era 0, page 0) is claimed
assert_eq!(Staking::claimed_rewards(0, &11), vec![0]);
// Change RewardDestination to Stash
<Payee<Test>>::insert(&11, RewardDestination::Stash);
// 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());
Pallet::<Test>::reward_by_ids(vec![(11, 1)]);
mock::start_active_era(2);
// Check that RewardDestination is Stash
assert_eq!(Staking::payee(11.into()), Some(RewardDestination::Stash));
// Check that reward went to the stash account
assert_eq!(Balances::free_balance(11), 1000 + total_payout_0 + total_payout_1);
// Record this value
let recorded_stash_balance = 1000 + total_payout_0 + total_payout_1;
// Check that amount at stake is NOT increased
Staking::ledger(11.into()).unwrap(),
StakingLedgerInspect {
stash: 11,
total: 1000 + total_payout_0,
active: 1000 + total_payout_0,
unlocking: Default::default(),
legacy_claimed_rewards: bounded_vec![],
// (era 1, page 0) is claimed
assert_eq!(Staking::claimed_rewards(1, &11), vec![0]);
// Change RewardDestination to Account
<Payee<Test>>::insert(&11, RewardDestination::Account(11));
assert_eq!(Balances::free_balance(11), 23150);
// Compute total payout now for whole duration as other parameter won't change
let total_payout_2 = current_total_payout_for_duration(reward_time_per_era());
Pallet::<Test>::reward_by_ids(vec![(11, 1)]);
mock::start_active_era(3);
// Check that RewardDestination is Account(11)
assert_eq!(Staking::payee(11.into()), Some(RewardDestination::Account(11)));
// Check that reward went to the controller account
assert_eq!(Balances::free_balance(11), recorded_stash_balance + total_payout_2);
// Check that amount at stake is NOT increased
Staking::ledger(11.into()).unwrap(),
StakingLedgerInspect {
stash: 11,
total: 1000 + total_payout_0,
active: 1000 + total_payout_0,
unlocking: Default::default(),
legacy_claimed_rewards: bounded_vec![],
// (era 2, page 0) is claimed
assert_eq!(Staking::claimed_rewards(2, &11), vec![0]);
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 { commission, ..Default::default() });
// Reward stash so staked ratio doesn't change.
<Payee<Test>>::insert(&11, RewardDestination::Stash);
<Payee<Test>>::insert(&101, RewardDestination::Stash);
mock::start_active_era(1);
let balance_era_1_11 = Balances::total_balance(&11);
let balance_era_1_101 = Balances::total_balance(&101);
// 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(active_era(), &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(&11), balance_era_1_11 + reward_of_10, 2);
assert_eq_error_rate!(Balances::total_balance(&101), balance_era_1_101 + 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(11));
Staking::ledger(11.into()).unwrap(),
StakingLedgerInspect {
stash: 11,
total: 1000,
active: 1000,
unlocking: Default::default(),
legacy_claimed_rewards: bounded_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(RuntimeOrigin::signed(11), 100));
// There should be 100 more `total` and `active` in the ledger
Staking::ledger(11.into()).unwrap(),
StakingLedgerInspect {
stash: 11,
total: 1000 + 100,
active: 1000 + 100,
unlocking: Default::default(),
legacy_claimed_rewards: bounded_vec![],
// Call the bond_extra function with a large number, should handle it
assert_ok!(Staking::bond_extra(RuntimeOrigin::signed(11), Balance::max_value()));
// The full amount of the funds should now be in the total and active
Staking::ledger(11.into()).unwrap(),
StakingLedgerInspect {
stash: 11,
total: 1000000,
active: 1000000,
unlocking: Default::default(),
legacy_claimed_rewards: bounded_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 stash.
assert_ok!(Staking::set_payee(RuntimeOrigin::signed(11), RewardDestination::Stash));
// 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(&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 11
Staking::ledger(11.into()).unwrap(),
StakingLedgerInspect {
stash: 11,
total: 1000,
active: 1000,
unlocking: Default::default(),
legacy_claimed_rewards: bounded_vec![],
Staking::eras_stakers(active_era(), &11),
Exposure { total: 1000, own: 1000, others: vec![] }
);
// deposit the extra 100 units
Staking::bond_extra(RuntimeOrigin::signed(11), 100).unwrap();
Staking::ledger(11.into()).unwrap(),
StakingLedgerInspect {
stash: 11,
total: 1000 + 100,
active: 1000 + 100,
unlocking: Default::default(),
legacy_claimed_rewards: bounded_vec![],
// Exposure is a snapshot! only updated after the next era update.
Staking::eras_stakers(active_era(), &11),
Exposure { total: 1000 + 100, own: 1000 + 100, others: vec![] }
);
mock::start_active_era(2);
Staking::ledger(11.into()).unwrap(),
StakingLedgerInspect {
stash: 11,
total: 1000 + 100,
active: 1000 + 100,
unlocking: Default::default(),
legacy_claimed_rewards: bounded_vec![],
Staking::eras_stakers(active_era(), &11),
Exposure { total: 1000 + 100, own: 1000 + 100, others: vec![] }
);
// Unbond almost all of the funds in stash.
Staking::unbond(RuntimeOrigin::signed(11), 1000).unwrap();
Staking::ledger(11.into()).unwrap(),
StakingLedgerInspect {
stash: 11,
total: 1000 + 100,
active: 100,
unlocking: bounded_vec![UnlockChunk { value: 1000, era: 2 + 3 }],
legacy_claimed_rewards: bounded_vec![],
// Attempting to free the balances now will fail. 2 eras need to pass.
assert_ok!(Staking::withdraw_unbonded(RuntimeOrigin::signed(11), 0));
Staking::ledger(11.into()).unwrap(),
StakingLedgerInspect {
stash: 11,
total: 1000 + 100,
active: 100,
unlocking: bounded_vec![UnlockChunk { value: 1000, era: 2 + 3 }],
legacy_claimed_rewards: bounded_vec![],
mock::start_active_era(3);
assert_ok!(Staking::withdraw_unbonded(RuntimeOrigin::signed(11), 0));
Staking::ledger(11.into()).unwrap(),
StakingLedgerInspect {
stash: 11,
total: 1000 + 100,
active: 100,
unlocking: bounded_vec![UnlockChunk { value: 1000, era: 2 + 3 }],
legacy_claimed_rewards: bounded_vec![],
mock::start_active_era(5);
assert_ok!(Staking::withdraw_unbonded(RuntimeOrigin::signed(11), 0));
// Now the value is free and the staking ledger is updated.
Staking::ledger(11.into()).unwrap(),
StakingLedgerInspect {
stash: 11,
total: 100,
active: 100,
unlocking: Default::default(),
legacy_claimed_rewards: bounded_vec![],
fn many_unbond_calls_should_work() {
ExtBuilder::default().build_and_execute(|| {
let mut current_era = 0;
// locked at era MaxUnlockingChunks - 1 until 3
Ankan
committed
let max_unlocking_chunks = <<Test as Config>::MaxUnlockingChunks as Get<u32>>::get();
for i in 0..max_unlocking_chunks - 1 {
// There is only 1 chunk per era, so we need to be in a new era to create a chunk.
current_era = i as u32;
mock::start_active_era(current_era);
assert_ok!(Staking::unbond(RuntimeOrigin::signed(11), 1));
current_era += 1;
mock::start_active_era(current_era);
// This chunk is locked at `current_era` through `current_era + 2` (because
// `BondingDuration` == 3).
assert_ok!(Staking::unbond(RuntimeOrigin::signed(11), 1));
Staking::ledger(11.into()).map(|l| l.unlocking.len()).unwrap(),
Ankan
committed
<<Test as Config>::MaxUnlockingChunks as Get<u32>>::get() as usize
// even though the number of unlocked chunks is the same as `MaxUnlockingChunks`,
// unbonding works as expected.
for i in current_era..(current_era + max_unlocking_chunks) - 1 {
// There is only 1 chunk per era, so we need to be in a new era to create a chunk.
current_era = i as u32;
mock::start_active_era(current_era);
assert_ok!(Staking::unbond(RuntimeOrigin::signed(11), 1));
}
// only slots within last `BondingDuration` are filled.
assert_eq!(
Staking::ledger(11.into()).map(|l| l.unlocking.len()).unwrap(),
<<Test as Config>::BondingDuration>::get() as usize
);
})
}
#[test]
fn auto_withdraw_may_not_unlock_all_chunks() {
ExtBuilder::default().build_and_execute(|| {
// set `MaxUnlockingChunks` to a low number to test case when the unbonding period
// is larger than the number of unlocking chunks available, which may result on a
// `Error::NoMoreChunks`, even when the auto-withdraw tries to release locked chunks.
MaxUnlockingChunks::set(1);
let mut current_era = 0;
// fills the chunking slots for account
mock::start_active_era(current_era);
assert_ok!(Staking::unbond(RuntimeOrigin::signed(11), 1));
current_era += 1;
mock::start_active_era(current_era);
// unbonding will fail because i) there are no remaining chunks and ii) no filled chunks
// can be released because current chunk hasn't stay in the queue for at least
// `BondingDuration`
assert_noop!(Staking::unbond(RuntimeOrigin::signed(11), 1), Error::<Test>::NoMoreChunks);
// fast-forward a few eras for unbond to be successful with implicit withdraw
current_era += 10;
mock::start_active_era(current_era);
assert_ok!(Staking::unbond(RuntimeOrigin::signed(11), 1));
// * 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_and_execute(|| {
// Set payee to stash.
assert_ok!(Staking::set_payee(RuntimeOrigin::signed(11), RewardDestination::Stash));
// 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 11
Staking::ledger(11.into()).unwrap(),
StakingLedgerInspect {
stash: 11,
total: 1000,
active: 1000,
unlocking: Default::default(),
legacy_claimed_rewards: bounded_vec![],
mock::start_active_era(2);
// Try to rebond some funds. We get an error since no fund is unbonded.
assert_noop!(Staking::rebond(RuntimeOrigin::signed(11), 500), Error::<Test>::NoUnlockChunk);
// Unbond almost all of the funds in stash.
Staking::unbond(RuntimeOrigin::signed(11), 900).unwrap();
Staking::ledger(11.into()).unwrap(),
StakingLedgerInspect {
stash: 11,
total: 1000,
active: 100,
unlocking: bounded_vec![UnlockChunk { value: 900, era: 2 + 3 }],
legacy_claimed_rewards: bounded_vec![],
// Re-bond all the funds unbonded.
Staking::rebond(RuntimeOrigin::signed(11), 900).unwrap();
Staking::ledger(11.into()).unwrap(),
StakingLedgerInspect {
stash: 11,
total: 1000,
active: 1000,
unlocking: Default::default(),
legacy_claimed_rewards: bounded_vec![],
// Unbond almost all of the funds in stash.
Staking::unbond(RuntimeOrigin::signed(11), 900).unwrap();
Staking::ledger(11.into()).unwrap(),
StakingLedgerInspect {
stash: 11,
total: 1000,
active: 100,
unlocking: bounded_vec![UnlockChunk { value: 900, era: 5 }],
legacy_claimed_rewards: bounded_vec![],
// Re-bond part of the funds unbonded.
Staking::rebond(RuntimeOrigin::signed(11), 500).unwrap();
Staking::ledger(11.into()).unwrap(),
StakingLedgerInspect {
stash: 11,
total: 1000,
active: 600,
unlocking: bounded_vec![UnlockChunk { value: 400, era: 5 }],
legacy_claimed_rewards: bounded_vec![],
// Re-bond the remainder of the funds unbonded.
Staking::rebond(RuntimeOrigin::signed(11), 500).unwrap();
Staking::ledger(11.into()).unwrap(),
StakingLedgerInspect {
stash: 11,
total: 1000,
active: 1000,
unlocking: Default::default(),
legacy_claimed_rewards: bounded_vec![],
// Unbond parts of the funds in stash.
Staking::unbond(RuntimeOrigin::signed(11), 300).unwrap();
Staking::unbond(RuntimeOrigin::signed(11), 300).unwrap();
Staking::unbond(RuntimeOrigin::signed(11), 300).unwrap();
Staking::ledger(11.into()).unwrap(),
StakingLedgerInspect {
stash: 11,
total: 1000,
active: 100,
unlocking: bounded_vec![UnlockChunk { value: 900, era: 5 }],
legacy_claimed_rewards: bounded_vec![],
// Re-bond part of the funds unbonded.
Staking::rebond(RuntimeOrigin::signed(11), 500).unwrap();
Staking::ledger(11.into()).unwrap(),
StakingLedgerInspect {
stash: 11,
total: 1000,
active: 600,
unlocking: bounded_vec![UnlockChunk { value: 400, era: 5 }],
legacy_claimed_rewards: bounded_vec![],
#[test]
fn rebond_is_fifo() {
// Rebond should proceed by reversing the most recent bond operations.
ExtBuilder::default().nominate(false).build_and_execute(|| {
// Set payee to stash.
assert_ok!(Staking::set_payee(RuntimeOrigin::signed(11), RewardDestination::Stash));
// 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(11.into()).unwrap(),
StakingLedgerInspect {
stash: 11,
total: 1000,
active: 1000,
unlocking: Default::default(),
legacy_claimed_rewards: bounded_vec![],
mock::start_active_era(2);
// Unbond some of the funds in stash.
Staking::unbond(RuntimeOrigin::signed(11), 400).unwrap();
Staking::ledger(11.into()).unwrap(),
StakingLedgerInspect {
stash: 11,
total: 1000,
active: 600,
unlocking: bounded_vec![UnlockChunk { value: 400, era: 2 + 3 }],
legacy_claimed_rewards: bounded_vec![],
mock::start_active_era(3);
// Unbond more of the funds in stash.
Staking::unbond(RuntimeOrigin::signed(11), 300).unwrap();
Staking::ledger(11.into()).unwrap(),
StakingLedgerInspect {
stash: 11,
total: 1000,
active: 300,
unlocking: bounded_vec![
UnlockChunk { value: 400, era: 2 + 3 },
UnlockChunk { value: 300, era: 3 + 3 },
legacy_claimed_rewards: bounded_vec![],
mock::start_active_era(4);
// Unbond yet more of the funds in stash.
Staking::unbond(RuntimeOrigin::signed(11), 200).unwrap();
Staking::ledger(11.into()).unwrap(),
StakingLedgerInspect {
stash: 11,
total: 1000,
active: 100,
unlocking: bounded_vec![
UnlockChunk { value: 400, era: 2 + 3 },
UnlockChunk { value: 300, era: 3 + 3 },
UnlockChunk { value: 200, era: 4 + 3 },
legacy_claimed_rewards: bounded_vec![],
// Re-bond half of the unbonding funds.
Staking::rebond(RuntimeOrigin::signed(11), 400).unwrap();
Staking::ledger(11.into()).unwrap(),
StakingLedgerInspect {
stash: 11,
total: 1000,
active: 500,
unlocking: bounded_vec![
UnlockChunk { value: 400, era: 2 + 3 },
UnlockChunk { value: 100, era: 3 + 3 },
legacy_claimed_rewards: bounded_vec![],
#[test]
fn rebond_emits_right_value_in_event() {
// When a user calls rebond with more than can be rebonded, things succeed,
// and the rebond event emits the actual value rebonded.
ExtBuilder::default().nominate(false).build_and_execute(|| {
// Set payee to stash.
assert_ok!(Staking::set_payee(RuntimeOrigin::signed(11), RewardDestination::Stash));
// 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);
// Unbond almost all of the funds in stash.
Staking::unbond(RuntimeOrigin::signed(11), 900).unwrap();
Staking::ledger(11.into()).unwrap(),
StakingLedgerInspect {
stash: 11,
total: 1000,
active: 100,
unlocking: bounded_vec![UnlockChunk { value: 900, era: 1 + 3 }],
legacy_claimed_rewards: bounded_vec![],
);
// Re-bond less than the total
Staking::rebond(RuntimeOrigin::signed(11), 100).unwrap();
Staking::ledger(11.into()).unwrap(),
StakingLedgerInspect {
stash: 11,
total: 1000,
active: 200,
unlocking: bounded_vec![UnlockChunk { value: 800, era: 1 + 3 }],
legacy_claimed_rewards: bounded_vec![],
);
// Event emitted should be correct
assert_eq!(*staking_events().last().unwrap(), Event::Bonded { stash: 11, amount: 100 });
// Re-bond way more than available
Staking::rebond(RuntimeOrigin::signed(11), 100_000).unwrap();
Staking::ledger(11.into()).unwrap(),
StakingLedgerInspect {
stash: 11,
total: 1000,
active: 1000,
unlocking: Default::default(),
legacy_claimed_rewards: bounded_vec![],
);
// Event emitted should be correct, only 800
assert_eq!(*staking_events().last().unwrap(), Event::Bonded { stash: 11, amount: 800 });
ExtBuilder::default()
.nominate(false)
.set_status(31, StakerStatus::Idle)
.set_status(41, StakerStatus::Idle)
.set_stake(21, 2000)
.try_state(false)
.build_and_execute(|| {
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(active_era(), &11).total, 1000);
assert_eq!(Staking::eras_stakers(active_era(), &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
EraInfo::<Test>::set_exposure(0, &21, Exposure { total: 69, own: 69, others: vec![] });
stash: 21,
total: 69,
active: 69,
unlocking: Default::default(),
legacy_claimed_rewards: bounded_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);
mock::make_all_reward_payment(0);
assert_eq!(Staking::eras_stakers(active_era(), &11).total, 1000);
assert_eq!(Staking::eras_stakers(active_era(), &21).total, 2000);
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);
assert_eq!(Staking::eras_stakers(active_era(), &11).total, 1000 + total_payout_0 / 2);
assert_eq!(Staking::eras_stakers(active_era(), &21).total, 2000 + total_payout_0 / 2);
ExtBuilder::default()
.existential_deposit(10)
.build_and_execute(|| {
assert_eq!(Balances::free_balance(11), 10 * 1000);
assert_eq!(Staking::bonded(&11), Some(11));
assert!(<Ledger<Test>>::contains_key(&11));
assert!(<Bonded<Test>>::contains_key(&11));
assert!(<Validators<Test>>::contains_key(&11));
assert!(<Payee<Test>>::contains_key(&11));
// stash is not reapable
assert_noop!(
Staking::reap_stash(RuntimeOrigin::signed(20), 11, 0),
Error::<Test>::FundedTarget
);
// no easy way to cause an account to go below ED, we tweak their staking ledger
// instead.
Ledger::<Test>::insert(11, StakingLedger::<Test>::new(11, 5));
assert_ok!(Staking::reap_stash(RuntimeOrigin::signed(20), 11, 0));
assert!(!<Ledger<Test>>::contains_key(&11));
assert!(!<Bonded<Test>>::contains_key(&11));
assert!(!<Validators<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 &[11, 21] {
assert_ok!(Staking::set_payee(RuntimeOrigin::signed(*i), RewardDestination::Stash));
assert_eq_uvec!(validator_controllers(), vec![21, 11]);
// put some money in account that we'll use.
for i in 1..7 {
let _ = Balances::deposit_creating(&i, 5000);
}
assert_ok!(Staking::bond(RuntimeOrigin::signed(1), 2000, RewardDestination::Account(1)));
assert_ok!(Staking::nominate(RuntimeOrigin::signed(1), vec![11, 5]));
assert_ok!(Staking::bond(RuntimeOrigin::signed(3), 500, RewardDestination::Account(3)));
assert_ok!(Staking::nominate(RuntimeOrigin::signed(3), vec![21, 1]));
// add a new validator candidate
assert_ok!(Staking::bond(RuntimeOrigin::signed(5), 1000, RewardDestination::Account(5)));
assert_ok!(Staking::validate(RuntimeOrigin::signed(5), ValidatorPrefs::default()));
RuntimeOrigin::signed(5),
SessionKeys { other: 6.into() },
vec![]
));
mock::start_active_era(1);
// with current nominators 11 and 5 have the most stake
assert_eq_uvec!(validator_controllers(), vec![5, 11]);
// 2 decides to be a validator. Consequences:
assert_ok!(Staking::validate(RuntimeOrigin::signed(1), ValidatorPrefs::default()));
RuntimeOrigin::signed(1),
SessionKeys { other: 2.into() },
vec![]
));
// 11: 1000 self vote
// 21: 1000 self vote + 250 vote
// 5 : 1000 self vote
// 1 : 2000 self vote + 250 vote.
// Winners: 21 and 1
mock::start_active_era(2);
assert_eq_uvec!(validator_controllers(), vec![1, 21]);
61,
500,
StakerStatus::Nominator(vec![
11, 21, // good votes
1, 2, 15, 1000, 25, // crap votes. No effect.
]),
)
// the genesis validators already reflect the above vote, nonetheless start a new era.
mock::start_active_era(1);
assert_eq_uvec!(validator_controllers(), vec![21, 11]);
// our new voter is taken into account
assert!(Staking::eras_stakers(active_era(), &11).others.iter().any(|i| i.who == 61));
assert!(Staking::eras_stakers(active_era(), &21).others.iter().any(|i| i.who == 61));
}
#[test]
fn bond_with_no_staked_value() {
// Behavior when someone bonds with no staked value.
// Particularly when they votes and the candidate is elected.
ExtBuilder::default()
.validator_count(3)
.existential_deposit(5)
.nominate(false)
.minimum_validator_count(1)
.build_and_execute(|| {
// Can't bond with 1
assert_noop!(
Staking::bond(RuntimeOrigin::signed(1), 1, RewardDestination::Account(1)),
Error::<Test>::InsufficientBond,
);
// bonded with absolute minimum value possible.
assert_ok!(Staking::bond(RuntimeOrigin::signed(1), 5, RewardDestination::Account(1)));
assert_eq!(Balances::locks(&1)[0].amount, 5);
// unbonding even 1 will cause all to be unbonded.
assert_ok!(Staking::unbond(RuntimeOrigin::signed(1), 1));
Staking::ledger(1.into()).unwrap(),
StakingLedgerInspect {
stash: 1,
active: 0,
total: 5,
unlocking: bounded_vec![UnlockChunk { value: 5, era: 3 }],
legacy_claimed_rewards: bounded_vec![],
mock::start_active_era(1);
mock::start_active_era(2);
assert_ok!(Staking::withdraw_unbonded(RuntimeOrigin::signed(1), 0));
assert!(Staking::ledger(1.into()).is_ok());
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(RuntimeOrigin::signed(1), 0));
assert!(Staking::ledger(1.into()).is_err());
assert_eq!(Balances::locks(&1).len(), 0);
});
ExtBuilder::default()
.validator_count(3)
.nominate(false)
.minimum_validator_count(1)
.build_and_execute(|| {
assert_ok!(Staking::chill(RuntimeOrigin::signed(31)));
assert_ok!(Staking::set_payee(RuntimeOrigin::signed(11), RewardDestination::Stash));
let init_balance_1 = Balances::free_balance(&1);
let init_balance_11 = Balances::free_balance(&11);
// Stingy validator.
assert_ok!(Staking::bond(RuntimeOrigin::signed(1), 1, RewardDestination::Account(1)));
assert_ok!(Staking::validate(RuntimeOrigin::signed(1), ValidatorPrefs::default()));
RuntimeOrigin::signed(1),
SessionKeys { other: 1.into() },
// 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);
// 1 is elected.
assert_eq_uvec!(validator_controllers(), vec![21, 11, 1]);
assert_eq!(Staking::eras_stakers(active_era(), &2).total, 0);