use super::*;
use crate::{ConfigOp, Pallet as Staking};
use testing_utils::*;
use codec::Decode;
use frame_election_provider_support::{bounds::DataProviderBounds, SortedListProvider};
use frame_support::{
dispatch::UnfilteredDispatchable,
pallet_prelude::*,
traits::{Currency, Get, Imbalance},
};
use sp_runtime::{
traits::{Bounded, One, StaticLookup, TrailingZeroInput, Zero},
Perbill, Percent,
};
use sp_staking::{currency_to_vote::CurrencyToVote, SessionIndex};
use sp_std::prelude::*;
pub use frame_benchmarking::v1::{
account, benchmarks, impl_benchmark_test_suite, whitelist_account, whitelisted_caller,
};
use frame_system::RawOrigin;
const SEED: u32 = 0;
const MAX_SPANS: u32 = 100;
const MAX_SLASHES: u32 = 1000;
type MaxValidators<T> = <<T as Config>::BenchmarkingConfig as BenchmarkingConfig>::MaxValidators;
type MaxNominators<T> = <<T as Config>::BenchmarkingConfig as BenchmarkingConfig>::MaxNominators;
pub fn add_slashing_spans<T: Config>(who: &T::AccountId, spans: u32) {
if spans == 0 {
return
}
let mut slashing_spans = crate::slashing::SlashingSpans::new(0);
SpanSlash::<T>::insert((who, 0), crate::slashing::SpanRecord::default());
for i in 1..spans {
assert!(slashing_spans.end_span(i));
SpanSlash::<T>::insert((who, i), crate::slashing::SpanRecord::default());
}
SlashingSpans::<T>::insert(who, slashing_spans);
}
pub fn create_validator_with_nominators<T: Config>(
n: u32,
upper_bound: u32,
dead_controller: bool,
unique_controller: bool,
destination: RewardDestination<T::AccountId>,
) -> Result<(T::AccountId, Vec<(T::AccountId, T::AccountId)>), &'static str> {
clear_validators_and_nominators::<T>();
let mut points_total = 0;
let mut points_individual = Vec::new();
let (v_stash, v_controller) = if unique_controller {
create_unique_stash_controller::<T>(0, 100, destination.clone(), false)?
} else {
create_stash_controller::<T>(0, 100, destination.clone())?
};
let validator_prefs =
ValidatorPrefs { commission: Perbill::from_percent(50), ..Default::default() };
Staking::<T>::validate(RawOrigin::Signed(v_controller).into(), validator_prefs)?;
let stash_lookup = T::Lookup::unlookup(v_stash.clone());
points_total += 10;
points_individual.push((v_stash.clone(), 10));
let original_nominator_count = Nominators::<T>::count();
let mut nominators = Vec::new();
for i in 0..upper_bound {
let (n_stash, n_controller) = if !dead_controller {
create_stash_controller::<T>(u32::MAX - i, 100, destination.clone())?
} else {
create_unique_stash_controller::<T>(u32::MAX - i, 100, destination.clone(), true)?
};
if i < n {
Staking::<T>::nominate(
RawOrigin::Signed(n_controller.clone()).into(),
vec![stash_lookup.clone()],
)?;
nominators.push((n_stash, n_controller));
}
}
ValidatorCount::<T>::put(1);
let new_validators = Staking::<T>::try_trigger_new_era(SessionIndex::one(), true).unwrap();
assert_eq!(new_validators.len(), 1);
assert_eq!(new_validators[0], v_stash, "Our validator was not selected!");
assert_ne!(Validators::<T>::count(), 0);
assert_eq!(Nominators::<T>::count(), original_nominator_count + nominators.len() as u32);
let reward = EraRewardPoints::<T::AccountId> {
total: points_total,
individual: points_individual.into_iter().collect(),
};
let current_era = CurrentEra::<T>::get().unwrap();
ErasRewardPoints::<T>::insert(current_era, reward);
let total_payout = T::Currency::minimum_balance()
.saturating_mul(upper_bound.into())
.saturating_mul(1000u32.into());
<ErasValidatorReward<T>>::insert(current_era, total_payout);
Ok((v_stash, nominators))
}
struct ListScenario<T: Config> {
origin_stash1: T::AccountId,
origin_controller1: T::AccountId,
dest_weight: BalanceOf<T>,
}
impl<T: Config> ListScenario<T> {
fn new(origin_weight: BalanceOf<T>, is_increase: bool) -> Result<Self, &'static str> {
ensure!(!origin_weight.is_zero(), "origin weight must be greater than 0");
let i = T::Currency::burn(T::Currency::total_issuance());
sp_std::mem::forget(i);
let (origin_stash1, origin_controller1) = create_stash_controller_with_balance::<T>(
USER_SEED + 2,
origin_weight,
Default::default(),
)?;
Staking::<T>::nominate(
RawOrigin::Signed(origin_controller1.clone()).into(),
vec![T::Lookup::unlookup(account("random_validator", 0, SEED))],
)?;
let (_origin_stash2, origin_controller2) = create_stash_controller_with_balance::<T>(
USER_SEED + 3,
origin_weight,
Default::default(),
)?;
Staking::<T>::nominate(
RawOrigin::Signed(origin_controller2).into(),
vec![T::Lookup::unlookup(account("random_validator", 0, SEED))],
)?;
let dest_weight_as_vote =
T::VoterList::score_update_worst_case(&origin_stash1, is_increase);
let total_issuance = T::Currency::total_issuance();
let dest_weight =
T::CurrencyToVote::to_currency(dest_weight_as_vote as u128, total_issuance);
let (_dest_stash1, dest_controller1) = create_stash_controller_with_balance::<T>(
USER_SEED + 1,
dest_weight,
Default::default(),
)?;
Staking::<T>::nominate(
RawOrigin::Signed(dest_controller1).into(),
vec![T::Lookup::unlookup(account("random_validator", 0, SEED))],
)?;
Ok(ListScenario { origin_stash1, origin_controller1, dest_weight })
}
}
const USER_SEED: u32 = 999666;
benchmarks! {
bond {
let stash = create_funded_user::<T>("stash", USER_SEED, 100);
let reward_destination = RewardDestination::Staked;
let amount = T::Currency::minimum_balance() * 10u32.into();
whitelist_account!(stash);
}: _(RawOrigin::Signed(stash.clone()), amount, reward_destination)
verify {
assert!(Bonded::<T>::contains_key(stash.clone()));
assert!(Ledger::<T>::contains_key(stash));
}
bond_extra {
clear_validators_and_nominators::<T>();
let origin_weight = MinNominatorBond::<T>::get().max(T::Currency::minimum_balance());
let scenario = ListScenario::<T>::new(origin_weight, true)?;
let max_additional = scenario.dest_weight - origin_weight;
let stash = scenario.origin_stash1.clone();
let controller = scenario.origin_controller1;
let original_bonded: BalanceOf<T>
= Ledger::<T>::get(&controller).map(|l| l.active).ok_or("ledger not created after")?;
T::Currency::deposit_into_existing(&stash, max_additional).unwrap();
whitelist_account!(stash);
}: _(RawOrigin::Signed(stash), max_additional)
verify {
let ledger = Ledger::<T>::get(&controller).ok_or("ledger not created after")?;
let new_bonded: BalanceOf<T> = ledger.active;
assert!(original_bonded < new_bonded);
}
unbond {
clear_validators_and_nominators::<T>();
let total_issuance = T::Currency::total_issuance();
let origin_weight = BalanceOf::<T>::try_from(952_994_955_240_703u128)
.map_err(|_| "balance expected to be a u128")
.unwrap();
let scenario = ListScenario::<T>::new(origin_weight, false)?;
let stash = scenario.origin_stash1.clone();
let controller = scenario.origin_controller1.clone();
let amount = origin_weight - scenario.dest_weight;
let ledger = Ledger::<T>::get(&controller).ok_or("ledger not created before")?;
let original_bonded: BalanceOf<T> = ledger.active;
whitelist_account!(controller);
}: _(RawOrigin::Signed(controller.clone()), amount)
verify {
let ledger = Ledger::<T>::get(&controller).ok_or("ledger not created after")?;
let new_bonded: BalanceOf<T> = ledger.active;
assert!(original_bonded > new_bonded);
}
withdraw_unbonded_update {
let s in 0 .. MAX_SPANS;
let (stash, controller) = create_stash_controller::<T>(0, 100, Default::default())?;
add_slashing_spans::<T>(&stash, s);
let amount = T::Currency::minimum_balance() * 5u32.into(); Staking::<T>::unbond(RawOrigin::Signed(controller.clone()).into(), amount)?;
CurrentEra::<T>::put(EraIndex::max_value());
let ledger = Ledger::<T>::get(&controller).ok_or("ledger not created before")?;
let original_total: BalanceOf<T> = ledger.total;
whitelist_account!(controller);
}: withdraw_unbonded(RawOrigin::Signed(controller.clone()), s)
verify {
let ledger = Ledger::<T>::get(&controller).ok_or("ledger not created after")?;
let new_total: BalanceOf<T> = ledger.total;
assert!(original_total > new_total);
}
withdraw_unbonded_kill {
let s in 0 .. MAX_SPANS;
clear_validators_and_nominators::<T>();
let origin_weight = MinNominatorBond::<T>::get().max(T::Currency::minimum_balance());
let scenario = ListScenario::<T>::new(origin_weight, true)?;
let controller = scenario.origin_controller1.clone();
let stash = scenario.origin_stash1;
add_slashing_spans::<T>(&stash, s);
assert!(T::VoterList::contains(&stash));
let ed = T::Currency::minimum_balance();
let mut ledger = Ledger::<T>::get(&controller).unwrap();
ledger.active = ed - One::one();
Ledger::<T>::insert(&controller, ledger);
CurrentEra::<T>::put(EraIndex::max_value());
whitelist_account!(controller);
}: withdraw_unbonded(RawOrigin::Signed(controller.clone()), s)
verify {
assert!(!Ledger::<T>::contains_key(controller));
assert!(!T::VoterList::contains(&stash));
}
validate {
let (stash, controller) = create_stash_controller::<T>(
MaxNominationsOf::<T>::get() - 1,
100,
Default::default(),
)?;
assert!(!T::VoterList::contains(&stash));
let prefs = ValidatorPrefs::default();
whitelist_account!(controller);
}: _(RawOrigin::Signed(controller), prefs)
verify {
assert!(Validators::<T>::contains_key(&stash));
assert!(T::VoterList::contains(&stash));
}
kick {
let k in 1 .. 128;
let rest_of_validators = create_validators_with_seed::<T>(MaxNominationsOf::<T>::get() - 1, 100, 415)?;
let (stash, controller) = create_stash_controller::<T>(
MaxNominationsOf::<T>::get() - 1,
100,
Default::default(),
)?;
let stash_lookup = T::Lookup::unlookup(stash.clone());
Staking::<T>::validate(RawOrigin::Signed(controller.clone()).into(), Default::default())?;
let mut nominator_stashes = Vec::with_capacity(k as usize);
for i in 0 .. k {
let (n_stash, n_controller) = create_stash_controller::<T>(
MaxNominationsOf::<T>::get() + i,
100,
Default::default(),
)?;
let mut nominations = rest_of_validators.clone();
nominations.insert(i as usize % (nominations.len() + 1), stash_lookup.clone());
Staking::<T>::nominate(RawOrigin::Signed(n_controller.clone()).into(), nominations)?;
nominator_stashes.push(n_stash);
}
for n in nominator_stashes.iter() {
assert!(Nominators::<T>::get(n).unwrap().targets.contains(&stash));
}
let kicks = nominator_stashes.iter()
.map(|n| T::Lookup::unlookup(n.clone()))
.collect::<Vec<_>>();
whitelist_account!(controller);
}: _(RawOrigin::Signed(controller), kicks)
verify {
for n in nominator_stashes.iter() {
assert!(!Nominators::<T>::get(n).unwrap().targets.contains(&stash));
}
}
nominate {
let n in 1 .. MaxNominationsOf::<T>::get();
clear_validators_and_nominators::<T>();
let origin_weight = MinNominatorBond::<T>::get().max(T::Currency::minimum_balance());
let scenario = ListScenario::<T>::new(origin_weight, true)?;
let (stash, controller) = create_stash_controller_with_balance::<T>(
SEED + MaxNominationsOf::<T>::get() + 1, origin_weight,
Default::default(),
).unwrap();
assert!(!Nominators::<T>::contains_key(&stash));
assert!(!T::VoterList::contains(&stash));
let validators = create_validators::<T>(n, 100).unwrap();
whitelist_account!(controller);
}: _(RawOrigin::Signed(controller), validators)
verify {
assert!(Nominators::<T>::contains_key(&stash));
assert!(T::VoterList::contains(&stash))
}
chill {
clear_validators_and_nominators::<T>();
let origin_weight = MinNominatorBond::<T>::get().max(T::Currency::minimum_balance());
let scenario = ListScenario::<T>::new(origin_weight, true)?;
let controller = scenario.origin_controller1.clone();
let stash = scenario.origin_stash1;
assert!(T::VoterList::contains(&stash));
whitelist_account!(controller);
}: _(RawOrigin::Signed(controller))
verify {
assert!(!T::VoterList::contains(&stash));
}
set_payee {
let (stash, controller) = create_stash_controller::<T>(USER_SEED, 100, Default::default())?;
assert_eq!(Payee::<T>::get(&stash), RewardDestination::Staked);
whitelist_account!(controller);
}: _(RawOrigin::Signed(controller), RewardDestination::Controller)
verify {
assert_eq!(Payee::<T>::get(&stash), RewardDestination::Controller);
}
set_controller {
let (stash, ctlr) = create_unique_stash_controller::<T>(9000, 100, Default::default(), false)?;
assert!(!Ledger::<T>::contains_key(&stash));
assert!(Ledger::<T>::contains_key(&ctlr));
assert_eq!(Bonded::<T>::get(&stash), Some(ctlr.clone()));
whitelist_account!(stash);
}: _(RawOrigin::Signed(stash.clone()))
verify {
assert!(Ledger::<T>::contains_key(&stash));
}
set_validator_count {
let validator_count = MaxValidators::<T>::get();
}: _(RawOrigin::Root, validator_count)
verify {
assert_eq!(ValidatorCount::<T>::get(), validator_count);
}
force_no_eras {}: _(RawOrigin::Root)
verify { assert_eq!(ForceEra::<T>::get(), Forcing::ForceNone); }
force_new_era {}: _(RawOrigin::Root)
verify { assert_eq!(ForceEra::<T>::get(), Forcing::ForceNew); }
force_new_era_always {}: _(RawOrigin::Root)
verify { assert_eq!(ForceEra::<T>::get(), Forcing::ForceAlways); }
set_invulnerables {
let v in 0 .. MaxValidators::<T>::get();
let mut invulnerables = Vec::new();
for i in 0 .. v {
invulnerables.push(account("invulnerable", i, SEED));
}
}: _(RawOrigin::Root, invulnerables)
verify {
assert_eq!(Invulnerables::<T>::get().len(), v as usize);
}
force_unstake {
let s in 0 .. MAX_SPANS;
clear_validators_and_nominators::<T>();
let origin_weight = MinNominatorBond::<T>::get().max(T::Currency::minimum_balance());
let scenario = ListScenario::<T>::new(origin_weight, true)?;
let controller = scenario.origin_controller1.clone();
let stash = scenario.origin_stash1;
assert!(T::VoterList::contains(&stash));
add_slashing_spans::<T>(&stash, s);
}: _(RawOrigin::Root, stash.clone(), s)
verify {
assert!(!Ledger::<T>::contains_key(&controller));
assert!(!T::VoterList::contains(&stash));
}
cancel_deferred_slash {
let s in 1 .. MAX_SLASHES;
let mut unapplied_slashes = Vec::new();
let era = EraIndex::one();
let dummy = || T::AccountId::decode(&mut TrailingZeroInput::zeroes()).unwrap();
for _ in 0 .. MAX_SLASHES {
unapplied_slashes.push(UnappliedSlash::<T::AccountId, BalanceOf<T>>::default_from(dummy()));
}
UnappliedSlashes::<T>::insert(era, &unapplied_slashes);
let slash_indices: Vec<u32> = (0 .. s).collect();
}: _(RawOrigin::Root, era, slash_indices)
verify {
assert_eq!(UnappliedSlashes::<T>::get(&era).len(), (MAX_SLASHES - s) as usize);
}
payout_stakers_dead_controller {
let n in 0 .. T::MaxNominatorRewardedPerValidator::get() as u32;
let (validator, nominators) = create_validator_with_nominators::<T>(
n,
T::MaxNominatorRewardedPerValidator::get() as u32,
true,
true,
RewardDestination::Controller,
)?;
let current_era = CurrentEra::<T>::get().unwrap();
<ErasValidatorPrefs<T>>::insert(current_era, validator.clone(), <Staking<T>>::validators(&validator));
let caller = whitelisted_caller();
let validator_controller = <Bonded<T>>::get(&validator).unwrap();
let balance_before = T::Currency::free_balance(&validator_controller);
for (_, controller) in &nominators {
let balance = T::Currency::free_balance(controller);
ensure!(balance.is_zero(), "Controller has balance, but should be dead.");
}
}: payout_stakers(RawOrigin::Signed(caller), validator, current_era)
verify {
let balance_after = T::Currency::free_balance(&validator_controller);
ensure!(
balance_before < balance_after,
"Balance of validator controller should have increased after payout.",
);
for (_, controller) in &nominators {
let balance = T::Currency::free_balance(controller);
ensure!(!balance.is_zero(), "Payout not given to controller.");
}
}
payout_stakers_alive_staked {
let n in 0 .. T::MaxNominatorRewardedPerValidator::get() as u32;
let (validator, nominators) = create_validator_with_nominators::<T>(
n,
T::MaxNominatorRewardedPerValidator::get() as u32,
false,
true,
RewardDestination::Staked,
)?;
let current_era = CurrentEra::<T>::get().unwrap();
<ErasValidatorPrefs<T>>::insert(current_era, validator.clone(), <Staking<T>>::validators(&validator));
let caller = whitelisted_caller();
let balance_before = T::Currency::free_balance(&validator);
let mut nominator_balances_before = Vec::new();
for (stash, _) in &nominators {
let balance = T::Currency::free_balance(stash);
nominator_balances_before.push(balance);
}
}: payout_stakers(RawOrigin::Signed(caller), validator.clone(), current_era)
verify {
let balance_after = T::Currency::free_balance(&validator);
ensure!(
balance_before < balance_after,
"Balance of validator stash should have increased after payout.",
);
for ((stash, _), balance_before) in nominators.iter().zip(nominator_balances_before.iter()) {
let balance_after = T::Currency::free_balance(stash);
ensure!(
balance_before < &balance_after,
"Balance of nominator stash should have increased after payout.",
);
}
}
rebond {
let l in 1 .. T::MaxUnlockingChunks::get() as u32;
clear_validators_and_nominators::<T>();
let origin_weight = MinNominatorBond::<T>::get()
.max(T::Currency::minimum_balance())
.max(100u32.into());
let scenario = ListScenario::<T>::new(origin_weight, true)?;
let dest_weight = scenario.dest_weight;
let rebond_amount = dest_weight - origin_weight;
let value = rebond_amount / l.into();
assert_ne!(value, Zero::zero());
assert!(value * l.into() + origin_weight > origin_weight);
assert!(value * l.into() + origin_weight <= dest_weight);
let unlock_chunk = UnlockChunk::<BalanceOf<T>> {
value,
era: EraIndex::zero(),
};
let stash = scenario.origin_stash1.clone();
let controller = scenario.origin_controller1;
let mut staking_ledger = Ledger::<T>::get(controller.clone()).unwrap();
for _ in 0 .. l {
staking_ledger.unlocking.try_push(unlock_chunk.clone()).unwrap()
}
Ledger::<T>::insert(controller.clone(), staking_ledger.clone());
let original_bonded: BalanceOf<T> = staking_ledger.active;
whitelist_account!(controller);
}: _(RawOrigin::Signed(controller.clone()), rebond_amount)
verify {
let ledger = Ledger::<T>::get(&controller).ok_or("ledger not created after")?;
let new_bonded: BalanceOf<T> = ledger.active;
assert!(original_bonded < new_bonded);
}
reap_stash {
let s in 1 .. MAX_SPANS;
clear_validators_and_nominators::<T>();
let origin_weight = MinNominatorBond::<T>::get().max(T::Currency::minimum_balance());
let scenario = ListScenario::<T>::new(origin_weight, true)?;
let controller = scenario.origin_controller1.clone();
let stash = scenario.origin_stash1;
add_slashing_spans::<T>(&stash, s);
let l = StakingLedger {
stash: stash.clone(),
active: T::Currency::minimum_balance() - One::one(),
total: T::Currency::minimum_balance() - One::one(),
unlocking: Default::default(),
claimed_rewards: Default::default(),
};
Ledger::<T>::insert(&controller, l);
assert!(Bonded::<T>::contains_key(&stash));
assert!(T::VoterList::contains(&stash));
whitelist_account!(controller);
}: _(RawOrigin::Signed(controller), stash.clone(), s)
verify {
assert!(!Bonded::<T>::contains_key(&stash));
assert!(!T::VoterList::contains(&stash));
}
new_era {
let v in 1 .. 10;
let n in 0 .. 100;
create_validators_with_nominators_for_era::<T>(
v,
n,
MaxNominationsOf::<T>::get() as usize,
false,
None,
)?;
let session_index = SessionIndex::one();
}: {
let validators = Staking::<T>::try_trigger_new_era(session_index, true)
.ok_or("`new_era` failed")?;
assert!(validators.len() == v as usize);
}
#[extra]
payout_all {
let v in 1 .. 10;
let n in 0 .. 100;
create_validators_with_nominators_for_era::<T>(
v,
n,
MaxNominationsOf::<T>::get() as usize,
false,
None,
)?;
let new_validators = Staking::<T>::try_trigger_new_era(SessionIndex::one(), true).unwrap();
assert!(new_validators.len() == v as usize);
let current_era = CurrentEra::<T>::get().unwrap();
let mut points_total = 0;
let mut points_individual = Vec::new();
let mut payout_calls_arg = Vec::new();
for validator in new_validators.iter() {
points_total += 10;
points_individual.push((validator.clone(), 10));
payout_calls_arg.push((validator.clone(), current_era));
}
let reward = EraRewardPoints::<T::AccountId> {
total: points_total,
individual: points_individual.into_iter().collect(),
};
ErasRewardPoints::<T>::insert(current_era, reward);
let total_payout = T::Currency::minimum_balance() * 1000u32.into();
<ErasValidatorReward<T>>::insert(current_era, total_payout);
let caller: T::AccountId = whitelisted_caller();
let origin = RawOrigin::Signed(caller);
let calls: Vec<_> = payout_calls_arg.iter().map(|arg|
Call::<T>::payout_stakers { validator_stash: arg.0.clone(), era: arg.1 }.encode()
).collect();
}: {
for call in calls {
<Call<T> as Decode>::decode(&mut &*call)
.expect("call is encoded above, encoding must be correct")
.dispatch_bypass_filter(origin.clone().into())?;
}
}
#[extra]
do_slash {
let l in 1 .. T::MaxUnlockingChunks::get() as u32;
let (stash, controller) = create_stash_controller::<T>(0, 100, Default::default())?;
let mut staking_ledger = Ledger::<T>::get(controller.clone()).unwrap();
let unlock_chunk = UnlockChunk::<BalanceOf<T>> {
value: 1u32.into(),
era: EraIndex::zero(),
};
for _ in 0 .. l {
staking_ledger.unlocking.try_push(unlock_chunk.clone()).unwrap();
}
Ledger::<T>::insert(controller, staking_ledger);
let slash_amount = T::Currency::minimum_balance() * 10u32.into();
let balance_before = T::Currency::free_balance(&stash);
}: {
crate::slashing::do_slash::<T>(
&stash,
slash_amount,
&mut BalanceOf::<T>::zero(),
&mut NegativeImbalanceOf::<T>::zero(),
EraIndex::zero()
);
} verify {
let balance_after = T::Currency::free_balance(&stash);
assert!(balance_before > balance_after);
}
get_npos_voters {
let v in (MaxValidators::<T>::get() / 2) .. MaxValidators::<T>::get();
let n in (MaxNominators::<T>::get() / 2) .. MaxNominators::<T>::get();
let validators = create_validators_with_nominators_for_era::<T>(
v, n, MaxNominationsOf::<T>::get() as usize, false, None
)?
.into_iter()
.map(|v| T::Lookup::lookup(v).unwrap())
.collect::<Vec<_>>();
assert_eq!(Validators::<T>::count(), v);
assert_eq!(Nominators::<T>::count(), n);
let num_voters = (v + n) as usize;
}: {
let voters = <Staking<T>>::get_npos_voters(DataProviderBounds::default());
assert_eq!(voters.len(), num_voters);
}
get_npos_targets {
let v in (MaxValidators::<T>::get() / 2) .. MaxValidators::<T>::get();
let n = MaxNominators::<T>::get();
let _ = create_validators_with_nominators_for_era::<T>(
v, n, MaxNominationsOf::<T>::get() as usize, false, None
)?;
}: {
let targets = <Staking<T>>::get_npos_targets(DataProviderBounds::default());
assert_eq!(targets.len() as u32, v);
}
set_staking_configs_all_set {
}: set_staking_configs(
RawOrigin::Root,
ConfigOp::Set(BalanceOf::<T>::max_value()),
ConfigOp::Set(BalanceOf::<T>::max_value()),
ConfigOp::Set(u32::MAX),
ConfigOp::Set(u32::MAX),
ConfigOp::Set(Percent::max_value()),
ConfigOp::Set(Perbill::max_value())
) verify {
assert_eq!(MinNominatorBond::<T>::get(), BalanceOf::<T>::max_value());
assert_eq!(MinValidatorBond::<T>::get(), BalanceOf::<T>::max_value());
assert_eq!(MaxNominatorsCount::<T>::get(), Some(u32::MAX));
assert_eq!(MaxValidatorsCount::<T>::get(), Some(u32::MAX));
assert_eq!(ChillThreshold::<T>::get(), Some(Percent::from_percent(100)));
assert_eq!(MinCommission::<T>::get(), Perbill::from_percent(100));
}
set_staking_configs_all_remove {
}: set_staking_configs(
RawOrigin::Root,
ConfigOp::Remove,
ConfigOp::Remove,
ConfigOp::Remove,
ConfigOp::Remove,
ConfigOp::Remove,
ConfigOp::Remove
) verify {
assert!(!MinNominatorBond::<T>::exists());
assert!(!MinValidatorBond::<T>::exists());
assert!(!MaxNominatorsCount::<T>::exists());
assert!(!MaxValidatorsCount::<T>::exists());
assert!(!ChillThreshold::<T>::exists());
assert!(!MinCommission::<T>::exists());
}
chill_other {
clear_validators_and_nominators::<T>();
let origin_weight = MinNominatorBond::<T>::get().max(T::Currency::minimum_balance());
let scenario = ListScenario::<T>::new(origin_weight, true)?;
let controller = scenario.origin_controller1.clone();
let stash = scenario.origin_stash1;
assert!(T::VoterList::contains(&stash));
Staking::<T>::set_staking_configs(
RawOrigin::Root.into(),
ConfigOp::Set(BalanceOf::<T>::max_value()),
ConfigOp::Set(BalanceOf::<T>::max_value()),
ConfigOp::Set(0),
ConfigOp::Set(0),
ConfigOp::Set(Percent::from_percent(0)),
ConfigOp::Set(Zero::zero()),
)?;
let caller = whitelisted_caller();
}: _(RawOrigin::Signed(caller), controller)
verify {
assert!(!T::VoterList::contains(&stash));
}
force_apply_min_commission {
clear_validators_and_nominators::<T>();
let (stash, controller) =
create_stash_controller::<T>(1, 1, RewardDestination::Staked)?;
let validator_prefs =
ValidatorPrefs { commission: Perbill::from_percent(50), ..Default::default() };
Staking::<T>::validate(RawOrigin::Signed(controller).into(), validator_prefs)?;
assert_eq!(
Validators::<T>::get(&stash),
ValidatorPrefs { commission: Perbill::from_percent(50), ..Default::default() }
);
MinCommission::<T>::set(Perbill::from_percent(75));
let caller = whitelisted_caller();
}: _(RawOrigin::Signed(caller), stash.clone())
verify {
assert_eq!(
Validators::<T>::get(&stash),
ValidatorPrefs { commission: Perbill::from_percent(75), ..Default::default() }
);
}
set_min_commission {
let min_commission = Perbill::max_value();
}: _(RawOrigin::Root, min_commission)
verify {
assert_eq!(MinCommission::<T>::get(), Perbill::from_percent(100));
}
impl_benchmark_test_suite!(
Staking,
crate::mock::ExtBuilder::default().has_stakers(true),
crate::mock::Test,
exec_name = build_and_execute
);
}
#[cfg(test)]
mod tests {
use super::*;
use crate::mock::{Balances, ExtBuilder, RuntimeOrigin, Staking, Test};
use frame_support::assert_ok;
#[test]
fn create_validators_with_nominators_for_era_works() {
ExtBuilder::default().build_and_execute(|| {
let v = 10;
let n = 100;
create_validators_with_nominators_for_era::<Test>(
v,
n,
MaxNominationsOf::<Test>::get() as usize,
false,
None,
)
.unwrap();
let count_validators = Validators::<Test>::iter().count();
let count_nominators = Nominators::<Test>::iter().count();
assert_eq!(count_validators, Validators::<Test>::count() as usize);
assert_eq!(count_nominators, Nominators::<Test>::count() as usize);
assert_eq!(count_validators, v as usize);
assert_eq!(count_nominators, n as usize);
});
}
#[test]
fn create_validator_with_nominators_works() {
ExtBuilder::default().build_and_execute(|| {
let n = 10;
let (validator_stash, nominators) = create_validator_with_nominators::<Test>(
n,
<<Test as Config>::MaxNominatorRewardedPerValidator as Get<_>>::get(),
false,
false,
RewardDestination::Staked,
)
.unwrap();
assert_eq!(nominators.len() as u32, n);
let current_era = CurrentEra::<Test>::get().unwrap();
let original_free_balance = Balances::free_balance(&validator_stash);
assert_ok!(Staking::payout_stakers(
RuntimeOrigin::signed(1337),
validator_stash,
current_era
));
let new_free_balance = Balances::free_balance(&validator_stash);
assert!(original_free_balance < new_free_balance);
});
}
#[test]
fn add_slashing_spans_works() {
ExtBuilder::default().build_and_execute(|| {
let n = 10;
let (validator_stash, _nominators) = create_validator_with_nominators::<Test>(
n,
<<Test as Config>::MaxNominatorRewardedPerValidator as Get<_>>::get(),
false,
false,
RewardDestination::Staked,
)
.unwrap();
let num_of_slashing_spans = 20;
add_slashing_spans::<Test>(&validator_stash, num_of_slashing_spans);
let slashing_spans = SlashingSpans::<Test>::get(&validator_stash).unwrap();
assert_eq!(slashing_spans.iter().count(), num_of_slashing_spans as usize);
for i in 0..num_of_slashing_spans {
assert!(SpanSlash::<Test>::contains_key((&validator_stash, i)));
}
assert_ok!(Staking::kill_stash(&validator_stash, num_of_slashing_spans));
assert!(SlashingSpans::<Test>::get(&validator_stash).is_none());
for i in 0..num_of_slashing_spans {
assert!(!SpanSlash::<Test>::contains_key((&validator_stash, i)));
}
});
}
#[test]
fn test_payout_all() {
ExtBuilder::default().build_and_execute(|| {
let v = 10;
let n = 100;
let selected_benchmark = SelectedBenchmark::payout_all;
let c = vec![
(frame_benchmarking::BenchmarkParameter::v, v),
(frame_benchmarking::BenchmarkParameter::n, n),
];
let closure_to_benchmark =
<SelectedBenchmark as frame_benchmarking::BenchmarkingSetup<Test>>::instance(
&selected_benchmark,
&c,
true,
)
.unwrap();
assert_ok!(closure_to_benchmark());
});
}
}