1use crate::{Pallet as Staking, *};
22use frame_benchmarking::account;
23use frame_system::RawOrigin;
24use rand_chacha::{
25 rand_core::{RngCore, SeedableRng},
26 ChaChaRng,
27};
28use sp_io::hashing::blake2_256;
29
30use frame_election_provider_support::SortedListProvider;
31use frame_support::pallet_prelude::*;
32use sp_runtime::{traits::StaticLookup, Perbill};
33
34const SEED: u32 = 0;
35
36pub fn clear_validators_and_nominators<T: Config>() {
38 #[allow(deprecated)]
39 Validators::<T>::remove_all();
40
41 #[allow(deprecated)]
43 Nominators::<T>::remove_all();
44
45 T::VoterList::unsafe_clear();
47}
48
49pub fn create_funded_user<T: Config>(
51 string: &'static str,
52 n: u32,
53 balance_factor: u32,
54) -> T::AccountId {
55 let user = account(string, n, SEED);
56 let balance = asset::existential_deposit::<T>() * balance_factor.into();
57 let _ = asset::set_stakeable_balance::<T>(&user, balance);
58 user
59}
60
61pub fn create_funded_user_with_balance<T: Config>(
63 string: &'static str,
64 n: u32,
65 balance: BalanceOf<T>,
66) -> T::AccountId {
67 let user = account(string, n, SEED);
68 let _ = asset::set_stakeable_balance::<T>(&user, balance);
69 user
70}
71
72pub fn create_stash_controller<T: Config>(
74 n: u32,
75 balance_factor: u32,
76 destination: RewardDestination<T::AccountId>,
77) -> Result<(T::AccountId, T::AccountId), &'static str> {
78 let staker = create_funded_user::<T>("stash", n, balance_factor);
79 let amount =
80 asset::existential_deposit::<T>().max(1u64.into()) * (balance_factor / 10).max(1).into();
81 Staking::<T>::bond(RawOrigin::Signed(staker.clone()).into(), amount, destination)?;
82 Ok((staker.clone(), staker))
83}
84
85pub fn create_unique_stash_controller<T: Config>(
87 n: u32,
88 balance_factor: u32,
89 destination: RewardDestination<T::AccountId>,
90 dead_controller: bool,
91) -> Result<(T::AccountId, T::AccountId), &'static str> {
92 let stash = create_funded_user::<T>("stash", n, balance_factor);
93
94 let controller = if dead_controller {
95 create_funded_user::<T>("controller", n, 0)
96 } else {
97 create_funded_user::<T>("controller", n, balance_factor)
98 };
99 let amount = asset::existential_deposit::<T>() * (balance_factor / 10).max(1).into();
100 Staking::<T>::bond(RawOrigin::Signed(stash.clone()).into(), amount, destination)?;
101
102 if let Some(l) = Ledger::<T>::take(&stash) {
104 <Ledger<T>>::insert(&controller, l);
105 }
106 <Bonded<T>>::insert(&stash, &controller);
108
109 Ok((stash, controller))
110}
111
112pub fn create_stash_controller_with_balance<T: Config>(
114 n: u32,
115 balance: crate::BalanceOf<T>,
116 destination: RewardDestination<T::AccountId>,
117) -> Result<(T::AccountId, T::AccountId), &'static str> {
118 let staker = create_funded_user_with_balance::<T>("stash", n, balance);
119 Staking::<T>::bond(RawOrigin::Signed(staker.clone()).into(), balance, destination)?;
120 Ok((staker.clone(), staker))
121}
122
123pub fn create_stash_and_dead_payee<T: Config>(
126 n: u32,
127 balance_factor: u32,
128) -> Result<(T::AccountId, T::AccountId), &'static str> {
129 let staker = create_funded_user::<T>("stash", n, 0);
130 let payee = create_funded_user::<T>("payee", n, 0);
132 let amount = asset::existential_deposit::<T>() * (balance_factor / 10).max(1).into();
133 Staking::<T>::bond(
134 RawOrigin::Signed(staker.clone()).into(),
135 amount,
136 RewardDestination::Account(payee),
137 )?;
138 Ok((staker.clone(), staker))
139}
140
141pub fn create_validators<T: Config>(
143 max: u32,
144 balance_factor: u32,
145) -> Result<Vec<AccountIdLookupOf<T>>, &'static str> {
146 create_validators_with_seed::<T>(max, balance_factor, 0)
147}
148
149pub fn create_validators_with_seed<T: Config>(
151 max: u32,
152 balance_factor: u32,
153 seed: u32,
154) -> Result<Vec<AccountIdLookupOf<T>>, &'static str> {
155 let mut validators: Vec<AccountIdLookupOf<T>> = Vec::with_capacity(max as usize);
156 for i in 0..max {
157 let (stash, controller) =
158 create_stash_controller::<T>(i + seed, balance_factor, RewardDestination::Staked)?;
159 let validator_prefs =
160 ValidatorPrefs { commission: Perbill::from_percent(50), ..Default::default() };
161 Staking::<T>::validate(RawOrigin::Signed(controller).into(), validator_prefs)?;
162 let stash_lookup = T::Lookup::unlookup(stash);
163 validators.push(stash_lookup);
164 }
165 Ok(validators)
166}
167
168pub fn create_validators_with_nominators_for_era<T: Config>(
184 validators: u32,
185 nominators: u32,
186 edge_per_nominator: usize,
187 randomize_stake: bool,
188 to_nominate: Option<u32>,
189) -> Result<Vec<AccountIdLookupOf<T>>, &'static str> {
190 clear_validators_and_nominators::<T>();
191
192 let mut validators_stash: Vec<AccountIdLookupOf<T>> = Vec::with_capacity(validators as usize);
193 let mut rng = ChaChaRng::from_seed(SEED.using_encoded(blake2_256));
194
195 for i in 0..validators {
197 let balance_factor = if randomize_stake { rng.next_u32() % 255 + 10 } else { 100u32 };
198 let (v_stash, v_controller) =
199 create_stash_controller::<T>(i, balance_factor, RewardDestination::Staked)?;
200 let validator_prefs =
201 ValidatorPrefs { commission: Perbill::from_percent(50), ..Default::default() };
202 Staking::<T>::validate(RawOrigin::Signed(v_controller.clone()).into(), validator_prefs)?;
203 let stash_lookup = T::Lookup::unlookup(v_stash.clone());
204 validators_stash.push(stash_lookup.clone());
205 }
206
207 let to_nominate = to_nominate.unwrap_or(validators_stash.len() as u32) as usize;
208 let validator_chosen = validators_stash[0..to_nominate].to_vec();
209
210 for j in 0..nominators {
212 let balance_factor = if randomize_stake { rng.next_u32() % 255 + 10 } else { 100u32 };
213 let (_n_stash, n_controller) =
214 create_stash_controller::<T>(u32::MAX - j, balance_factor, RewardDestination::Staked)?;
215
216 let mut available_validators = validator_chosen.clone();
218 let mut selected_validators: Vec<AccountIdLookupOf<T>> =
219 Vec::with_capacity(edge_per_nominator);
220
221 for _ in 0..validators.min(edge_per_nominator as u32) {
222 let selected = rng.next_u32() as usize % available_validators.len();
223 let validator = available_validators.remove(selected);
224 selected_validators.push(validator);
225 }
226 Staking::<T>::nominate(
227 RawOrigin::Signed(n_controller.clone()).into(),
228 selected_validators,
229 )?;
230 }
231
232 ValidatorCount::<T>::put(validators);
233
234 Ok(validator_chosen)
235}
236
237pub fn current_era<T: Config>() -> EraIndex {
239 CurrentEra::<T>::get().unwrap_or(0)
240}
241
242pub fn migrate_to_old_currency<T: Config>(who: T::AccountId) {
243 use frame_support::traits::LockableCurrency;
244 let staked = asset::staked::<T>(&who);
245
246 T::OldCurrency::set_lock(
248 STAKING_ID,
249 &who,
250 staked,
251 frame_support::traits::WithdrawReasons::all(),
252 );
253 asset::kill_stake::<T>(&who).expect("remove hold failed");
255
256 frame_system::Pallet::<T>::inc_consumers(&who).expect("increment consumer failed");
258}