Newer
Older
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 Controller
assert_eq!(Staking::payee(&11), RewardDestination::Controller);
// Check that reward went to the controller account
assert_eq!(Balances::free_balance(10), 1 + total_payout_2);
// Check that amount at stake is NOT increased
assert_eq!(
Staking::ledger(&10),
Some(StakingLedger {
stash: 11,
total: 1000 + total_payout_0,
active: 1000 + total_payout_0,
unlocking: vec![],
claimed_rewards: vec![0, 1, 2],
})
);
// 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 { commission: commission.clone(), ..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(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(&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![],
claimed_rewards: 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![],
claimed_rewards: 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![],
claimed_rewards: 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![],
claimed_rewards: vec![],
})
);
Staking::eras_stakers(active_era(), 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![],
claimed_rewards: 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);
assert_eq!(
Staking::ledger(&10),
Some(StakingLedger {
stash: 11,
total: 1000 + 100,
active: 1000 + 100,
unlocking: vec![],
claimed_rewards: 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(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 }],
// 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(|| {
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);
})
}
// * 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 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![],
claimed_rewards: 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, era: 2 + 3 }],
claimed_rewards: vec![],
})
);
// 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![],
claimed_rewards: 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 }],
claimed_rewards: vec![],
})
);
// 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 }],
claimed_rewards: vec![],
})
);
// 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,
unlocking: vec![],
claimed_rewards: vec![],
})
);
// 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 },
],
claimed_rewards: vec![],
})
);
// 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 },
],
claimed_rewards: 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 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![],
claimed_rewards: 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 },],
claimed_rewards: vec![],
})
);
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 },
],
claimed_rewards: vec![],
})
);
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 },
],
claimed_rewards: vec![],
})
);
// 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 },
],
claimed_rewards: vec![],
})
);
})
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
#[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 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);
// 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: 1 + 3 }],
claimed_rewards: vec![],
})
);
// Re-bond less than the total
Staking::rebond(Origin::signed(10), 100).unwrap();
assert_eq!(
Staking::ledger(&10),
Some(StakingLedger {
stash: 11,
total: 1000,
active: 200,
unlocking: vec![UnlockChunk { value: 800, era: 1 + 3 }],
claimed_rewards: vec![],
})
);
// Event emitted should be correct
assert_eq!(*staking_events().last().unwrap(), Event::Bonded(11, 100));
// Re-bond way more than available
Staking::rebond(Origin::signed(10), 100_000).unwrap();
assert_eq!(
Staking::ledger(&10),
Some(StakingLedger {
stash: 11,
total: 1000,
active: 1000,
unlocking: vec![],
claimed_rewards: vec![],
})
);
// Event emitted should be correct, only 800
assert_eq!(*staking_events().last().unwrap(), Event::Bonded(11, 800));
});
}
ExtBuilder::default()
.nominate(false)
.set_status(31, StakerStatus::Idle)
.set_status(41, StakerStatus::Idle)
.set_stake(21, 2000)
.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
ErasStakers::<Test>::insert(0, 21, Exposure { total: 69, own: 69, others: vec![] });
<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);
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, 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(active_era(), 11).total, 1000 + total_payout_0 / 2);
assert_eq!(Staking::eras_stakers(active_era(), 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), 10);
// Check the balance of the stash account
assert_eq!(Balances::free_balance(11), 10 * 1000);
// Check these two accounts are bonded
assert_eq!(Staking::bonded(&11), Some(10));
// 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), 10 * 1000);
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
// 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());
// Check total balance of stash
assert_eq!(Balances::total_balance(&11), 10);
// Reap the stash
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), 10);
// Check the balance of the stash account
assert_eq!(Balances::free_balance(11), 10_000);
// 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), 10_000);
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
// 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());
// Check total balance of stash
assert_eq!(Balances::total_balance(&11), 10);
// Reap the stash
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]);
.add_staker(
61,
60,
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![20, 10]);
// 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 she 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(Origin::signed(1), 2, 1, RewardDestination::Controller),
Error::<Test>::InsufficientBond,
);
// 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,
unlocking: vec![UnlockChunk { value: 5, era: 3 }],
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_and_execute(|| {
// 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_and_execute(|| {
// 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();
assert_eq!(
supports,
vec![
(21, Support { total: 1800, voters: vec![(21, 1000), (1, 400), (3, 400)] }),
(31, Support { total: 2200, voters: vec![(31, 1000), (1, 600), (3, 600)] })
],
);
});
}
#[test]
fn bond_with_duplicate_vote_should_be_ignored_by_election_provider_elected() {
// same as above but ensures that even when the dupe is being elected, everything is sane.
ExtBuilder::default()
.validator_count(2)
.nominate(false)
.minimum_validator_count(1)
.build_and_execute(|| {
// 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().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);
}