Newer
Older
// This file is part of Substrate.
// Copyright (C) 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.
Ankan
committed
use super::{ConfigOp, Event, *};
use frame_election_provider_support::{
bounds::{DataProviderBounds, ElectionBoundsBuilder},
ElectionProvider, SortedListProvider, Support,
};
assert_noop, assert_ok, assert_storage_noop,
dispatch::{extract_actual_weight, GetDispatchInfo, WithPostDispatchInfo},
pallet_prelude::*,
traits::{Currency, Get, ReservableCurrency},
use pallet_balances::Error as BalancesError;
assert_eq_error_rate, bounded_vec,
traits::{BadOrigin, Dispatchable},
Gavin Wood
committed
Perbill, Percent, Rounding, TokenError,
use sp_staking::{
offence::{DisableStrategy, OffenceDetails, OnOffenceHandler},
SessionIndex,
};
use sp_std::prelude::*;
Benjamin Kampmann
committed
use substrate_test_utils::assert_eq_uvec;
#[test]
fn set_staking_configs_works() {
ExtBuilder::default().build_and_execute(|| {
// setting works
assert_ok!(Staking::set_staking_configs(
ConfigOp::Set(1_500),
ConfigOp::Set(2_000),
ConfigOp::Set(10),
ConfigOp::Set(20),
ConfigOp::Set(Percent::from_percent(75)),
ConfigOp::Set(Zero::zero())
));
assert_eq!(MinNominatorBond::<Test>::get(), 1_500);
assert_eq!(MinValidatorBond::<Test>::get(), 2_000);
assert_eq!(MaxNominatorsCount::<Test>::get(), Some(10));
assert_eq!(MaxValidatorsCount::<Test>::get(), Some(20));
assert_eq!(ChillThreshold::<Test>::get(), Some(Percent::from_percent(75)));
assert_eq!(MinCommission::<Test>::get(), Perbill::from_percent(0));
// noop does nothing
assert_storage_noop!(assert_ok!(Staking::set_staking_configs(
ConfigOp::Noop,
ConfigOp::Noop,
ConfigOp::Noop,
ConfigOp::Noop,
ConfigOp::Noop,
ConfigOp::Noop
)));
// removing works
assert_ok!(Staking::set_staking_configs(
ConfigOp::Remove,
ConfigOp::Remove,
ConfigOp::Remove,
ConfigOp::Remove,
ConfigOp::Remove,
ConfigOp::Remove
));
assert_eq!(MinNominatorBond::<Test>::get(), 0);
assert_eq!(MinValidatorBond::<Test>::get(), 0);
assert_eq!(MaxNominatorsCount::<Test>::get(), None);
assert_eq!(MaxValidatorsCount::<Test>::get(), None);
assert_eq!(ChillThreshold::<Test>::get(), None);
assert_eq!(MinCommission::<Test>::get(), Perbill::from_percent(0));
});
}
#[test]
fn force_unstake_works() {
ExtBuilder::default().build_and_execute(|| {
// Account 11 (also controller) is stashed and locked
assert_eq!(Staking::bonded(&11), Some(11));
// Adds 2 slashing spans
add_slash(&11);
// Cant transfer
assert_noop!(
Gavin Wood
committed
Balances::transfer_allow_death(RuntimeOrigin::signed(11), 1, 10),
TokenError::Frozen,
);
// Force unstake requires root.
assert_noop!(Staking::force_unstake(RuntimeOrigin::signed(11), 11, 2), BadOrigin);
// Force unstake needs correct number of slashing spans (for weight calculation)
Staking::force_unstake(RuntimeOrigin::root(), 11, 0),
Error::<Test>::IncorrectSlashingSpans
);
// We now force them to unstake
assert_ok!(Staking::force_unstake(RuntimeOrigin::root(), 11, 2));
// No longer bonded.
assert_eq!(Staking::bonded(&11), None);
// Transfer works.
Gavin Wood
committed
assert_ok!(Balances::transfer_allow_death(RuntimeOrigin::signed(11), 1, 10));
#[test]
fn kill_stash_works() {
ExtBuilder::default().build_and_execute(|| {
// Account 11 (also controller) is stashed and locked
assert_eq!(Staking::bonded(&11), Some(11));
// 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 is the controller
assert_eq!(Staking::bonded(&11), Some(11));
// Account 21 is stashed and locked and is the controller
assert_eq!(Staking::bonded(&21), Some(21));
// Account 1 is not a stashed
assert_eq!(Staking::bonded(&1), None);
// Account 11 controls its own stash, which is 100 * balance_factor units
Staking::ledger(&11).unwrap(),
stash: 11,
total: 1000,
active: 1000,
unlocking: Default::default(),
// Account 21 controls its own stash, which is 200 * balance_factor units
Staking::ledger(&21),
Some(StakingLedger {
stash: 21,
total: 1000,
active: 1000,
unlocking: Default::default(),
// 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())
]
);
Staking::ledger(101),
Some(StakingLedger {
stash: 101,
total: 500,
active: 500,
unlocking: Default::default(),
assert_eq!(Staking::nominators(101).unwrap().targets, vec![11, 21]);
Staking::eras_stakers(active_era(), 11),
others: vec![IndividualExposure { who: 101, value: 125 }]
Staking::eras_stakers(active_era(), 21),
others: vec![IndividualExposure { who: 101, value: 375 }]
// initial total stake = 1125 + 1375
assert_eq!(Staking::eras_total_stake(active_era()), 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(|| {
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
let (stash, controller) = testing_utils::create_unique_stash_controller::<Test>(
0,
100,
RewardDestination::Staked,
false,
)
.unwrap();
// ensure `stash` and `controller` are bonded as stash controller pair.
assert_eq!(Staking::bonded(&stash), Some(controller));
// `controller` can control `stash` who is initially a validator.
assert_ok!(Staking::chill(RuntimeOrigin::signed(controller)));
// sets controller back to `stash`.
assert_ok!(Staking::set_controller(RuntimeOrigin::signed(stash)));
assert_eq!(Staking::bonded(&stash), Some(stash));
mock::start_active_era(1);
// `controller` is no longer in control. `stash` is now controller.
assert_noop!(
Staking::validate(RuntimeOrigin::signed(controller), ValidatorPrefs::default()),
Error::<Test>::NotController,
);
assert_ok!(Staking::validate(RuntimeOrigin::signed(stash), ValidatorPrefs::default()));
})
}
#[test]
fn change_controller_already_paired_once_stash() {
ExtBuilder::default().build_and_execute(|| {
// 10 and 11 are bonded as controller and stash respectively.
assert_eq!(Staking::bonded(&11), Some(11));
// 11 is initially a validator.
assert_ok!(Staking::chill(RuntimeOrigin::signed(11)));
// Controller cannot change once matching with stash.
assert_noop!(
Staking::set_controller(RuntimeOrigin::signed(11)),
Error::<Test>::AlreadyPaired
);
assert_eq!(Staking::bonded(&11), Some(11));
mock::start_active_era(1);
Staking::validate(RuntimeOrigin::signed(10), ValidatorPrefs::default()),
assert_ok!(Staking::validate(RuntimeOrigin::signed(11), ValidatorPrefs::default()));
#[test]
fn rewards_should_work() {
ExtBuilder::default().nominate(true).session_per_era(3).build_and_execute(|| {
let init_balance_11 = Balances::total_balance(&11);
let init_balance_21 = Balances::total_balance(&21);
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);
Pallet::<Test>::reward_by_ids(vec![(11, 50)]);
Pallet::<Test>::reward_by_ids(vec![(11, 50)]);
// This is the second validator of the current elected set.
Pallet::<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_uvec!(Session::validators(), vec![11, 21]);
assert_eq!(Balances::total_balance(&11), init_balance_11);
assert_eq!(Balances::total_balance(&21), init_balance_21);
assert_eq!(Balances::total_balance(&101), init_balance_101);
assert_eq!(
Staking::eras_reward_points(active_era()),
EraRewardPoints {
total: 50 * 3,
individual: vec![(11, 100), (21, 50)].into_iter().collect(),
}
);
let part_for_11 = Perbill::from_rational::<u32>(1000, 1125);
let part_for_21 = Perbill::from_rational::<u32>(1000, 1375);
let part_for_101_from_11 = Perbill::from_rational::<u32>(125, 1125);
let part_for_101_from_21 = Perbill::from_rational::<u32>(375, 1375);
assert_eq!(mock::RewardRemainderUnbalanced::get(), maximum_payout - total_payout_0,);
assert_eq!(
*mock::staking_events().last().unwrap(),
Event::EraPaid {
era_index: 0,
validator_payout: total_payout_0,
remainder: maximum_payout - total_payout_0
}
assert_eq_error_rate!(
Balances::total_balance(&11),
init_balance_11 + part_for_11 * total_payout_0 * 2 / 3,
2,
);
assert_eq_error_rate!(
Balances::total_balance(&21),
init_balance_21 + part_for_21 * total_payout_0 * 1 / 3,
2,
);
Balances::total_balance(&101),
init_balance_101 +
part_for_101_from_11 * total_payout_0 * 2 / 3 +
part_for_101_from_21 * total_payout_0 * 1 / 3,
Pallet::<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::RewardRemainderUnbalanced::get(),
maximum_payout * 2 - total_payout_0 - total_payout_1,
);
assert_eq!(
*mock::staking_events().last().unwrap(),
Event::EraPaid {
era_index: 1,
validator_payout: total_payout_1,
remainder: maximum_payout - total_payout_1
}
assert_eq_error_rate!(
Balances::total_balance(&11),
init_balance_11 + part_for_11 * (total_payout_0 * 2 / 3 + total_payout_1),
2,
);
assert_eq_error_rate!(
Balances::total_balance(&21),
init_balance_21 + part_for_21 * total_payout_0 * 1 / 3,
2,
);
Balances::total_balance(&101),
init_balance_101 +
part_for_101_from_11 * (total_payout_0 * 2 / 3 + total_payout_1) +
part_for_101_from_21 * total_payout_0 * 1 / 3,
ExtBuilder::default().nominate(false).build_and_execute(|| {
// remember + compare this along with the test.
assert_eq_uvec!(validator_controllers(), vec![21, 11]);
// put some money in account that we'll use.
for i in 1..5 {
let _ = Balances::make_free_balance_be(&i, 2000);
}
// --- Block 2:
start_session(2);
// add a new candidate for being a validator. account 3 controlled by 4.
assert_ok!(Staking::bond(RuntimeOrigin::signed(3), 1500, RewardDestination::Controller));
assert_ok!(Staking::validate(RuntimeOrigin::signed(3), ValidatorPrefs::default()));
RuntimeOrigin::signed(3),
SessionKeys { other: 4.into() },
vec![]
));
assert_eq_uvec!(validator_controllers(), vec![21, 11]);
// --- Block 3:
start_session(3);
// No effects will be seen so far. Era has not been yet triggered.
assert_eq_uvec!(validator_controllers(), vec![21, 11]);
// --- Block 4: the validators will now be queued.
start_session(4);
assert_eq!(active_era(), 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![21, 3]);
// --- Block 6: Unstake 4 as a validator, freeing up the balance stashed in 3
// 4 will chill
Staking::chill(RuntimeOrigin::signed(3)).unwrap();
// --- Block 7: nothing. 3 is still there.
assert_eq_uvec!(validator_controllers(), vec![21, 3]);
// --- Block 8:
start_session(8);
// --- Block 9: 4 will not be a validator.
start_session(9);
assert_eq_uvec!(validator_controllers(), vec![21, 11]);
// Note: the stashed value of 4 is still lock
assert_eq!(
Staking::ledger(&3),
Some(StakingLedger {
stash: 3,
total: 1500,
active: 1500,
unlocking: Default::default(),
})
);
// e.g. it cannot reserve more than 500 that it has free from the total 2000
assert_noop!(Balances::reserve(&3, 501), BalancesError::<Test, _>::LiquidityRestrictions);
assert_ok!(Balances::reserve(&3, 409));
});
#[test]
fn blocking_and_kicking_works() {
ExtBuilder::default()
.minimum_validator_count(1)
.validator_count(4)
.nominate(true)
.build_and_execute(|| {
// block validator 10/11
assert_ok!(Staking::validate(
RuntimeOrigin::signed(11),
ValidatorPrefs { blocked: true, ..Default::default() }
));
// attempt to nominate from 100/101...
assert_ok!(Staking::nominate(RuntimeOrigin::signed(101), vec![11]));
// should have worked since we're already nominated them
assert_eq!(Nominators::<Test>::get(&101).unwrap().targets, vec![11]);
// kick the nominator
assert_ok!(Staking::kick(RuntimeOrigin::signed(11), vec![101]));
// should have been kicked now
assert!(Nominators::<Test>::get(&101).unwrap().targets.is_empty());
// attempt to nominate from 100/101...
Staking::nominate(RuntimeOrigin::signed(101), vec![11]),
Error::<Test>::BadTarget
);
});
}
#[test]
fn less_than_needed_candidates_works() {
ExtBuilder::default()
.build_and_execute(|| {
assert_eq!(Staking::validator_count(), 4);
assert_eq!(Staking::minimum_validator_count(), 1);
assert_eq_uvec!(validator_controllers(), vec![31, 21, 11]);
mock::start_active_era(1);
// Previous set is selected. NO election algorithm is even executed.
assert_eq_uvec!(validator_controllers(), vec![31, 21, 11]);
// But the exposure is updated in a simple way. No external votes exists.
// This is purely self-vote.
assert!(ErasStakers::<Test>::iter_prefix_values(active_era())
.all(|exposure| exposure.others.is_empty()));
}
#[test]
fn no_candidate_emergency_condition() {
ExtBuilder::default()
.set_status(41, StakerStatus::Validator)
.build_and_execute(|| {
// initial validators
assert_eq_uvec!(validator_controllers(), vec![11, 21, 31, 41]);
let prefs = ValidatorPrefs { commission: Perbill::one(), ..Default::default() };
Validators::<Test>::insert(11, prefs.clone());
// set the minimum validator count.
MinimumValidatorCount::<Test>::put(11);
let res = Staking::chill(RuntimeOrigin::signed(11));
thiolliere
committed
let current_era = CurrentEra::<Test>::get();
// try trigger new era
mock::run_to_block(21);
assert_eq!(*staking_events().last().unwrap(), Event::StakingElectionFailed);
thiolliere
committed
// No new era is created
assert_eq!(current_era, CurrentEra::<Test>::get());
// Go to far further session to see if validator have changed
mock::run_to_block(100);
// Previous ones are elected. chill is not effective in active era (as era hasn't
// changed)
assert_eq_uvec!(validator_controllers(), vec![11, 21, 31, 41]);
thiolliere
committed
// The chill is still pending.
assert!(!Validators::<Test>::contains_key(11));
thiolliere
committed
// No new era is created.
assert_eq!(current_era, CurrentEra::<Test>::get());
#[test]
fn nominating_and_rewards_should_work() {
ExtBuilder::default()
.set_status(41, StakerStatus::Validator)
.set_status(11, StakerStatus::Idle)
.set_status(31, StakerStatus::Idle)
.build_and_execute(|| {
assert_eq_uvec!(validator_controllers(), vec![41, 21]);
assert_ok!(Staking::validate(RuntimeOrigin::signed(11), Default::default()));
assert_ok!(Staking::validate(RuntimeOrigin::signed(31), Default::default()));
RuntimeOrigin::signed(11),
RewardDestination::Controller
));
assert_ok!(Staking::set_payee(
RuntimeOrigin::signed(21),
RewardDestination::Controller
));
assert_ok!(Staking::set_payee(
RuntimeOrigin::signed(31),
RewardDestination::Controller
));
assert_ok!(Staking::set_payee(
RuntimeOrigin::signed(41),
// give the man some money
let initial_balance = 1000;
for i in [1, 3, 5, 11, 21].iter() {
let _ = Balances::make_free_balance_be(i, initial_balance);
}
// bond two account pairs and state interest in nomination.
assert_ok!(Staking::bond(
RuntimeOrigin::signed(1),
1000,
RewardDestination::Controller
));
assert_ok!(Staking::nominate(RuntimeOrigin::signed(1), vec![11, 21, 31]));
assert_ok!(Staking::bond(
RuntimeOrigin::signed(3),
1000,
RewardDestination::Controller
));
assert_ok!(Staking::nominate(RuntimeOrigin::signed(3), vec![11, 21, 41]));
// the total reward for era 0
let total_payout_0 = current_total_payout_for_duration(reward_time_per_era());
Pallet::<Test>::reward_by_ids(vec![(41, 1)]);
Pallet::<Test>::reward_by_ids(vec![(21, 1)]);
mock::start_active_era(1);
// 10 and 20 have more votes, they will be chosen.
assert_eq_uvec!(validator_controllers(), vec![21, 11]);
// old validators must have already received some rewards.
let initial_balance_41 = Balances::total_balance(&41);
let mut initial_balance_21 = Balances::total_balance(&21);
assert_eq!(Balances::total_balance(&41), initial_balance_41 + total_payout_0 / 2);
assert_eq!(Balances::total_balance(&21), initial_balance_21 + total_payout_0 / 2);
initial_balance_21 = Balances::total_balance(&21);
assert_eq!(ErasStakers::<Test>::iter_prefix_values(active_era()).count(), 2);
Staking::eras_stakers(active_era(), 11),
Exposure {
total: 1000 + 800,
own: 1000,
others: vec![
IndividualExposure { who: 1, value: 400 },
IndividualExposure { who: 3, value: 400 },
Staking::eras_stakers(active_era(), 21),
Exposure {
total: 1000 + 1200,
own: 1000,
others: vec![
IndividualExposure { who: 1, value: 600 },
IndividualExposure { who: 3, value: 600 },
// the total reward for era 1
let total_payout_1 = current_total_payout_for_duration(reward_time_per_era());
Pallet::<Test>::reward_by_ids(vec![(21, 2)]);
Pallet::<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_11 = total_payout_1 / 3;
let payout_for_21 = 2 * total_payout_1 / 3;
// Nominator 2: has [400/1800 ~ 2/9 from 10] + [600/2200 ~ 3/11 from 21]'s reward. ==>
Balances::total_balance(&1),
initial_balance + (2 * payout_for_11 / 9 + 3 * payout_for_21 / 11),
// Nominator 3: has [400/1800 ~ 2/9 from 10] + [600/2200 ~ 3/11 from 21]'s reward. ==>
Balances::total_balance(&3),
initial_balance + (2 * payout_for_11 / 9 + 3 * payout_for_21 / 11),
// Validator 11: got 800 / 1800 external stake => 8/18 =? 4/9 => Validator's share = 5/9
Balances::total_balance(&11),
initial_balance + 5 * payout_for_11 / 9,
// Validator 21: got 1200 / 2200 external stake => 12/22 =? 6/11 => Validator's share =
Balances::total_balance(&21),
initial_balance_21 + 5 * payout_for_21 / 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);
let nominator_stake = Staking::ledger(101).unwrap().active;
let nominator_balance = balances(&101).0;
let validator_stake = Staking::ledger(11).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, initial_exposure.clone()), reporters: vec![] }],
// both stakes must have been decreased.
assert!(Staking::ledger(101).unwrap().active < nominator_stake);
assert!(Staking::ledger(11).unwrap().active < validator_stake);
let slash_amount = slash_percent * exposed_stake;
let validator_share =
Perbill::from_rational(exposed_validator, exposed_stake) * slash_amount;
let nominator_share =
Perbill::from_rational(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(101).unwrap().active, nominator_stake - nominator_share);
assert_eq!(Staking::ledger(11).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,
);
assert!(is_disabled(11));
});
}
#[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;
let (stash, controller) = testing_utils::create_unique_stash_controller::<Test>(
0,
RewardDestination::default(),
false,
)
.unwrap();
// 4 = not used so far, stash => not allowed.
RuntimeOrigin::signed(stash),
arbitrary_value.into(),
Error::<Test>::AlreadyBonded,
// stash => attempting to nominate should fail.
Staking::nominate(RuntimeOrigin::signed(stash), vec![1]),
// controller => nominating should work.
assert_ok!(Staking::nominate(RuntimeOrigin::signed(controller), vec![1]));
fn double_controlling_attempt_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;
let (stash, _) = testing_utils::create_unique_stash_controller::<Test>(
0,
arbitrary_value,
RewardDestination::default(),
false,
)
.unwrap();
// Note that controller (same as stash) is reused => no-op.
RuntimeOrigin::signed(stash),
arbitrary_value.into(),
Error::<Test>::AlreadyBonded,
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);
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
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);
Staking::set_force_era(Forcing::ForceNone);
assert_eq!(active_era(), 1);
assert_eq!(active_era(), 1);
assert_eq!(active_era(), 1);
assert_eq!(active_era(), 1);
Staking::set_force_era(Forcing::NotForcing);
assert_eq!(active_era(), 1);
start_session(9);
assert_eq!(active_era(), 2);
Staking::set_force_era(Forcing::ForceAlways);
assert_eq!(active_era(), 2);
assert_eq!(active_era(), 3);
assert_eq!(active_era(), 4);
Staking::set_force_era(Forcing::ForceNew);
assert_eq!(active_era(), 5);
assert_eq!(ForceEra::<Test>::get(), Forcing::NotForcing);
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(|| {
assert_eq!(Staking::bonded(&11), Some(11));
// Confirm account 11 has some free balance
assert_eq!(Balances::free_balance(11), 1000);
// Confirm account 11 (via controller) is totally staked
assert_eq!(Staking::eras_stakers(active_era(), 11).total, 1000);
// Confirm account 11 cannot transfer as a result
Balances::transfer_allow_death(RuntimeOrigin::signed(11), 21, 1),
Gavin Wood
committed
TokenError::Frozen,
// 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_allow_death(RuntimeOrigin::signed(11), 21, 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.