Newer
Older
let recorded_stash_balance = 1000 + total_payout_0 + total_payout_1;
// 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,
// Change RewardDestination to Controller
<Payee<Test>>::insert(&11, RewardDestination::Controller);
// Check controller balance
assert_eq!(Balances::free_balance(&10), 1);
// Compute total payout now for whole duration as other parameter won't change
let total_payout_2 = current_total_payout_for_duration(3);
assert!(total_payout_2 > 100); // Test is meaningfull if reward something
<Module<Test>>::add_reward_points_to_validator(11, 1);
// 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,
// 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.
with_externalities(&mut ExtBuilder::default()
.build(),
let stash_initial_balance = Balances::total_balance(&11);
// check the balance of a validator accounts.
assert_eq!(Balances::total_balance(&10), 1);
// check the balance of a validator's stash accounts.
assert_eq!(Balances::total_balance(&11), stash_initial_balance);
let _ = Balances::make_free_balance_be(&2, 500);
<Stakers<Test>>::insert(&11, Exposure {
own: 500, // equal division indicates that the reward will be equally divided among validator and nominator.
total: 1000,
others: vec![IndividualExposure {who: 2, value: 500 }]
<Payee<Test>>::insert(&2, RewardDestination::Stash);
<Validators<Test>>::insert(&11, ValidatorPrefs {
unstake_threshold: 3,
validator_payment: validator_cut
// Compute total payout now for whole duration as other parameter won't change
let total_payout_0 = current_total_payout_for_duration(3);
assert!(total_payout_0 > 100); // Test is meaningfull if reward something
<Module<Test>>::add_reward_points_to_validator(11, 1);
// whats left to be shared is the sum of 3 rounds minus the validator's cut.
let shared_cut = total_payout_0 - validator_cut;
// Validator's payee is Staked account, 11, reward will be paid here.
assert_eq!(Balances::total_balance(&11), stash_initial_balance + shared_cut/2 + validator_cut);
// Controller account will not get any reward.
assert_eq!(Balances::total_balance(&10), 1);
// Rest of the reward will be shared and paid to the nominator in stake.
assert_eq!(Balances::total_balance(&2), 500 + shared_cut/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`.
with_externalities(&mut ExtBuilder::default().build(),
|| {
// Check that account 10 is a validator
assert!(<Validators<Test>>::exists(11));
// Check that account 10 is bonded to account 11
assert_eq!(Staking::bonded(&11), Some(10));
// Check how much is at stake
assert_eq!(Staking::ledger(&10), Some(StakingLedger {
stash: 11,
total: 1000,
active: 1000,
unlocking: vec![],
}));
// Give account 11 some large free balance greater than total
let _ = Balances::make_free_balance_be(&11, 1000000);
// Call the bond_extra function from controller, add only 100
assert_ok!(Staking::bond_extra(Origin::signed(11), 100));
// There should be 100 more `total` and `active` in the ledger
assert_eq!(Staking::ledger(&10), Some(StakingLedger {
stash: 11,
total: 1000 + 100,
active: 1000 + 100,
unlocking: vec![],
}));
// Call the bond_extra function with a large number, should handle it
assert_ok!(Staking::bond_extra(Origin::signed(11), u64::max_value()));
// The full amount of the funds should now be in the total and active
assert_eq!(Staking::ledger(&10), Some(StakingLedger {
stash: 11,
total: 1000000,
active: 1000000,
unlocking: vec![],
}));
fn bond_extra_and_withdraw_unbonded_works() {
// * Should test
// * Given an account being bonded [and chosen as a validator](not mandatory)
// * It can add extra funds to the bonded account.
// * it can unbond a portion of its funds from the stash account.
// * Once the unbonding period is done, it can actually take the funds out of the stash.
with_externalities(&mut ExtBuilder::default()
.nominate(false)
|| {
// 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);
// Initial config should be correct
assert_eq!(Staking::current_era(), 0);
assert_eq!(Session::current_index(), 0);
// 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.
assert_eq!(Staking::ledger(&10), Some(StakingLedger {
stash: 11,
total: 1000,
active: 1000,
unlocking: vec![],
}));
assert_eq!(Staking::stakers(&11), Exposure { total: 1000, own: 1000, others: vec![] });
// deposit the extra 100 units
Staking::bond_extra(Origin::signed(11), 100).unwrap();
assert_eq!(Staking::ledger(&10), Some(StakingLedger {
stash: 11,
total: 1000 + 100,
active: 1000 + 100,
unlocking: vec![],
}));
// Exposure is a snapshot! only updated after the next era update.
assert_ne!(Staking::stakers(&11), Exposure { total: 1000 + 100, own: 1000 + 100, others: vec![] });
Timestamp::set_timestamp(10);
start_era(2);
assert_eq!(Staking::current_era(), 2);
// ledger should be the same.
assert_eq!(Staking::ledger(&10), Some(StakingLedger {
stash: 11,
total: 1000 + 100,
active: 1000 + 100,
unlocking: vec![],
}));
assert_eq!(Staking::stakers(&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.
Staking::withdraw_unbonded(Origin::signed(10)).unwrap();
assert_eq!(Staking::ledger(&10), Some(StakingLedger {
stash: 11, total: 1000 + 100, active: 100, unlocking: vec![UnlockChunk{ value: 1000, era: 2 + 3}] }));
// nothing yet
Staking::withdraw_unbonded(Origin::signed(10)).unwrap();
assert_eq!(Staking::ledger(&10), Some(StakingLedger {
stash: 11, total: 1000 + 100, active: 100, unlocking: vec![UnlockChunk{ value: 1000, era: 2 + 3}] }));
Staking::withdraw_unbonded(Origin::signed(10)).unwrap();
// 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![] }));
})
}
#[test]
fn too_many_unbond_calls_should_not_work() {
with_externalities(&mut ExtBuilder::default().build(), || {
// locked at era 0 until 3
for _ in 0..MAX_UNLOCKING_CHUNKS-1 {
assert_ok!(Staking::unbond(Origin::signed(10), 1));
}
assert_ok!(Staking::unbond(Origin::signed(10), 1));
// can't do more.
assert_noop!(Staking::unbond(Origin::signed(10), 1), "can not schedule more unlock chunks");
assert_noop!(Staking::unbond(Origin::signed(10), 1), "can not schedule more unlock chunks");
// free up.
assert_ok!(Staking::withdraw_unbonded(Origin::signed(10)));
// Can add again.
assert_ok!(Staking::unbond(Origin::signed(10), 1));
assert_eq!(Staking::ledger(&10).unwrap().unlocking.len(), 2);
})
}
fn slot_stake_is_least_staked_validator_and_exposure_defines_maximum_punishment() {
// Test that slot_stake is determined by the least staked validator
// Test that slot_stake is the maximum punishment that can happen to a validator
with_externalities(&mut ExtBuilder::default()
.nominate(false)
// Confirm validator count is 2
assert_eq!(Staking::validator_count(), 2);
// Confirm account 10 and 20 are validators
assert!(<Validators<Test>>::exists(&11) && <Validators<Test>>::exists(&21));
assert_eq!(Staking::stakers(&11).total, 1000);
assert_eq!(Staking::stakers(&21).total, 2000);
// Give the man some money.
let _ = Balances::make_free_balance_be(&10, 1000);
let _ = Balances::make_free_balance_be(&20, 1000);
// We confirm initialized slot_stake is this value
assert_eq!(Staking::slot_stake(), Staking::stakers(&11).total);
// Now lets lower account 20 stake
<Stakers<Test>>::insert(&21, Exposure { total: 69, own: 69, others: vec![] });
assert_eq!(Staking::stakers(&21).total, 69);
<Ledger<Test>>::insert(&20, StakingLedger { stash: 22, total: 69, active: 69, unlocking: vec![] });
// Compute total payout now for whole duration as other parameter won't change
let total_payout_0 = current_total_payout_for_duration(3);
assert!(total_payout_0 > 100); // Test is meaningfull if reward something
<Module<Test>>::add_reward_points_to_validator(11, 1);
<Module<Test>>::add_reward_points_to_validator(21, 1);
// New era --> rewards are paid --> stakes are changed
assert_eq!(Staking::stakers(&11).total, 1000 + total_payout_0/2);
assert_eq!(Staking::stakers(&21).total, 69 + total_payout_0/2);
let _11_balance = Balances::free_balance(&11);
assert_eq!(_11_balance, 1000 + total_payout_0/2);
// -- slot stake should also be updated.
assert_eq!(Staking::slot_stake(), 69 + total_payout_0/2);
// If 10 gets slashed now, it will be slashed by 5% of exposure.total * 2.pow(unstake_thresh)
Staking::on_offline_validator(10, 4);
// Confirm user has been reported
assert_eq!(Staking::slash_count(&11), 4);
// check the balance of 10 (slash will be deducted from free balance.)
assert_eq!(Balances::free_balance(&11), _11_balance - _11_balance*5/100 * 2u64.pow(3));
#[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
with_externalities(&mut ExtBuilder::default()
.existential_deposit(10)
.build(),
|| {
// 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
// Initiate slash count storage item
Staking::on_offline_validator(10, 1);
// Set payee information
assert_ok!(Staking::set_payee(Origin::signed(10), RewardDestination::Stash));
// Check storage items that should be cleaned up
assert!(<Ledger<Test>>::exists(&10));
assert!(<Bonded<Test>>::exists(&11));
assert!(<Validators<Test>>::exists(&11));
assert!(<SlashCount<Test>>::exists(&11));
assert!(<Payee<Test>>::exists(&11));
// Reduce free_balance of controller to 0
let _ = Balances::slash(&10, u64::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>>::exists(&10));
assert!(<Bonded<Test>>::exists(&11));
assert!(<Validators<Test>>::exists(&11));
assert!(<SlashCount<Test>>::exists(&11));
assert!(<Payee<Test>>::exists(&11));
// Reduce free_balance of stash to 0
let _ = Balances::slash(&11, u64::max_value());
assert_eq!(Balances::total_balance(&11), 0);
// Check storage items do not exist
assert!(!<Ledger<Test>>::exists(&10));
assert!(!<Bonded<Test>>::exists(&11));
assert!(!<Validators<Test>>::exists(&11));
assert!(!<Nominators<Test>>::exists(&11));
assert!(!<SlashCount<Test>>::exists(&11));
assert!(!<Payee<Test>>::exists(&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
with_externalities(&mut ExtBuilder::default()
.existential_deposit(10)
.build(),
|| {
// Make 10 a nominator
assert_ok!(Staking::nominate(Origin::signed(10), vec![20]));
// Check that account 10 is a nominator
assert!(<Nominators<Test>>::exists(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>>::exists(&10));
assert!(<Bonded<Test>>::exists(&11));
assert!(<Nominators<Test>>::exists(&11));
assert!(<Payee<Test>>::exists(&11));
// Reduce free_balance of controller to 0
let _ = Balances::slash(&10, u64::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>>::exists(&10));
assert!(<Bonded<Test>>::exists(&11));
assert!(<Nominators<Test>>::exists(&11));
assert!(<Payee<Test>>::exists(&11));
// Reduce free_balance of stash to 0
let _ = Balances::slash(&11, u64::max_value());
assert_eq!(Balances::total_balance(&11), 0);
// Check storage items do not exist
assert!(!<Ledger<Test>>::exists(&10));
assert!(!<Bonded<Test>>::exists(&11));
assert!(!<Validators<Test>>::exists(&11));
assert!(!<Nominators<Test>>::exists(&11));
assert!(!<SlashCount<Test>>::exists(&11));
assert!(!<Payee<Test>>::exists(&11));
}
#[test]
fn phragmen_poc_works() {
// Tests the POC test of the phragmen, mentioned in the paper and reference implementation.
// Initial votes:
// Votes [
// ('2', 500, ['10', '20', '30']),
// ('4', 500, ['10', '20', '40']),
// ('10', 1000, ['10']),
// ('20', 1000, ['20']),
// ('30', 1000, ['30']),
// ('40', 1000, ['40'])]
//
// Sequential Phragmén gives
// 10 is elected with stake 1666.6666666666665 and score 0.0005
// 20 is elected with stake 1333.3333333333333 and score 0.00075
// 2 has load 0.00075 and supported
// 10 with stake 333.3333333333333 20 with stake 166.66666666666666 30 with stake 0.0
// 4 has load 0.00075 and supported
// 10 with stake 333.3333333333333 20 with stake 166.66666666666666 40 with stake 0.0
// 10 has load 0.0005 and supported
// 10 with stake 1000.0
// 20 has load 0.00075 and supported
// 20 with stake 1000.0
// 30 has load 0 and supported
// 30 with stake 0
// 40 has load 0 and supported
// 40 with stake 0
// Sequential Phragmén with post processing gives
// 10 is elected with stake 1500.0 and score 0.0005
// 20 is elected with stake 1500.0 and score 0.00075
// 10 has load 0.0005 and supported
// 10 with stake 1000.0
// 20 has load 0.00075 and supported
// 20 with stake 1000.0
// 30 has load 0 and supported
// 30 with stake 0
// 40 has load 0 and supported
// 40 with stake 0
// 2 has load 0.00075 and supported
// 10 with stake 166.66666666666674 20 with stake 333.33333333333326 30 with stake 0
// 4 has load 0.00075 and supported
// 10 with stake 333.3333333333333 20 with stake 166.66666666666666 40 with stake 0.0
with_externalities(&mut ExtBuilder::default()
.nominate(false)
// We don't really care about this. At this point everything is even.
assert_eq_uvec!(validator_controllers(), vec![40, 30]);
// Set payees to Controller
assert_ok!(Staking::set_payee(Origin::signed(10), RewardDestination::Controller));
assert_ok!(Staking::set_payee(Origin::signed(20), RewardDestination::Controller));
assert_ok!(Staking::set_payee(Origin::signed(30), RewardDestination::Controller));
assert_ok!(Staking::set_payee(Origin::signed(40), RewardDestination::Controller));
// no one is a nominator
assert_eq!(<Nominators<Test>>::enumerate().count(), 0 as usize);
// bond [2,1] / [4,3] a nominator
let _ = Balances::deposit_creating(&1, 1000);
let _ = Balances::deposit_creating(&3, 1000);
assert_ok!(Staking::bond(Origin::signed(1), 2, 500, RewardDestination::default()));
assert_ok!(Staking::nominate(Origin::signed(2), vec![11, 21, 31]));
assert_ok!(Staking::bond(Origin::signed(3), 4, 500, RewardDestination::default()));
assert_ok!(Staking::nominate(Origin::signed(4), vec![11, 21, 41]));
// New era => election algorithm will trigger
assert_eq_uvec!(validator_controllers(), vec![20, 10]);
assert_eq!(Staking::stakers(11).own, 1000);
assert_eq!(Staking::stakers(21).own, 1000);
if cfg!(feature = "equalize") {
assert_eq!(Staking::stakers(11).total, 1000 + 499);
assert_eq!(Staking::stakers(21).total, 1000 + 499);
} else {
assert_eq!(Staking::stakers(11).total, 1000 + 332);
assert_eq!(Staking::stakers(21).total, 1000 + 666);
}
// Nominator's stake distribution.
assert_eq!(Staking::stakers(11).others.iter().map(|e| e.who).collect::<Vec<BalanceOf<Test>>>(), vec![3, 1]);
assert_eq!(Staking::stakers(21).others.iter().map(|e| e.who).collect::<Vec<BalanceOf<Test>>>(), vec![3, 1]);
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
if cfg!(feature = "equalize") {
assert_eq_uvec!(
Staking::stakers(11).others.iter().map(|e| e.value).collect::<Vec<BalanceOf<Test>>>(),
vec![333, 166]
);
assert_eq!(
Staking::stakers(11).others.iter().map(|e| e.value).sum::<BalanceOf<Test>>(),
499
);
assert_eq_uvec!(
Staking::stakers(21).others.iter().map(|e| e.value).collect::<Vec<BalanceOf<Test>>>(),
vec![333, 166]
);
assert_eq!(
Staking::stakers(21).others.iter().map(|e| e.value).sum::<BalanceOf<Test>>(),
499
);
} else {
assert_eq_uvec!(
Staking::stakers(11).others.iter().map(|e| e.value).collect::<Vec<BalanceOf<Test>>>(),
vec![166, 166]
);
assert_eq!(
Staking::stakers(11).others.iter().map(|e| e.value).sum::<BalanceOf<Test>>(),
332
);
assert_eq_uvec!(
Staking::stakers(21).others.iter().map(|e| e.value).collect::<Vec<BalanceOf<Test>>>(),
vec![333, 333]
);
assert_eq!(
Staking::stakers(21).others.iter().map(|e| e.value).sum::<BalanceOf<Test>>(),
666
);
}
// tests the encapsulated phragmen::elect function.
// Votes [
// ('10', 1000, ['10']),
// ('20', 1000, ['20']),
// ('30', 1000, ['30']),
// ('2', 50, ['10', '20']),
// ('4', 1000, ['10', '30'])
// ]
// Sequential Phragmén gives
// 10 is elected with stake 1705.7377049180327 and score 0.0004878048780487805
// 30 is elected with stake 1344.2622950819673 and score 0.0007439024390243903
with_externalities(&mut ExtBuilder::default().nominate(false).build(), || {
// initial setup of 10 and 20, both validators
assert_eq_uvec!(validator_controllers(), vec![20, 10]);
// Bond [30, 31] as the third validator
assert_ok!(Staking::bond_extra(Origin::signed(31), 999));
assert_ok!(Staking::validate(Origin::signed(30), ValidatorPrefs::default()));
// bond [2,1](A), [4,3](B), as 2 nominators
for i in &[1, 3] { let _ = Balances::deposit_creating(i, 2000); }
assert_ok!(Staking::bond(Origin::signed(1), 2, 50, RewardDestination::default()));
assert_ok!(Staking::nominate(Origin::signed(2), vec![11, 21]));
assert_ok!(Staking::bond(Origin::signed(3), 4, 1000, RewardDestination::default()));
assert_ok!(Staking::nominate(Origin::signed(4), vec![11, 31]));
let winners = phragmen::elect::<Test, _, _, _>(
2,
Staking::minimum_validator_count() as usize,
<Validators<Test>>::enumerate(),
<Nominators<Test>>::enumerate(),
Staking::slashable_balance_of,
let (winners, assignment) = winners.unwrap();
assert_eq!(winners, vec![11, 31]);
assert_eq!(assignment, vec![
(3, vec![(11, 2816371998), (31, 1478595298)]),
(1, vec![(11, 4294967296)]),
]);
check_exposure_all();
})
}
#[test]
fn switching_roles() {
// Test that it should be possible to switch between roles (nominator, validator, idle) with minimal overhead.
with_externalities(&mut ExtBuilder::default()
.nominate(false)
.build(),
|| {
Timestamp::set_timestamp(1); // Initialize time.
// 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()));
assert_eq_uvec!(validator_controllers(), vec![20, 10]);
assert_eq_uvec!(validator_controllers(), vec![20, 10]);
// new block --> ne era --> new validators
// 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
assert_eq_uvec!(validator_controllers(), vec![6, 10]);
assert_eq_uvec!(validator_controllers(), vec![6, 10]);
assert_eq_uvec!(validator_controllers(), vec![2, 20]);
});
}
#[test]
fn wrong_vote_is_null() {
with_externalities(&mut ExtBuilder::default()
.nominate(false)
.validator_pool(true)
.build(),
|| {
assert_eq_uvec!(validator_controllers(), vec![40, 30]);
// put some money in account that we'll use.
for i in 1..3 { let _ = Balances::deposit_creating(&i, 5000); }
// add 1 nominators
assert_ok!(Staking::bond(Origin::signed(1), 2, 2000, RewardDestination::default()));
assert_ok!(Staking::nominate(Origin::signed(2), vec![
1, 2, 15, 1000, 25 // crap votes. No effect.
]));
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.
with_externalities(&mut ExtBuilder::default()
.validator_count(3)
.existential_deposit(5)
.nominate(false)
.minimum_validator_count(1)
.build(), || {
assert_noop!(
Staking::bond(Origin::signed(1), 2, 1, RewardDestination::Controller),
"can not bond with value less than minimum balance"
);
// 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}]
})
);
start_era(1);
start_era(2);
// not yet removed.
assert_ok!(Staking::withdraw_unbonded(Origin::signed(2)));
assert!(Staking::ledger(2).is_some());
assert_eq!(Balances::locks(&1)[0].amount, 5);
// poof. Account 1 is removed from the staking system.
assert_ok!(Staking::withdraw_unbonded(Origin::signed(2)));
assert!(Staking::ledger(2).is_none());
assert_eq!(Balances::locks(&1).len(), 0);
});
}
#[test]
fn bond_with_little_staked_value_bounded_by_slot_stake() {
// Behavior when someone bonds with little staked value.
// Particularly when she votes and the candidate is elected.
with_externalities(&mut ExtBuilder::default()
.validator_count(3)
.nominate(false)
.minimum_validator_count(1)
.build(),
|| {
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()));
let total_payout_0 = current_total_payout_for_duration(3);
assert!(total_payout_0 > 100); // Test is meaningfull if reward something
add_reward_points_to_all_elected();
// 2 is elected.
// and fucks up the slot stake.
assert_eq_uvec!(validator_controllers(), vec![20, 10, 2]);
assert_eq!(Staking::slot_stake(), 1);
// Old ones are rewarded.
assert_eq!(Balances::free_balance(&10), init_balance_10 + total_payout_0/3);
// no rewards paid to 2. This was initial election.
assert_eq!(Balances::free_balance(&2), init_balance_2);
let total_payout_1 = current_total_payout_for_duration(3);
assert!(total_payout_1 > 100); // Test is meaningfull if reward something
add_reward_points_to_all_elected();
assert_eq_uvec!(validator_controllers(), vec![20, 10, 2]);
assert_eq!(Staking::slot_stake(), 1);
assert_eq!(Balances::free_balance(&2), init_balance_2 + total_payout_1/3);
assert_eq!(Balances::free_balance(&10), init_balance_10 + total_payout_0/3 + total_payout_1/3);
fn phragmen_linear_worse_case_equalize() {
with_externalities(&mut ExtBuilder::default()
.nominate(false)
.validator_pool(true)
.build(),
|| {
bond_validator(50, 1000);
bond_validator(60, 1000);
bond_validator(70, 1000);
bond_nominator(2, 2000, vec![11]);
bond_nominator(4, 1000, vec![11, 21]);
bond_nominator(6, 1000, vec![21, 31]);
bond_nominator(8, 1000, vec![31, 41]);
bond_nominator(110, 1000, vec![41, 51]);
bond_nominator(120, 1000, vec![51, 61]);
bond_nominator(130, 1000, vec![61, 71]);
for i in &[10, 20, 30, 40, 50, 60, 70] {
assert_ok!(Staking::set_payee(Origin::signed(*i), RewardDestination::Controller));
}
assert_eq_uvec!(validator_controllers(), vec![40, 30]);
assert_ok!(Staking::set_validator_count(Origin::ROOT, 7));
assert_eq_uvec!(validator_controllers(), vec![10, 60, 40, 20, 50, 30, 70]);
assert_eq!(Staking::stakers(11).total, 3000);
assert_eq!(Staking::stakers(21).total, 2254);
assert_eq!(Staking::stakers(31).total, 2254);
assert_eq!(Staking::stakers(41).total, 1926);
assert_eq!(Staking::stakers(51).total, 1871);
assert_eq!(Staking::stakers(61).total, 1892);
assert_eq!(Staking::stakers(71).total, 1799);
})
}
#[test]
fn phragmen_chooses_correct_number_of_validators() {
with_externalities(&mut ExtBuilder::default()
.nominate(true)
.validator_pool(true)
.validator_count(1)
.build(),
|| {
assert_eq!(Staking::validator_count(), 1);
assert_eq!(validator_controllers().len(), 1);
System::set_block_number(1);
Session::on_initialize(System::block_number());
assert_eq!(validator_controllers().len(), 1);
Kian Peymani
committed
#[test]
fn phragmen_score_should_be_accurate_on_large_stakes() {
with_externalities(&mut ExtBuilder::default()
.nominate(false)
.build(),
|| {
bond_validator(2, u64::max_value());
bond_validator(4, u64::max_value());
bond_validator(6, u64::max_value()-1);
bond_validator(8, u64::max_value()-2);
assert_eq!(validator_controllers(), vec![4, 2]);
Kian Peymani
committed
#[test]
fn phragmen_should_not_overflow_validators() {
with_externalities(&mut ExtBuilder::default()
.nominate(false)
.build(),
|| {
Kian Peymani
committed
let _ = Staking::chill(Origin::signed(10));
let _ = Staking::chill(Origin::signed(20));
bond_validator(2, u64::max_value());
bond_validator(4, u64::max_value());
bond_nominator(6, u64::max_value()/2, vec![3, 5]);
bond_nominator(8, u64::max_value()/2, vec![3, 5]);
Kian Peymani
committed
Kian Peymani
committed
assert_eq_uvec!(validator_controllers(), vec![4, 2]);
// This test will fail this. Will saturate.
// check_exposure_all();
assert_eq!(Staking::stakers(3).total, u64::max_value());
assert_eq!(Staking::stakers(5).total, u64::max_value());
Kian Peymani
committed
})
}
#[test]
fn phragmen_should_not_overflow_nominators() {
with_externalities(&mut ExtBuilder::default()
.nominate(false)
.build(),
|| {
Kian Peymani
committed
let _ = Staking::chill(Origin::signed(10));
let _ = Staking::chill(Origin::signed(20));
bond_validator(2, u64::max_value()/2);
bond_validator(4, u64::max_value()/2);
bond_nominator(6, u64::max_value(), vec![3, 5]);
bond_nominator(8, u64::max_value(), vec![3, 5]);
Kian Peymani
committed
Kian Peymani
committed
assert_eq_uvec!(validator_controllers(), vec![4, 2]);
// Saturate.
assert_eq!(Staking::stakers(3).total, u64::max_value());
assert_eq!(Staking::stakers(5).total, u64::max_value());
Kian Peymani
committed
})
}
#[test]
fn phragmen_should_not_overflow_ultimate() {
with_externalities(&mut ExtBuilder::default()
.nominate(false)
.build(),
|| {
Kian Peymani
committed
bond_validator(2, u64::max_value());
bond_validator(4, u64::max_value());
bond_nominator(6, u64::max_value(), vec![3, 5]);
bond_nominator(8, u64::max_value(), vec![3, 5]);
Kian Peymani
committed
Kian Peymani
committed
assert_eq_uvec!(validator_controllers(), vec![4, 2]);
// Saturate.
assert_eq!(Staking::stakers(3).total, u64::max_value());
assert_eq!(Staking::stakers(5).total, u64::max_value());
Kian Peymani
committed
})
with_externalities(&mut ExtBuilder::default()
.nominate(false)
.minimum_validator_count(1)
.validator_count(20)
.build(),
|| {
let _ = Staking::chill(Origin::signed(10));
let _ = Staking::chill(Origin::signed(20));
let _ = Staking::chill(Origin::signed(30));
let prefix = 200;
bond_validator(prefix + 2, 1);
bond_validator(prefix + 4, 100);
bond_validator(prefix + 6, 1000000);
bond_validator(prefix + 8, 100000000001000);
bond_validator(prefix + 10, 100000000002000);
bond_validator(prefix + 12, 100000000003000);
bond_validator(prefix + 14, 400000000000000);
bond_validator(prefix + 16, 400000000001000);
bond_validator(prefix + 18, 18000000000000000);
bond_validator(prefix + 20, 20000000000000000);
bond_validator(prefix + 22, 500000000000100000);
bond_validator(prefix + 24, 500000000000200000);
bond_nominator(50, 990000000000000000, vec![
prefix + 3,
prefix + 5,
prefix + 7,
prefix + 9,
prefix + 11,