Files
pezkuwi-subxt/substrate/frame/staking/src/testing_utils.rs
T
Ross Bulat 56940bc874 Staking::{bond, set_controller} to set controllers to stash only. (#14039)
* update set_controller

* clone

* bond uses `stash`

* remove controller from bond(), chill_other test works

* remove ctlr from testing_utils &  dead ctlr -> dead payee

* mvs controllers to stashes for 3 tests

* migrate mock bond fns & fix 1 test

* mvs controllers to stashes for 7 tests

* mvs controllers to stashes for 9 tests

* remove double_controlling_should_fail

* remove double_staking_should_fail

* mvs controllers to stashes for 10 tests

* mvs controllers to stashes for 2 tests

* remove payout_creates_controller

* mvs controllers to stashes for 27 tests

* remove println!

* fix rewards_should_work

* fix test_payout_stakers

* fix bond benchmark

* clone

* rm unused import

* rm unused var

* rm controller from create_offender

* fix GenesisConfig stakers

* fix controllers in consensus pallets

* fix unqiue controller in chain_spec

* fmt

* fix create_offender

* fix set_controller benchmark

* add TODO

* create_unique_stash_controller

* staking benchmarks working

* fmt

* fix args

* rm println

* import

* import

* fix fast unstake tests

* fix staking-tests-e2e

* fix root-offenses

* fmt

* differentiate controller to stash

* bring back change_controller_works w. unique ctrl

* bring back double_staking_should_fail

* double_controlling_attempt_should_fail

* bring back payout_creates_controller

* add commnet to controller balances

* + set_controller call description

* fmt

* rm clones

* fmt

* clippy fixes

* fmt

* update README

* small fixes

* use controller_to_be_deprecated

* .comment

* comment

* bump zombienet version

* ci

---------

Co-authored-by: parity-processbot <>
Co-authored-by: Javier Viola <javier@parity.io>
2023-05-11 18:22:15 +00:00

241 lines
8.4 KiB
Rust

// 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.
//! Testing utils for staking. Provides some common functions to setup staking state, such as
//! bonding validators, nominators, and generating different types of solutions.
use crate::{Pallet as Staking, *};
use frame_benchmarking::account;
use frame_system::RawOrigin;
use rand_chacha::{
rand_core::{RngCore, SeedableRng},
ChaChaRng,
};
use sp_io::hashing::blake2_256;
use frame_election_provider_support::SortedListProvider;
use frame_support::{pallet_prelude::*, traits::Currency};
use sp_runtime::{traits::StaticLookup, Perbill};
use sp_std::prelude::*;
const SEED: u32 = 0;
/// This function removes all validators and nominators from storage.
pub fn clear_validators_and_nominators<T: Config>() {
#[allow(deprecated)]
Validators::<T>::remove_all();
// whenever we touch nominators counter we should update `T::VoterList` as well.
#[allow(deprecated)]
Nominators::<T>::remove_all();
// NOTE: safe to call outside block production
T::VoterList::unsafe_clear();
}
/// Grab a funded user.
pub fn create_funded_user<T: Config>(
string: &'static str,
n: u32,
balance_factor: u32,
) -> T::AccountId {
let user = account(string, n, SEED);
let balance = T::Currency::minimum_balance() * balance_factor.into();
let _ = T::Currency::make_free_balance_be(&user, balance);
user
}
/// Grab a funded user with max Balance.
pub fn create_funded_user_with_balance<T: Config>(
string: &'static str,
n: u32,
balance: BalanceOf<T>,
) -> T::AccountId {
let user = account(string, n, SEED);
let _ = T::Currency::make_free_balance_be(&user, balance);
user
}
/// Create a stash and controller pair.
pub fn create_stash_controller<T: Config>(
n: u32,
balance_factor: u32,
destination: RewardDestination<T::AccountId>,
) -> Result<(T::AccountId, T::AccountId), &'static str> {
let staker = create_funded_user::<T>("stash", n, balance_factor);
let amount = T::Currency::minimum_balance() * (balance_factor / 10).max(1).into();
Staking::<T>::bond(RawOrigin::Signed(staker.clone()).into(), amount, destination)?;
Ok((staker.clone(), staker))
}
/// Create a unique stash and controller pair.
pub fn create_unique_stash_controller<T: Config>(
n: u32,
balance_factor: u32,
destination: RewardDestination<T::AccountId>,
dead_controller: bool,
) -> Result<(T::AccountId, T::AccountId), &'static str> {
let stash = create_funded_user::<T>("stash", n, balance_factor);
let controller = if dead_controller {
create_funded_user::<T>("controller", n, 0)
} else {
create_funded_user::<T>("controller", n, balance_factor)
};
let amount = T::Currency::minimum_balance() * (balance_factor / 10).max(1).into();
Staking::<T>::bond(RawOrigin::Signed(stash.clone()).into(), amount, destination)?;
// update ledger to be a *different* controller to stash
if let Some(l) = Ledger::<T>::take(&stash) {
<Ledger<T>>::insert(&controller, l);
}
// update bonded account to be unique controller
<Bonded<T>>::insert(&stash, &controller);
Ok((stash, controller))
}
/// Create a stash and controller pair with fixed balance.
pub fn create_stash_controller_with_balance<T: Config>(
n: u32,
balance: crate::BalanceOf<T>,
destination: RewardDestination<T::AccountId>,
) -> Result<(T::AccountId, T::AccountId), &'static str> {
let staker = create_funded_user_with_balance::<T>("stash", n, balance);
Staking::<T>::bond(RawOrigin::Signed(staker.clone()).into(), balance, destination)?;
Ok((staker.clone(), staker))
}
/// Create a stash and controller pair, where payouts go to a dead payee account. This is used to
/// test worst case payout scenarios.
pub fn create_stash_and_dead_payee<T: Config>(
n: u32,
balance_factor: u32,
) -> Result<(T::AccountId, T::AccountId), &'static str> {
let staker = create_funded_user::<T>("stash", n, 0);
// payee has no funds
let payee = create_funded_user::<T>("payee", n, 0);
let amount = T::Currency::minimum_balance() * (balance_factor / 10).max(1).into();
Staking::<T>::bond(
RawOrigin::Signed(staker.clone()).into(),
amount,
RewardDestination::Account(payee),
)?;
Ok((staker.clone(), staker))
}
/// create `max` validators.
pub fn create_validators<T: Config>(
max: u32,
balance_factor: u32,
) -> Result<Vec<AccountIdLookupOf<T>>, &'static str> {
create_validators_with_seed::<T>(max, balance_factor, 0)
}
/// create `max` validators, with a seed to help unintentional prevent account collisions.
pub fn create_validators_with_seed<T: Config>(
max: u32,
balance_factor: u32,
seed: u32,
) -> Result<Vec<AccountIdLookupOf<T>>, &'static str> {
let mut validators: Vec<AccountIdLookupOf<T>> = Vec::with_capacity(max as usize);
for i in 0..max {
let (stash, controller) =
create_stash_controller::<T>(i + seed, balance_factor, RewardDestination::Staked)?;
let validator_prefs =
ValidatorPrefs { commission: Perbill::from_percent(50), ..Default::default() };
Staking::<T>::validate(RawOrigin::Signed(controller).into(), validator_prefs)?;
let stash_lookup = T::Lookup::unlookup(stash);
validators.push(stash_lookup);
}
Ok(validators)
}
/// This function generates validators and nominators who are randomly nominating
/// `edge_per_nominator` random validators (until `to_nominate` if provided).
///
/// NOTE: This function will remove any existing validators or nominators to ensure
/// we are working with a clean state.
///
/// Parameters:
/// - `validators`: number of bonded validators
/// - `nominators`: number of bonded nominators.
/// - `edge_per_nominator`: number of edge (vote) per nominator.
/// - `randomize_stake`: whether to randomize the stakes.
/// - `to_nominate`: if `Some(n)`, only the first `n` bonded validator are voted upon. Else, all of
/// them are considered and `edge_per_nominator` random validators are voted for.
///
/// Return the validators chosen to be nominated.
pub fn create_validators_with_nominators_for_era<T: Config>(
validators: u32,
nominators: u32,
edge_per_nominator: usize,
randomize_stake: bool,
to_nominate: Option<u32>,
) -> Result<Vec<AccountIdLookupOf<T>>, &'static str> {
clear_validators_and_nominators::<T>();
let mut validators_stash: Vec<AccountIdLookupOf<T>> = Vec::with_capacity(validators as usize);
let mut rng = ChaChaRng::from_seed(SEED.using_encoded(blake2_256));
// Create validators
for i in 0..validators {
let balance_factor = if randomize_stake { rng.next_u32() % 255 + 10 } else { 100u32 };
let (v_stash, v_controller) =
create_stash_controller::<T>(i, balance_factor, RewardDestination::Staked)?;
let validator_prefs =
ValidatorPrefs { commission: Perbill::from_percent(50), ..Default::default() };
Staking::<T>::validate(RawOrigin::Signed(v_controller.clone()).into(), validator_prefs)?;
let stash_lookup = T::Lookup::unlookup(v_stash.clone());
validators_stash.push(stash_lookup.clone());
}
let to_nominate = to_nominate.unwrap_or(validators_stash.len() as u32) as usize;
let validator_chosen = validators_stash[0..to_nominate].to_vec();
// Create nominators
for j in 0..nominators {
let balance_factor = if randomize_stake { rng.next_u32() % 255 + 10 } else { 100u32 };
let (_n_stash, n_controller) =
create_stash_controller::<T>(u32::MAX - j, balance_factor, RewardDestination::Staked)?;
// Have them randomly validate
let mut available_validators = validator_chosen.clone();
let mut selected_validators: Vec<AccountIdLookupOf<T>> =
Vec::with_capacity(edge_per_nominator);
for _ in 0..validators.min(edge_per_nominator as u32) {
let selected = rng.next_u32() as usize % available_validators.len();
let validator = available_validators.remove(selected);
selected_validators.push(validator);
}
Staking::<T>::nominate(
RawOrigin::Signed(n_controller.clone()).into(),
selected_validators,
)?;
}
ValidatorCount::<T>::put(validators);
Ok(validator_chosen)
}
/// get the current era.
pub fn current_era<T: Config>() -> EraIndex {
<Pallet<T>>::current_era().unwrap_or(0)
}