Newer
Older
// Copyright 2017-2020 Parity Technologies (UK) Ltd.
// This file is part of Substrate.
// Substrate is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Substrate is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
use sp_runtime::{
assert_eq_error_rate, traits::BadOrigin,
};
assert_ok, assert_noop, StorageMap,
thiolliere
committed
traits::{Currency, ReservableCurrency, OnInitialize},
Benjamin Kampmann
committed
use substrate_test_utils::assert_eq_uvec;
#[test]
fn force_unstake_works() {
ExtBuilder::default().build_and_execute(|| {
// Account 11 is stashed and locked, and account 10 is the controller
assert_eq!(Staking::bonded(&11), Some(10));
// Cant transfer
assert_noop!(
Balances::transfer(Origin::signed(11), 1, 10),
);
// Force unstake requires root.
assert_noop!(Staking::force_unstake(Origin::signed(11), 11), BadOrigin);
// We now force them to unstake
assert_ok!(Staking::force_unstake(Origin::ROOT, 11));
// No longer bonded.
assert_eq!(Staking::bonded(&11), None);
// Transfer works.
assert_ok!(Balances::transfer(Origin::signed(11), 1, 10));
});
}
fn basic_setup_works() {
// Verifies initial conditions of mock
ExtBuilder::default().build_and_execute(|| {
// Account 11 is stashed and locked, and account 10 is the controller
assert_eq!(Staking::bonded(&11), Some(10));
// Account 21 is stashed and locked, and account 20 is the controller
assert_eq!(Staking::bonded(&21), Some(20));
// Account 1 is not a stashed
assert_eq!(Staking::bonded(&1), None);
// Account 10 controls the stash from account 11, which is 100 * balance_factor units
assert_eq!(
Staking::ledger(&10),
Some(StakingLedger { stash: 11, total: 1000, active: 1000, unlocking: vec![], claimed_rewards: vec![] })
// Account 20 controls the stash from account 21, which is 200 * balance_factor units
assert_eq!(
Staking::ledger(&20),
Some(StakingLedger { stash: 21, total: 1000, active: 1000, unlocking: vec![], claimed_rewards: vec![] })
// Account 1 does not control any stash
assert_eq!(Staking::ledger(&1), None);
assert_eq_uvec!(<Validators<Test>>::iter().collect::<Vec<_>>(), vec![
(31, ValidatorPrefs::default()),
(21, ValidatorPrefs::default()),
(11, ValidatorPrefs::default())
assert_eq!(
Staking::ledger(100),
Some(StakingLedger { stash: 101, total: 500, active: 500, unlocking: vec![], claimed_rewards: vec![] })
assert_eq!(Staking::nominators(101).unwrap().targets, vec![11, 21]);
Staking::eras_stakers(Staking::active_era().unwrap().index, 11),
Exposure {
total: 1125,
own: 1000,
others: vec![ IndividualExposure { who: 101, value: 125 }]
},
Staking::eras_stakers(Staking::active_era().unwrap().index, 21),
Exposure {
total: 1375,
own: 1000,
others: vec![ IndividualExposure { who: 101, value: 375 }]
},
// initial total stake = 1125 + 1375
assert_eq!(Staking::eras_total_stake(Staking::active_era().unwrap().index), 2500);
// The number of validators required.
assert_eq!(Staking::validator_count(), 2);
// Initial Era and session
// Account 10 has `balance_factor` free balance
assert_eq!(Balances::free_balance(10), 1);
assert_eq!(Balances::free_balance(10), 1);
assert_eq!(Staking::force_era(), Forcing::NotForcing);
#[test]
fn change_controller_works() {
ExtBuilder::default().build_and_execute(|| {
// 10 and 11 are bonded as stash controller.
assert_eq!(Staking::bonded(&11), Some(10));
// 10 can control 11 who is initially a validator.
assert_ok!(Staking::chill(Origin::signed(10)));
assert_ok!(Staking::set_controller(Origin::signed(11), 5));
assert_eq!(Staking::bonded(&11), Some(5));
assert_noop!(
Staking::validate(Origin::signed(10), ValidatorPrefs::default()),
);
assert_ok!(Staking::validate(Origin::signed(5), ValidatorPrefs::default()));
})
}
#[test]
fn rewards_should_work() {
// should check that:
// * rewards get recorded per session
// * rewards get paid per Era
// * `RewardRemainder::on_unbalanced` is called
// * Check that nominators are also rewarded
ExtBuilder::default().nominate(true).build_and_execute(|| {
let init_balance_10 = Balances::total_balance(&10);
let init_balance_11 = Balances::total_balance(&11);
let init_balance_20 = Balances::total_balance(&20);
let init_balance_21 = Balances::total_balance(&21);
let init_balance_100 = Balances::total_balance(&100);
let init_balance_101 = Balances::total_balance(&101);
// Check state
Payee::<Test>::insert(11, RewardDestination::Controller);
Payee::<Test>::insert(21, RewardDestination::Controller);
Payee::<Test>::insert(101, RewardDestination::Controller);
<Module<Test>>::reward_by_ids(vec![(11, 50)]);
<Module<Test>>::reward_by_ids(vec![(11, 50)]);
// This is the second validator of the current elected set.
<Module<Test>>::reward_by_ids(vec![(21, 50)]);
// Compute total payout now for whole duration as other parameter won't change
let total_payout_0 = current_total_payout_for_duration(3 * 1000);
assert!(total_payout_0 > 10); // Test is meaningful if reward something
assert_eq!(Balances::total_balance(&10), init_balance_10);
assert_eq!(Balances::total_balance(&11), init_balance_11);
assert_eq!(Balances::total_balance(&20), init_balance_20);
assert_eq!(Balances::total_balance(&21), init_balance_21);
assert_eq!(Balances::total_balance(&100), init_balance_100);
assert_eq!(Balances::total_balance(&101), init_balance_101);
assert_eq_uvec!(Session::validators(), vec![11, 21]);
assert_eq!(Staking::eras_reward_points(Staking::active_era().unwrap().index), EraRewardPoints {
total: 50*3,
individual: vec![(11, 100), (21, 50)].into_iter().collect(),
});
let part_for_10 = Perbill::from_rational_approximation::<u32>(1000, 1125);
let part_for_20 = Perbill::from_rational_approximation::<u32>(1000, 1375);
let part_for_100_from_10 = Perbill::from_rational_approximation::<u32>(125, 1125);
let part_for_100_from_20 = Perbill::from_rational_approximation::<u32>(375, 1375);
assert_eq!(mock::REWARD_REMAINDER_UNBALANCED.with(|v| *v.borrow()), 7050);
assert_eq!(*mock::staking_events().last().unwrap(), RawEvent::EraPayout(0, 2350, 7050));
mock::make_all_reward_payment(0);
assert_eq_error_rate!(Balances::total_balance(&10), init_balance_10 + part_for_10 * total_payout_0*2/3, 2);
assert_eq_error_rate!(Balances::total_balance(&11), init_balance_11, 2);
assert_eq_error_rate!(Balances::total_balance(&20), init_balance_20 + part_for_20 * total_payout_0*1/3, 2);
assert_eq_error_rate!(Balances::total_balance(&21), init_balance_21, 2);
assert_eq_error_rate!(
Balances::total_balance(&100),
init_balance_100
+ part_for_100_from_10 * total_payout_0 * 2/3
+ part_for_100_from_20 * total_payout_0 * 1/3,
2
);
assert_eq_error_rate!(Balances::total_balance(&101), init_balance_101, 2);
assert_eq_uvec!(Session::validators(), vec![11, 21]);
<Module<Test>>::reward_by_ids(vec![(11, 1)]);
// Compute total payout now for whole duration as other parameter won't change
let total_payout_1 = current_total_payout_for_duration(3 * 1000);
assert!(total_payout_1 > 10); // Test is meaningful if reward something
assert_eq!(mock::REWARD_REMAINDER_UNBALANCED.with(|v| *v.borrow()), 7050*2);
assert_eq!(*mock::staking_events().last().unwrap(), RawEvent::EraPayout(1, 2350, 7050));
mock::make_all_reward_payment(1);
assert_eq_error_rate!(Balances::total_balance(&10), init_balance_10 + part_for_10 * (total_payout_0 * 2/3 + total_payout_1), 2);
assert_eq_error_rate!(Balances::total_balance(&11), init_balance_11, 2);
assert_eq_error_rate!(Balances::total_balance(&20), init_balance_20 + part_for_20 * total_payout_0 * 1/3, 2);
assert_eq_error_rate!(Balances::total_balance(&21), init_balance_21, 2);
assert_eq_error_rate!(
Balances::total_balance(&100),
init_balance_100
+ part_for_100_from_10 * (total_payout_0 * 2/3 + total_payout_1)
+ part_for_100_from_20 * total_payout_0 * 1/3,
2
);
assert_eq_error_rate!(Balances::total_balance(&101), init_balance_101, 2);
// * new validators can be added to the default set
// * new ones will be chosen per era
// * either one can unlock the stash and back-down from being a validator via `chill`ing.
ExtBuilder::default()
.fair(false) // to give 20 more staked value
.build()
.execute_with(|| {
// remember + compare this along with the test.
assert_eq_uvec!(validator_controllers(), vec![20, 10]);
// put some money in account that we'll use.
for i in 1..5 { let _ = Balances::make_free_balance_be(&i, 2000); }
// add a new candidate for being a validator. account 3 controlled by 4.
assert_ok!(Staking::bond(Origin::signed(3), 4, 1500, RewardDestination::Controller));
assert_ok!(Staking::validate(Origin::signed(4), ValidatorPrefs::default()));
// No effects will be seen so far.
assert_eq_uvec!(validator_controllers(), vec![20, 10]);
// No effects will be seen so far. Era has not been yet triggered.
assert_eq_uvec!(validator_controllers(), vec![20, 10]);
assert_eq!(Staking::active_era().unwrap().index, 1);
// --- Block 5: the validators are still in queue.
start_session(5);
// --- Block 6: the validators will now be changed.
start_session(6);
assert_eq_uvec!(validator_controllers(), vec![20, 4]);
// --- Block 6: Unstake 4 as a validator, freeing up the balance stashed in 3
// 4 will chill
Staking::chill(Origin::signed(4)).unwrap();
// --- Block 7: nothing. 4 is still there.
start_session(7);
assert_eq_uvec!(validator_controllers(), vec![20, 4]);
// --- Block 8:
start_session(8);
// --- Block 9: 4 will not be a validator.
start_session(9);
assert_eq_uvec!(validator_controllers(), vec![20, 10]);
// Note: the stashed value of 4 is still lock
assert_eq!(
Staking::ledger(&4),
Some(StakingLedger {
stash: 3,
total: 1500,
active: 1500,
unlocking: vec![],
);
// e.g. it cannot spend more than 500 that it has free from the total 2000
assert_noop!(
Balances::reserve(&3, 501),
assert_ok!(Balances::reserve(&3, 409));
});
#[test]
fn less_than_needed_candidates_works() {
ExtBuilder::default()
.build()
.execute_with(|| {
assert_eq!(Staking::validator_count(), 4);
assert_eq!(Staking::minimum_validator_count(), 1);
assert_eq_uvec!(validator_controllers(), vec![30, 20, 10]);
// Previous set is selected. NO election algorithm is even executed.
assert_eq_uvec!(validator_controllers(), vec![30, 20, 10]);
// But the exposure is updated in a simple way. No external votes exists.
// This is purely self-vote.
ErasStakers::<Test>::iter_prefix_values(Staking::active_era().unwrap().index)
}
#[test]
fn no_candidate_emergency_condition() {
ExtBuilder::default()
.build()
.execute_with(|| {
// initial validators
assert_eq_uvec!(validator_controllers(), vec![10, 20, 30, 40]);
let prefs = ValidatorPrefs { commission: Perbill::one() };
<Staking as crate::Store>::Validators::insert(11, prefs.clone());
// set the minimum validator count.
<Staking as crate::Store>::MinimumValidatorCount::put(10);
let _ = Staking::chill(Origin::signed(10));
// Previous ones are elected. chill is invalidates. TODO: #2494
assert_eq_uvec!(validator_controllers(), vec![10, 20, 30, 40]);
// Though the validator preferences has been removed.
assert!(Staking::validators(11) != prefs);
#[test]
fn nominating_and_rewards_should_work() {
// PHRAGMEN OUTPUT: running this test with the reference impl gives:
//
// Sequential Phragmén gives
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
// 10 is elected with stake 2200.0 and score 0.0003333333333333333
// 20 is elected with stake 1800.0 and score 0.0005555555555555556
// 10 has load 0.0003333333333333333 and supported
// 10 with stake 1000.0
// 20 has load 0.0005555555555555556 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.0005555555555555556 and supported
// 10 with stake 600.0 20 with stake 400.0 30 with stake 0.0
// 4 has load 0.0005555555555555556 and supported
// 10 with stake 600.0 20 with stake 400.0 40 with stake 0.0
// Sequential Phragmén with post processing gives
// 10 is elected with stake 2000.0 and score 0.0003333333333333333
// 20 is elected with stake 2000.0 and score 0.0005555555555555556
// 10 has load 0.0003333333333333333 and supported
// 10 with stake 1000.0
// 20 has load 0.0005555555555555556 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.0005555555555555556 and supported
// 10 with stake 400.0 20 with stake 600.0 30 with stake 0
// 4 has load 0.0005555555555555556 and supported
// 10 with stake 600.0 20 with stake 400.0 40 with stake 0.0
ExtBuilder::default()
.nominate(false)
.validator_pool(true)
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
.build()
.execute_with(|| {
// initial validators -- everyone is actually even.
assert_eq_uvec!(validator_controllers(), vec![40, 30]);
// Set payee 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));
// give the man some money
let initial_balance = 1000;
for i in [1, 2, 3, 4, 5, 10, 11, 20, 21].iter() {
let _ = Balances::make_free_balance_be(i, initial_balance);
}
// bond two account pairs and state interest in nomination.
// 2 will nominate for 10, 20, 30
assert_ok!(Staking::bond(Origin::signed(1), 2, 1000, RewardDestination::Controller));
assert_ok!(Staking::nominate(Origin::signed(2), vec![11, 21, 31]));
// 4 will nominate for 10, 20, 40
assert_ok!(Staking::bond(Origin::signed(3), 4, 1000, RewardDestination::Controller));
assert_ok!(Staking::nominate(Origin::signed(4), vec![11, 21, 41]));
// the total reward for era 0
let total_payout_0 = current_total_payout_for_duration(3000);
assert!(total_payout_0 > 100); // Test is meaningful if reward something
<Module<Test>>::reward_by_ids(vec![(41, 1)]);
<Module<Test>>::reward_by_ids(vec![(31, 1)]);
// 10 and 20 have more votes, they will be chosen by phragmen.
assert_eq_uvec!(validator_controllers(), vec![20, 10]);
// OLD validators must have already received some rewards.
assert_eq!(Balances::total_balance(&40), 1 + total_payout_0 / 2);
assert_eq!(Balances::total_balance(&30), 1 + total_payout_0 / 2);
// ------ check the staked value of all parties.
assert_eq!(ErasStakers::<Test>::iter_prefix_values(Staking::active_era().unwrap().index).count(), 2);
Staking::eras_stakers(Staking::active_era().unwrap().index, 11),
Exposure {
total: 1000 + 800,
own: 1000,
others: vec![
IndividualExposure { who: 3, value: 400 },
IndividualExposure { who: 1, value: 400 },
]
},
Staking::eras_stakers(Staking::active_era().unwrap().index, 21),
Exposure {
total: 1000 + 1200,
own: 1000,
others: vec![
IndividualExposure { who: 3, value: 600 },
IndividualExposure { who: 1, value: 600 },
]
},
// the total reward for era 1
let total_payout_1 = current_total_payout_for_duration(3000);
assert!(total_payout_1 > 100); // Test is meaningful if reward something
<Module<Test>>::reward_by_ids(vec![(21, 2)]);
<Module<Test>>::reward_by_ids(vec![(11, 1)]);
// nothing else will happen, era ends and rewards are paid again,
// it is expected that nominators will also be paid. See below
let payout_for_10 = total_payout_1 / 3;
let payout_for_20 = 2 * total_payout_1 / 3;
// Nominator 2: has [400/1800 ~ 2/9 from 10] + [600/2200 ~ 3/11 from 20]'s reward. ==> 2/9 + 3/11
assert_eq_error_rate!(
Balances::total_balance(&2),
initial_balance + (2 * payout_for_10 / 9 + 3 * payout_for_20 / 11),
1,
);
// Nominator 4: has [400/1800 ~ 2/9 from 10] + [600/2200 ~ 3/11 from 20]'s reward. ==> 2/9 + 3/11
assert_eq_error_rate!(
Balances::total_balance(&4),
initial_balance + (2 * payout_for_10 / 9 + 3 * payout_for_20 / 11),
1,
);
// Validator 10: got 800 / 1800 external stake => 8/18 =? 4/9 => Validator's share = 5/9
assert_eq_error_rate!(
Balances::total_balance(&10),
initial_balance + 5 * payout_for_10 / 9,
1,
);
// Validator 20: got 1200 / 2200 external stake => 12/22 =? 6/11 => Validator's share = 5/11
assert_eq_error_rate!(
Balances::total_balance(&20),
initial_balance + 5 * payout_for_20 / 11,
1,
);
fn nominators_also_get_slashed_pro_rata() {
ExtBuilder::default().build_and_execute(|| {
let slash_percent = Perbill::from_percent(5);
let initial_exposure = Staking::eras_stakers(active_era(), 11);
// 101 is a nominator for 11
assert_eq!(
initial_exposure.others.first().unwrap().who,
101,
);
// staked values;
let nominator_stake = Staking::ledger(100).unwrap().active;
let nominator_balance = balances(&101).0;
let validator_stake = Staking::ledger(10).unwrap().active;
let validator_balance = balances(&11).0;
let exposed_stake = initial_exposure.total;
let exposed_validator = initial_exposure.own;
let exposed_nominator = initial_exposure.others.first().unwrap().value;
&[OffenceDetails {
offender: (
11,
),
reporters: vec![],
}],
// both stakes must have been decreased.
assert!(Staking::ledger(100).unwrap().active < nominator_stake);
assert!(Staking::ledger(10).unwrap().active < validator_stake);
let slash_amount = slash_percent * exposed_stake;
let validator_share =
Perbill::from_rational_approximation(exposed_validator, exposed_stake) * slash_amount;
let nominator_share = Perbill::from_rational_approximation(
exposed_nominator,
exposed_stake,
) * slash_amount;
// both slash amounts need to be positive for the test to make sense.
assert!(validator_share > 0);
assert!(nominator_share > 0);
// both stakes must have been decreased pro-rata.
assert_eq!(
Staking::ledger(100).unwrap().active,
nominator_stake - nominator_share,
);
assert_eq!(
Staking::ledger(10).unwrap().active,
validator_stake - validator_share,
);
assert_eq!(
balances(&101).0, // free balance
nominator_balance - nominator_share,
);
assert_eq!(
balances(&11).0, // free balance
validator_balance - validator_share,
);
});
}
#[test]
fn double_staking_should_fail() {
// should test (in the same order):
// * an account already bonded as stash cannot be be stashed again.
// * an account already bonded as stash cannot nominate.
// * an account already bonded as controller can nominate.
ExtBuilder::default().build_and_execute(|| {
let arbitrary_value = 5;
// 2 = controller, 1 stashed => ok
assert_ok!(
Staking::bond(Origin::signed(1), 2, arbitrary_value,
RewardDestination::default())
);
// 4 = not used so far, 1 stashed => not allowed.
assert_noop!(
Staking::bond(Origin::signed(1), 4, arbitrary_value,
RewardDestination::default()), Error::<Test>::AlreadyBonded,
);
// 1 = stashed => attempting to nominate should fail.
assert_noop!(Staking::nominate(Origin::signed(1), vec![1]), Error::<Test>::NotController);
// 2 = controller => nominating should work.
assert_ok!(Staking::nominate(Origin::signed(2), vec![1]));
});
}
#[test]
fn double_controlling_should_fail() {
// should test (in the same order):
// * an account already bonded as controller CANNOT be reused as the controller of another account.
ExtBuilder::default().build_and_execute(|| {
let arbitrary_value = 5;
// 2 = controller, 1 stashed => ok
assert_ok!(Staking::bond(
Origin::signed(1),
2,
arbitrary_value,
RewardDestination::default(),
));
// 2 = controller, 3 stashed (Note that 2 is reused.) => no-op
assert_noop!(
Staking::bond(Origin::signed(3), 2, arbitrary_value, RewardDestination::default()),
ExtBuilder::default().build_and_execute(|| {
assert_eq!(Session::current_index(), 0);
assert_eq!(Session::current_index(), 1);
assert_eq!(Session::current_index(), 2);
assert_eq!(Staking::active_era().unwrap().index, 0);
assert_eq!(Session::current_index(), 3);
assert_eq!(Staking::active_era().unwrap().index, 1);
assert_eq!(Session::current_index(), 4);
assert_eq!(Session::current_index(), 5);
assert_eq!(Staking::active_era().unwrap().index, 1);
assert_eq!(Session::current_index(), 6);
assert_eq!(Staking::active_era().unwrap().index, 2);
#[test]
fn forcing_new_era_works() {
ExtBuilder::default().build_and_execute(|| {
// normal flow of session.
assert_eq!(Staking::active_era().unwrap().index, 0);
start_session(3);
assert_eq!(Staking::active_era().unwrap().index, 1);
// no era change.
ForceEra::put(Forcing::ForceNone);
start_session(4);
assert_eq!(Staking::active_era().unwrap().index, 1);
start_session(7);
assert_eq!(Staking::active_era().unwrap().index, 1);
ForceEra::put(Forcing::NotForcing);
start_session(8);
assert_eq!(Staking::active_era().unwrap().index, 1); // There is one session delay
start_session(9);
assert_eq!(Staking::active_era().unwrap().index, 2);
ForceEra::put(Forcing::ForceAlways);
start_session(10);
assert_eq!(Staking::active_era().unwrap().index, 2); // There is one session delay
assert_eq!(Staking::active_era().unwrap().index, 3);
start_session(12);
assert_eq!(Staking::active_era().unwrap().index, 4);
// just one forceful change
ForceEra::put(Forcing::ForceNew);
start_session(13);
assert_eq!(Staking::active_era().unwrap().index, 5);
assert_eq!(ForceEra::get(), Forcing::NotForcing);
start_session(14);
assert_eq!(Staking::active_era().unwrap().index, 6);
start_session(15);
assert_eq!(Staking::active_era().unwrap().index, 6);
fn cannot_transfer_staked_balance() {
// Tests that a stash account cannot transfer funds
ExtBuilder::default().nominate(false).build_and_execute(|| {
// Confirm account 11 is stashed
assert_eq!(Staking::bonded(&11), Some(10));
// Confirm account 11 has some free balance
assert_eq!(Balances::free_balance(11), 1000);
// Confirm account 11 (via controller 10) is totally staked
assert_eq!(Staking::eras_stakers(Staking::active_era().unwrap().index, 11).total, 1000);
// Confirm account 11 cannot transfer as a result
assert_noop!(
Balances::transfer(Origin::signed(11), 20, 1),
// Give account 11 extra free balance
let _ = Balances::make_free_balance_be(&11, 10000);
// Confirm that account 11 can now transfer some balance
assert_ok!(Balances::transfer(Origin::signed(11), 20, 1));
#[test]
fn cannot_transfer_staked_balance_2() {
// Tests that a stash account cannot transfer funds
// Same test as above but with 20, and more accurate.
// 21 has 2000 free balance but 1000 at stake
ExtBuilder::default().nominate(false).fair(true).build_and_execute(|| {
// Confirm account 21 is stashed
assert_eq!(Staking::bonded(&21), Some(20));
// Confirm account 21 has some free balance
assert_eq!(Balances::free_balance(21), 2000);
// Confirm account 21 (via controller 20) is totally staked
assert_eq!(Staking::eras_stakers(Staking::active_era().unwrap().index, 21).total, 1000);
// Confirm account 21 can transfer at most 1000
assert_noop!(
Balances::transfer(Origin::signed(21), 20, 1001),
assert_ok!(Balances::transfer(Origin::signed(21), 20, 1000));
});
}
fn cannot_reserve_staked_balance() {
// Checks that a bonded account cannot reserve balance from free balance
ExtBuilder::default().build_and_execute(|| {
// Confirm account 11 is stashed
assert_eq!(Staking::bonded(&11), Some(10));
// Confirm account 11 has some free balance
assert_eq!(Balances::free_balance(11), 1000);
// Confirm account 11 (via controller 10) is totally staked
assert_eq!(Staking::eras_stakers(Staking::active_era().unwrap().index, 11).own, 1000);
// Confirm account 11 cannot transfer as a result
assert_noop!(
Balances::reserve(&11, 1),
// Give account 11 extra free balance
let _ = Balances::make_free_balance_be(&11, 10000);
// Confirm account 11 can now reserve balance
assert_ok!(Balances::reserve(&11, 1));
#[test]
fn reward_destination_works() {
// Rewards go to the correct destination as determined in Payee
ExtBuilder::default().nominate(false).build_and_execute(|| {
// Check that account 11 is a validator
// Check the balance of the validator account
assert_eq!(Balances::free_balance(10), 1);
// Check the balance of the stash account
assert_eq!(Balances::free_balance(11), 1000);
assert_eq!(Staking::ledger(&10), Some(StakingLedger {
stash: 11,
total: 1000,
active: 1000,
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 meaningful if reward something
// Check that RewardDestination is Staked (default)
assert_eq!(Staking::payee(&11), RewardDestination::Staked);
// Check that reward went to the stash account of validator
assert_eq!(Balances::free_balance(11), 1000 + total_payout_0);
// Check that amount at stake increased accordingly
assert_eq!(Staking::ledger(&10), Some(StakingLedger {
stash: 11,
total: 1000 + total_payout_0,
active: 1000 + total_payout_0,
//Change RewardDestination to Stash
<Payee<Test>>::insert(&11, RewardDestination::Stash);
// Compute total payout now for whole duration as other parameter won't change
let total_payout_1 = current_total_payout_for_duration(3000);
assert!(total_payout_1 > 100); // Test is meaningful if reward something
// Check that RewardDestination is Stash
assert_eq!(Staking::payee(&11), RewardDestination::Stash);
// Check that reward went to the stash account
assert_eq!(Balances::free_balance(11), 1000 + total_payout_0 + total_payout_1);
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);
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(3000);
assert!(total_payout_2 > 100); // Test is meaningful if reward something
// 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.
ExtBuilder::default().build_and_execute(|| {
<Validators<Test>>::insert(&11, ValidatorPrefs {
// Reward controller so staked ratio doesn't change.
<Payee<Test>>::insert(&11, RewardDestination::Controller);
<Payee<Test>>::insert(&101, RewardDestination::Controller);
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(3000);
assert!(total_payout_1 > 100); // Test is meaningful if reward something
let exposure_1 = Staking::eras_stakers(Staking::active_era().unwrap().index, 11);
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![],
// 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), 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![],
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.