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 crate::ledger::StakingLedgerInspect;
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, InspectLockableCurrency, ReservableCurrency},
use pallet_balances::Error as BalancesError;
assert_eq_error_rate, bounded_vec,
traits::{BadOrigin, Dispatchable},
Perbill, Percent, Perquintill, 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()),
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));
assert_eq!(MaxStakedRewards::<Test>::get(), Some(Percent::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,
ConfigOp::Noop
)));
// removing works
assert_ok!(Staking::set_staking_configs(
ConfigOp::Remove,
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));
assert_eq!(MaxStakedRewards::<Test>::get(), None);
#[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
Ledger::get(&11).unwrap(),
StakingLedgerInspect::<Test> {
stash: 11,
total: 1000,
active: 1000,
unlocking: Default::default(),
legacy_claimed_rewards: bounded_vec![],
// Account 21 controls its own stash, which is 200 * balance_factor units
Ledger::get(&21).unwrap(),
StakingLedgerInspect::<Test> {
stash: 21,
total: 1000,
active: 1000,
unlocking: Default::default(),
legacy_claimed_rewards: bounded_vec![],
// Account 1 does not control any stash
assert!(Staking::ledger(1.into()).is_err());
assert_eq_uvec!(
<Validators<Test>>::iter().collect::<Vec<_>>(),
vec![
(31, ValidatorPrefs::default()),
(21, ValidatorPrefs::default()),
(11, ValidatorPrefs::default())
]
);
Staking::ledger(101.into()).unwrap(),
StakingLedgerInspect {
stash: 101,
total: 500,
active: 500,
unlocking: Default::default(),
legacy_claimed_rewards: bounded_vec![],
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(|| {
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);
Gonçalo Pestana
committed
// fetch the ledger from storage and check if the controller is correct.
let ledger = Staking::ledger(StakingAccount::Stash(stash)).unwrap();
assert_eq!(ledger.controller(), Some(stash));
// same if we fetch the ledger by controller.
let ledger = Staking::ledger(StakingAccount::Controller(stash)).unwrap();
assert_eq!(ledger.controller, Some(stash));
assert_eq!(ledger.controller(), Some(stash));
// the raw storage ledger's controller is always `None`. however, we can still fetch the
// correct controller with `ledger.controller()`.
Gonçalo Pestana
committed
let raw_ledger = <Ledger<Test>>::get(&stash).unwrap();
assert_eq!(raw_ledger.controller, None);
// `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(|| {
// 11 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::Account(11));
Payee::<Test>::insert(21, RewardDestination::Account(21));
Payee::<Test>::insert(101, RewardDestination::Account(101));
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::Account(3)));
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.into()).unwrap(),
StakingLedgerInspect {
stash: 3,
total: 1500,
active: 1500,
unlocking: Default::default(),
legacy_claimed_rewards: bounded_vec![],
);
// 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!(ErasStakersPaged::<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()));
assert_ok!(Staking::set_payee(RuntimeOrigin::signed(11), RewardDestination::Stash));
assert_ok!(Staking::set_payee(RuntimeOrigin::signed(21), RewardDestination::Stash));
assert_ok!(Staking::set_payee(RuntimeOrigin::signed(31), RewardDestination::Stash));
assert_ok!(Staking::set_payee(RuntimeOrigin::signed(41), RewardDestination::Stash));
// 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::Account(1)
assert_ok!(Staking::nominate(RuntimeOrigin::signed(1), vec![11, 21, 31]));
// the second nominator is virtual.
bond_virtual_nominator(3, 333, 1000, 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!(ErasStakersPaged::<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. ==>
assert_eq!(Balances::total_balance(&3), initial_balance);
// 333 is the reward destination for 3.
Balances::total_balance(&333),
2 * payout_for_11 / 9 + 3 * payout_for_21 / 11,
2
// 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);
assert_eq!(initial_exposure.others.first().unwrap().who, 101);
let nominator_stake = Staking::ledger(101.into()).unwrap().active;
let nominator_balance = balances(&101).0;
let validator_stake = Staking::ledger(11.into()).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.into()).unwrap().active < nominator_stake);
assert!(Staking::ledger(11.into()).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.into()).unwrap().active, nominator_stake - nominator_share);
assert_eq!(Staking::ledger(11.into()).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().try_state(false).build_and_execute(|| {
let arbitrary_value = 5;
let (stash, controller) = testing_utils::create_unique_stash_controller::<Test>(
0,
RewardDestination::Staked,
false,
)
.unwrap();
// 4 = not used so far, stash => not allowed.
RuntimeOrigin::signed(stash),
arbitrary_value.into(),
RewardDestination::Staked,
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().try_state(false).build_and_execute(|| {
let arbitrary_value = 5;
let (stash, _) = testing_utils::create_unique_stash_controller::<Test>(
0,
RewardDestination::Staked,
false,
)
.unwrap();
// Note that controller (same as stash) is reused => no-op.
RuntimeOrigin::signed(stash),
arbitrary_value.into(),
RewardDestination::Staked,
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);
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
908
909
910
911
912
913
914
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));