Newer
Older
// 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(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![],
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![],
})
);
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![],
claimed_rewards: 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![],
claimed_rewards: 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 }],
// 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);
})
}
#[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_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);
assert_eq!(Staking::active_era().unwrap().index, 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![],
})
);
})
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);
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
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
ExtBuilder::default()
.existential_deposit(10)
.min_nominator_bond(10)
.min_validator_bond(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());
// 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
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
ExtBuilder::default()
.existential_deposit(10)
.min_nominator_bond(10)
.min_validator_bond(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());
// 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]);
});
}
#[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![
11, 21, // good votes
1, 2, 15, 1000, 25 // crap votes. No effect.
]
));
// new block
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)
.min_nominator_bond(5)
.min_validator_bond(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(|| {
// 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_and_execute(|| {
// 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_and_execute(|| {
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);