Newer
Older
// Confirm that account 11 can now transfer some balance
assert_ok!(Balances::transfer_allow_death(RuntimeOrigin::signed(11), 21, 1));
#[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![],
#[test]
fn bond_extra_controller_bad_state_works() {
ExtBuilder::default().try_state(false).build_and_execute(|| {
assert_eq!(StakingLedger::<Test>::get(StakingAccount::Stash(31)).unwrap().stash, 31);
// simulate ledger in bad state: the controller 41 is associated to the stash 31 and 41.
Bonded::<Test>::insert(31, 41);
// we confirm that the ledger is in bad state: 31 has 41 as controller and when fetching
// the ledger associated with the controller 41, its stash is 41 (and not 31).
assert_eq!(Ledger::<Test>::get(41).unwrap().stash, 41);
// if the ledger is in this bad state, the `bond_extra` should fail.
assert_noop!(Staking::bond_extra(RuntimeOrigin::signed(31), 10), Error::<Test>::BadState);
})
}
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 });
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
#[test]
fn max_staked_rewards_default_works() {
ExtBuilder::default().build_and_execute(|| {
assert_eq!(<MaxStakedRewards<Test>>::get(), None);
let default_stakers_payout = current_total_payout_for_duration(reward_time_per_era());
assert!(default_stakers_payout > 0);
start_active_era(1);
// the final stakers reward is the same as the reward before applied the cap.
assert_eq!(ErasValidatorReward::<Test>::get(0).unwrap(), default_stakers_payout);
// which is the same behaviour if the `MaxStakedRewards` is set to 100%.
<MaxStakedRewards<Test>>::set(Some(Percent::from_parts(100)));
let default_stakers_payout = current_total_payout_for_duration(reward_time_per_era());
assert_eq!(ErasValidatorReward::<Test>::get(0).unwrap(), default_stakers_payout);
})
}
#[test]
fn max_staked_rewards_works() {
ExtBuilder::default().nominate(true).build_and_execute(|| {
let max_staked_rewards = 10;
// sets new max staked rewards through set_staking_configs.
assert_ok!(Staking::set_staking_configs(
RuntimeOrigin::root(),
ConfigOp::Noop,
ConfigOp::Noop,
ConfigOp::Noop,
ConfigOp::Noop,
ConfigOp::Noop,
ConfigOp::Noop,
ConfigOp::Set(Percent::from_percent(max_staked_rewards)),
));
assert_eq!(<MaxStakedRewards<Test>>::get(), Some(Percent::from_percent(10)));
// check validators account state.
assert_eq!(Session::validators().len(), 2);
assert!(Session::validators().contains(&11) & Session::validators().contains(&21));
// balance of the mock treasury account is 0
assert_eq!(RewardRemainderUnbalanced::get(), 0);
let max_stakers_payout = current_total_payout_for_duration(reward_time_per_era());
start_active_era(1);
let treasury_payout = RewardRemainderUnbalanced::get();
let validators_payout = ErasValidatorReward::<Test>::get(0).unwrap();
let total_payout = treasury_payout + validators_payout;
// max stakers payout (without max staked rewards cap applied) is larger than the final
// validator rewards. The final payment and remainder should be adjusted by redistributing
// the era inflation to apply the cap...
assert!(max_stakers_payout > validators_payout);
// .. which means that the final validator payout is 10% of the total payout..
assert_eq!(validators_payout, Percent::from_percent(max_staked_rewards) * total_payout);
// .. and the remainder 90% goes to the treasury.
assert_eq!(
treasury_payout,
Percent::from_percent(100 - max_staked_rewards) * (treasury_payout + validators_payout)
);
})
}
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]);