Newer
Older
// This file is part of Substrate.
// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: Apache-2.0
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use sp_runtime::{
assert_eq_error_rate, traits::BadOrigin,
};
assert_ok, assert_noop, StorageMap,
traits::{Currency, ReservableCurrency, OnInitialize, OnFinalize},
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));
// Adds 2 slashing spans
add_slash(&11);
// Cant transfer
assert_noop!(
Balances::transfer(Origin::signed(11), 1, 10),
);
// Force unstake requires root.
assert_noop!(Staking::force_unstake(Origin::signed(11), 11, 2), BadOrigin);
// Force unstake needs correct number of slashing spans (for weight calculation)
assert_noop!(Staking::force_unstake(Origin::root(), 11, 0), Error::<Test>::IncorrectSlashingSpans);
// We now force them to unstake
assert_ok!(Staking::force_unstake(Origin::root(), 11, 2));
// No longer bonded.
assert_eq!(Staking::bonded(&11), None);
// Transfer works.
assert_ok!(Balances::transfer(Origin::signed(11), 1, 10));
});
}
#[test]
fn kill_stash_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));
// Adds 2 slashing spans
add_slash(&11);
// Only can kill a stash account
assert_noop!(Staking::kill_stash(&12, 0), Error::<Test>::NotStash);
// Respects slashing span count
assert_noop!(Staking::kill_stash(&11, 0), Error::<Test>::IncorrectSlashingSpans);
// Correct inputs, everything works
assert_ok!(Staking::kill_stash(&11, 2));
// No longer bonded.
assert_eq!(Staking::bonded(&11), None);
});
}
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));
mock::start_active_era(1);
assert_noop!(
Staking::validate(Origin::signed(10), ValidatorPrefs::default()),
);
assert_ok!(Staking::validate(Origin::signed(5), ValidatorPrefs::default()));
})
}
#[test]
fn rewards_should_work() {
ExtBuilder::default().nominate(true).session_per_era(3).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);
// Set payees
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 of the session.
let total_payout_0 = current_total_payout_for_duration(reward_time_per_era());
let maximum_payout = maximum_payout_for_duration(reward_time_per_era());
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()),
maximum_payout - total_payout_0,
);
assert_eq!(
*mock::staking_events().last().unwrap(),
RawEvent::EraPayout(0, total_payout_0, maximum_payout - total_payout_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(reward_time_per_era());
mock::start_active_era(2);
assert_eq!(
mock::REWARD_REMAINDER_UNBALANCED.with(|v| *v.borrow()),
maximum_payout * 2 - total_payout_0 - total_payout_1,
);
assert_eq!(
*mock::staking_events().last().unwrap(),
RawEvent::EraPayout(1, total_payout_1, maximum_payout - total_payout_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);
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 reserve 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]);
mock::start_active_era(1);
// 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));
mock::start_active_era(1);
// 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() {
ExtBuilder::default()
.nominate(false)
.validator_pool(true)
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
.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(reward_time_per_era());
<Module<Test>>::reward_by_ids(vec![(41, 1)]);
<Module<Test>>::reward_by_ids(vec![(31, 1)]);
mock::start_active_era(1);
// 10 and 20 have more votes, they will be chosen.
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(reward_time_per_era());
<Module<Test>>::reward_by_ids(vec![(21, 2)]);
<Module<Test>>::reward_by_ids(vec![(11, 1)]);
mock::start_active_era(2);
// 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),
);
// 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),
);
// 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,
);
// 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,
fn nominators_also_get_slashed_pro_rata() {
ExtBuilder::default().build_and_execute(|| {
mock::start_active_era(1);
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()),
fn session_and_eras_work_simple() {
ExtBuilder::default().period(1).build_and_execute(|| {
assert_eq!(active_era(), 0);
assert_eq!(current_era(), 0);
assert_eq!(Session::current_index(), 1);
assert_eq!(System::block_number(), 1);
// Session 1: this is basically a noop. This has already been started.
assert_eq!(Session::current_index(), 1);
assert_eq!(active_era(), 0);
assert_eq!(System::block_number(), 1);
assert_eq!(active_era(), 0);
assert_eq!(System::block_number(), 2);
assert_eq!(active_era(), 1);
assert_eq!(System::block_number(), 3);
assert_eq!(Session::current_index(), 4);
assert_eq!(active_era(), 1);
assert_eq!(System::block_number(), 4);
assert_eq!(active_era(), 1);
assert_eq!(System::block_number(), 5);
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
assert_eq!(active_era(), 2);
assert_eq!(System::block_number(), 6);
});
}
#[test]
fn session_and_eras_work_complex() {
ExtBuilder::default().period(5).build_and_execute(|| {
assert_eq!(active_era(), 0);
assert_eq!(Session::current_index(), 0);
assert_eq!(System::block_number(), 1);
start_session(1);
assert_eq!(Session::current_index(), 1);
assert_eq!(active_era(), 0);
assert_eq!(System::block_number(), 5);
start_session(2);
assert_eq!(Session::current_index(), 2);
assert_eq!(active_era(), 0);
assert_eq!(System::block_number(), 10);
start_session(3);
assert_eq!(Session::current_index(), 3);
assert_eq!(active_era(), 1);
assert_eq!(System::block_number(), 15);
start_session(4);
assert_eq!(Session::current_index(), 4);
assert_eq!(active_era(), 1);
assert_eq!(System::block_number(), 20);
start_session(5);
assert_eq!(Session::current_index(), 5);
assert_eq!(active_era(), 1);
assert_eq!(System::block_number(), 25);
start_session(6);
assert_eq!(Session::current_index(), 6);
assert_eq!(active_era(), 2);
assert_eq!(System::block_number(), 30);
#[test]
fn forcing_new_era_works() {
ExtBuilder::default().build_and_execute(|| {
// normal flow of session.
start_session(1);
assert_eq!(active_era(), 0);
assert_eq!(active_era(), 0);
assert_eq!(active_era(), 1);
// no era change.
ForceEra::put(Forcing::ForceNone);
assert_eq!(active_era(), 1);
assert_eq!(active_era(), 1);
assert_eq!(active_era(), 1);
assert_eq!(active_era(), 1);
ForceEra::put(Forcing::NotForcing);
assert_eq!(active_era(), 1);
start_session(9);
assert_eq!(active_era(), 2);
assert_eq!(active_era(), 2);
assert_eq!(active_era(), 3);
assert_eq!(active_era(), 4);
// just one forceful change
ForceEra::put(Forcing::ForceNew);
start_session(13);
assert_eq!(active_era(), 5);
assert_eq!(active_era(), 6);
assert_eq!(active_era(), 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(active_era(), 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 reserve as a result
assert_noop!(
Balances::reserve(&11, 1),
BalancesError::<Test, _>::LiquidityRestrictions,
// 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(reward_time_per_era());
mock::start_active_era(1);
// 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(reward_time_per_era());
mock::start_active_era(2);
// 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(reward_time_per_era());
mock::start_active_era(3);
// Check that RewardDestination is Controller
assert_eq!(Staking::payee(&11), RewardDestination::Controller);
// Check that reward went to the controller account
assert_eq!(Balances::free_balance(10), 1 + total_payout_2);
// Check that amount at stake is NOT increased
assert_eq!(Staking::ledger(&10), Some(StakingLedger {
stash: 11,
total: 1000 + total_payout_0,
active: 1000 + total_payout_0,
// 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::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);
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);