Newer
Older
// 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`.
ExtBuilder::default().build().execute_with(|| {
// 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.
ExtBuilder::default().nominate(false).build().execute_with(|| {
// 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() {
ExtBuilder::default().build().execute_with(|| {
// 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
ExtBuilder::default().nominate(false).fair(false).build().execute_with(|| {
// 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(3000);
assert!(total_payout_0 > 100); // Test is meaningfull if reward something
<Module<Test>>::reward_by_ids(vec![(11, 1)]);
<Module<Test>>::reward_by_ids(vec![(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);
#[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().execute_with(|| {
// 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>>::exists(&10));
assert!(<Bonded<Test>>::exists(&11));
assert!(<Validators<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!(<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!(!<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
ExtBuilder::default().existential_deposit(10).build().execute_with(|| {
// 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!(!<Payee<Test>>::exists(&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().execute_with(|| {
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() {
ExtBuilder::default().nominate(false).validator_pool(true).build().execute_with(|| {
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.
ExtBuilder::default()
.validator_count(3)
.existential_deposit(5)
.nominate(false)
.minimum_validator_count(1)
.build()
.execute_with(|| {
// Can't bond with 1
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);
});
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.
ExtBuilder::default()
.validator_count(3)
.nominate(false)
.minimum_validator_count(1)
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
.build()
.execute_with(|| {
// 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()));
let total_payout_0 = current_total_payout_for_duration(3000);
assert!(total_payout_0 > 100); // Test is meaningfull if reward something
reward_all_elected();
start_era(1);
// 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(3000);
assert!(total_payout_1 > 100); // Test is meaningfull if reward something
reward_all_elected();
start_era(2);
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,
);
check_exposure_all();
check_nominator_all();
});
fn phragmen_linear_worse_case_equalize() {
ExtBuilder::default()
.nominate(false)
.validator_pool(true)
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
.build()
.execute_with(|| {
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));
start_era(1);
assert_eq_uvec!(validator_controllers(), vec![10, 60, 40, 20, 50, 30, 70]);
assert_eq_error_rate!(Staking::stakers(11).total, 3000, 2);
assert_eq_error_rate!(Staking::stakers(21).total, 2255, 2);
assert_eq_error_rate!(Staking::stakers(31).total, 2255, 2);
assert_eq_error_rate!(Staking::stakers(41).total, 1925, 2);
assert_eq_error_rate!(Staking::stakers(51).total, 1870, 2);
assert_eq_error_rate!(Staking::stakers(61).total, 1890, 2);
assert_eq_error_rate!(Staking::stakers(71).total, 1800, 2);
check_exposure_all();
check_nominator_all();
})
fn new_era_elects_correct_number_of_validators() {
ExtBuilder::default()
.nominate(true)
.validator_pool(true)
.build()
.execute_with(|| {
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);
check_exposure_all();
check_nominator_all();
})
Kian Peymani
committed
#[test]
fn phragmen_should_not_overflow_validators() {
ExtBuilder::default().nominate(false).build().execute_with(|| {
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() {
ExtBuilder::default().nominate(false).build().execute_with(|| {
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);
Kian Peymani
committed
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() {
ExtBuilder::default().nominate(false).build().execute_with(|| {
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
})
#[test]
fn reward_validator_slashing_validator_doesnt_overflow() {
ExtBuilder::default().build().execute_with(|| {
let stake = u32::max_value() as u64 * 2;
let reward_slash = u32::max_value() as u64 * 2;
// Assert multiplication overflows in balance arithmetic.
assert!(stake.checked_mul(reward_slash).is_none());
// Set staker
let _ = Balances::make_free_balance_be(&11, stake);
<Stakers<Test>>::insert(&11, Exposure { total: stake, own: stake, others: vec![] });
// Check reward
let _ = Staking::reward_validator(&11, reward_slash);
assert_eq!(Balances::total_balance(&11), stake * 2);
// Set staker
let _ = Balances::make_free_balance_be(&11, stake);
let _ = Balances::make_free_balance_be(&2, stake);
<Stakers<Test>>::insert(&11, Exposure { total: stake, own: 1, others: vec![
IndividualExposure { who: 2, value: stake - 1 }
]});
// Check slashing
let _ = Staking::slash_validator(&11, reward_slash, &Staking::stakers(&11), &mut Vec::new());
assert_eq!(Balances::total_balance(&11), stake - 1);
assert_eq!(Balances::total_balance(&2), 1);
})
}
#[test]
fn reward_from_authorship_event_handler_works() {
ExtBuilder::default().build().execute_with(|| {
use authorship::EventHandler;
assert_eq!(<authorship::Module<Test>>::author(), 11);
<Module<Test>>::note_author(11);
<Module<Test>>::note_uncle(21, 1);
// An uncle author that is not currently elected doesn't get rewards,
// but the block producer does get reward for referencing it.
<Module<Test>>::note_uncle(31, 1);
// Rewarding the same two times works.
<Module<Test>>::note_uncle(11, 1);
// Not mandatory but must be coherent with rewards
assert_eq!(<CurrentElected<Test>>::get(), vec![21, 11]);
// 11 is rewarded as a block producer and uncle referencer and uncle producer
assert_eq!(CurrentEraPointsEarned::get().individual, vec![1, 20 + 2 * 3 + 1]);
assert_eq!(CurrentEraPointsEarned::get().total, 28);
})
}
#[test]
fn add_reward_points_fns_works() {
ExtBuilder::default().build().execute_with(|| {
let validators = <Module<Test>>::current_elected();
// Not mandatory but must be coherent with rewards
assert_eq!(validators, vec![21, 11]);
<Module<Test>>::reward_by_indices(vec![
(0, 1),
(1, 1),
(2, 1),
(1, 1),
]);
<Module<Test>>::reward_by_ids(vec![
(21, 1),
(11, 1),
(31, 1),
(11, 1),
]);
assert_eq!(CurrentEraPointsEarned::get().individual, vec![2, 4]);
assert_eq!(CurrentEraPointsEarned::get().total, 6);
#[test]
fn unbonded_balance_is_not_slashable() {
ExtBuilder::default().build().execute_with(|| {
// total amount staked is slashable.
assert_eq!(Staking::slashable_balance_of(&11), 1000);
assert_ok!(Staking::unbond(Origin::signed(10), 800));
// only the active portion.
assert_eq!(Staking::slashable_balance_of(&11), 200);
})
}
#[test]
fn era_is_always_same_length() {
// This ensures that the sessions is always of the same length if there is no forcing no
// session changes.
ExtBuilder::default().build().execute_with(|| {
start_era(1);
assert_eq!(Staking::current_era_start_session_index(), SessionsPerEra::get());
start_era(2);
assert_eq!(Staking::current_era_start_session_index(), SessionsPerEra::get() * 2);
let session = Session::current_index();
ForceEra::put(Forcing::ForceNew);
advance_session();
assert_eq!(Staking::current_era(), 3);
assert_eq!(Staking::current_era_start_session_index(), session + 1);
start_era(4);
assert_eq!(Staking::current_era_start_session_index(), session + SessionsPerEra::get() + 1);
});
}
#[test]
fn offence_forces_new_era() {
ExtBuilder::default().build().execute_with(|| {
Staking::on_offence(
&[OffenceDetails {
offender: (
11,
Staking::stakers(&11),
),
reporters: vec![],
}],
&[Perbill::from_percent(5)],
);
assert_eq!(Staking::force_era(), Forcing::ForceNew);
});
}
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
#[test]
fn offence_ensures_new_era_without_clobbering() {
ExtBuilder::default().build().execute_with(|| {
assert_ok!(Staking::force_new_era_always(Origin::ROOT));
Staking::on_offence(
&[OffenceDetails {
offender: (
11,
Staking::stakers(&11),
),
reporters: vec![],
}],
&[Perbill::from_percent(5)],
);
assert_eq!(Staking::force_era(), Forcing::ForceAlways);
});
}
#[test]
fn offence_deselects_validator_when_slash_is_zero() {
ExtBuilder::default().build().execute_with(|| {
assert!(<Validators<Test>>::exists(11));
Staking::on_offence(
&[OffenceDetails {
offender: (
11,
Staking::stakers(&11),
),
reporters: vec![],
}],
&[Perbill::from_percent(0)],
);
assert_eq!(Staking::force_era(), Forcing::ForceNew);
assert!(!<Validators<Test>>::exists(11));
});
}
#[test]
fn slashing_performed_according_exposure() {
// This test checks that slashing is performed according the exposure (or more precisely,
// historical exposure), not the current balance.
ExtBuilder::default().build().execute_with(|| {
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
assert_eq!(Staking::stakers(&11).own, 1000);
// Handle an offence with a historical exposure.
Staking::on_offence(
&[OffenceDetails {
offender: (
11,
Exposure {
total: 500,
own: 500,
others: vec![],
},
),
reporters: vec![],
}],
&[Perbill::from_percent(50)],
);
// The stash account should be slashed for 250 (50% of 500).
assert_eq!(Balances::free_balance(&11), 1000 - 250);
});
}
#[test]
fn reporters_receive_their_slice() {
// This test verifies that the reporters of the offence receive their slice from the slashed
// amount.
ExtBuilder::default().build().execute_with(|| {
// The reporters' reward is calculated from the total exposure.
#[cfg(feature = "equalize")]
let initial_balance = 1250;
#[cfg(not(feature = "equalize"))]
let initial_balance = 1125;
assert_eq!(Staking::stakers(&11).total, initial_balance);
Staking::on_offence(
&[OffenceDetails {
offender: (
11,
Staking::stakers(&11),
),
reporters: vec![1, 2],
}],
&[Perbill::from_percent(50)],
);
// initial_balance x 50% (slash fraction) x 10% (rewards slice)
let reward = initial_balance / 20 / 2;
assert_eq!(Balances::free_balance(&1), 10 + reward);
assert_eq!(Balances::free_balance(&2), 20 + reward);
});
}
#[test]
fn invulnerables_are_not_slashed() {
// For invulnerable validators no slashing is performed.
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
ExtBuilder::default().invulnerables(vec![11]).build().execute_with(|| {
#[cfg(feature = "equalize")]
let initial_balance = 1250;
#[cfg(not(feature = "equalize"))]
let initial_balance = 1375;
assert_eq!(Balances::free_balance(&11), 1000);
assert_eq!(Balances::free_balance(&21), 2000);
assert_eq!(Staking::stakers(&21).total, initial_balance);
Staking::on_offence(
&[
OffenceDetails {
offender: (11, Staking::stakers(&11)),
reporters: vec![],
},
OffenceDetails {
offender: (21, Staking::stakers(&21)),
reporters: vec![],
},
],
&[Perbill::from_percent(50), Perbill::from_percent(20)],
);
// The validator 11 hasn't been slashed, but 21 has been.
assert_eq!(Balances::free_balance(&11), 1000);
// 2000 - (0.2 * initial_balance)
assert_eq!(Balances::free_balance(&21), 2000 - (2 * initial_balance / 10));
});
}
#[test]
fn dont_slash_if_fraction_is_zero() {
// Don't slash if the fraction is zero.
ExtBuilder::default().build().execute_with(|| {
assert_eq!(Balances::free_balance(&11), 1000);
Staking::on_offence(
&[OffenceDetails {
offender: (
11,
Staking::stakers(&11),
),
reporters: vec![],
}],
&[Perbill::from_percent(0)],
);
// The validator hasn't been slashed. The new era is not forced.
assert_eq!(Balances::free_balance(&11), 1000);
});
}