1234567891011121314151617181920212223242526272829303132333435use super::*;3637#[allow(unused)]38use crate::Pallet as CollatorSelection;39use frame_benchmarking::{account, benchmarks, impl_benchmark_test_suite, whitelisted_caller};40use frame_support::{41 assert_ok,42 codec::Decode,43 traits::{Currency, EnsureOrigin, Get},44};45use frame_system::{EventRecord, RawOrigin};46use pallet_authorship::EventHandler;47use pallet_session::{self as session, SessionManager};48use sp_std::prelude::*;4950pub type BalanceOf<T> =51 <<T as Config>::Currency as Currency<<T as frame_system::Config>::AccountId>>::Balance;5253const SEED: u32 = 0;545556macro_rules! whitelist {57 ($acc:ident) => {58 frame_benchmarking::benchmarking::add_to_whitelist(59 frame_system::Account::<T>::hashed_key_for(&$acc).into(),60 );61 };62}6364fn assert_last_event<T: Config>(generic_event: <T as Config>::RuntimeEvent) {65 let events = frame_system::Pallet::<T>::events();66 let system_event: <T as frame_system::Config>::RuntimeEvent = generic_event.into();67 68 let EventRecord { event, .. } = &events[events.len() - 1];69 assert_eq!(event, &system_event);70}7172fn create_funded_user<T: Config>(73 string: &'static str,74 n: u32,75 balance_factor: u32,76) -> T::AccountId {77 let user = account(string, n, SEED);78 let balance = T::Currency::minimum_balance() * balance_factor.into();79 let _ = T::Currency::make_free_balance_be(&user, balance);80 user81}8283fn keys<T: Config + session::Config>(c: u32) -> <T as session::Config>::Keys {84 use rand::{RngCore, SeedableRng};8586 let keys = {87 let mut keys = [0u8; 128];8889 if c > 0 {90 let mut rng = rand::rngs::StdRng::seed_from_u64(c as u64);91 rng.fill_bytes(&mut keys);92 }9394 keys95 };9697 Decode::decode(&mut &keys[..]).unwrap()98}99100fn validator<T: Config + session::Config>(c: u32) -> (T::AccountId, <T as session::Config>::Keys) {101 (create_funded_user::<T>("candidate", c, 1000), keys::<T>(c))102}103104fn register_validators<T: Config + session::Config>(count: u32) -> Vec<T::AccountId> {105 let validators = (0..count).map(|c| validator::<T>(c)).collect::<Vec<_>>();106107 for (who, keys) in validators.clone() {108 <session::Pallet<T>>::set_keys(RawOrigin::Signed(who).into(), keys, Vec::new()).unwrap();109 }110111 validators.into_iter().map(|(who, _)| who).collect()112}113114fn register_candidates<T: Config>(count: u32) {115 let candidates = (0..count).map(|c| account("candidate", c, SEED)).collect::<Vec<_>>();116 assert!(<CandidacyBond<T>>::get() > 0u32.into(), "Bond cannot be zero!");117118 for who in candidates {119 T::Currency::make_free_balance_be(&who, <CandidacyBond<T>>::get() * 2u32.into());120 <CollatorSelection<T>>::register_as_candidate(RawOrigin::Signed(who).into()).unwrap();121 }122}123124benchmarks! {125 where_clause { where T: pallet_authorship::Config + session::Config }126127 set_invulnerables {128 let b in 1 .. T::MaxInvulnerables::get();129 let new_invulnerables = register_validators::<T>(b);130 let origin = T::UpdateOrigin::successful_origin();131 }: {132 assert_ok!(133 <CollatorSelection<T>>::set_invulnerables(origin, new_invulnerables.clone())134 );135 }136 verify {137 assert_last_event::<T>(Event::NewInvulnerables{invulnerables: new_invulnerables}.into());138 }139140 set_desired_candidates {141 let max: u32 = 999;142 let origin = T::UpdateOrigin::successful_origin();143 }: {144 assert_ok!(145 <CollatorSelection<T>>::set_desired_candidates(origin, max.clone())146 );147 }148 verify {149 assert_last_event::<T>(Event::NewDesiredCandidates{desired_candidates: max}.into());150 }151152 set_candidacy_bond {153 let bond_amount: BalanceOf<T> = T::Currency::minimum_balance() * 10u32.into();154 let origin = T::UpdateOrigin::successful_origin();155 }: {156 assert_ok!(157 <CollatorSelection<T>>::set_candidacy_bond(origin, bond_amount.clone())158 );159 }160 verify {161 assert_last_event::<T>(Event::NewCandidacyBond{bond_amount}.into());162 }163164 165 166 register_as_candidate {167 let c in 1 .. T::MaxCandidates::get();168169 <CandidacyBond<T>>::put(T::Currency::minimum_balance());170 <DesiredCandidates<T>>::put(c + 1);171172 register_validators::<T>(c);173 register_candidates::<T>(c);174175 let caller: T::AccountId = whitelisted_caller();176 let bond: BalanceOf<T> = T::Currency::minimum_balance() * 2u32.into();177 T::Currency::make_free_balance_be(&caller, bond.clone());178179 <session::Pallet<T>>::set_keys(180 RawOrigin::Signed(caller.clone()).into(),181 keys::<T>(c + 1),182 Vec::new()183 ).unwrap();184185 }: _(RawOrigin::Signed(caller.clone()))186 verify {187 assert_last_event::<T>(Event::CandidateAdded{account_id: caller, deposit: bond / 2u32.into()}.into());188 }189190 191 leave_intent {192 let c in (T::MinCandidates::get() + 1) .. T::MaxCandidates::get();193 <CandidacyBond<T>>::put(T::Currency::minimum_balance());194 <DesiredCandidates<T>>::put(c);195196 register_validators::<T>(c);197 register_candidates::<T>(c);198199 let leaving = <Candidates<T>>::get().last().unwrap().who.clone();200 whitelist!(leaving);201 }: _(RawOrigin::Signed(leaving.clone()))202 verify {203 assert_last_event::<T>(Event::CandidateRemoved{account_id: leaving}.into());204 }205206 207 note_author {208 <CandidacyBond<T>>::put(T::Currency::minimum_balance());209 T::Currency::make_free_balance_be(210 &<CollatorSelection<T>>::account_id(),211 T::Currency::minimum_balance() * 4u32.into(),212 );213 let author = account("author", 0, SEED);214 let new_block: T::BlockNumber = 10u32.into();215216 frame_system::Pallet::<T>::set_block_number(new_block);217 assert!(T::Currency::free_balance(&author) == 0u32.into());218 }: {219 <CollatorSelection<T> as EventHandler<_, _>>::note_author(author.clone())220 } verify {221 assert!(T::Currency::free_balance(&author) > 0u32.into());222 assert_eq!(frame_system::Pallet::<T>::block_number(), new_block);223 }224225 226 new_session {227 let r in 1 .. T::MaxCandidates::get();228 let c in 1 .. T::MaxCandidates::get();229230 <CandidacyBond<T>>::put(T::Currency::minimum_balance());231 <DesiredCandidates<T>>::put(c);232 frame_system::Pallet::<T>::set_block_number(0u32.into());233234 register_validators::<T>(c);235 register_candidates::<T>(c);236237 let new_block: T::BlockNumber = 1800u32.into();238 let zero_block: T::BlockNumber = 0u32.into();239 let candidates = <Candidates<T>>::get();240241 let non_removals = c.saturating_sub(r);242243 for i in 0..c {244 <LastAuthoredBlock<T>>::insert(candidates[i as usize].who.clone(), zero_block);245 }246247 if non_removals > 0 {248 for i in 0..non_removals {249 <LastAuthoredBlock<T>>::insert(candidates[i as usize].who.clone(), new_block);250 }251 } else {252 for i in 0..c {253 <LastAuthoredBlock<T>>::insert(candidates[i as usize].who.clone(), new_block);254 }255 }256257 let pre_length = <Candidates<T>>::get().len();258259 frame_system::Pallet::<T>::set_block_number(new_block);260261 assert!(<Candidates<T>>::get().len() == c as usize);262 }: {263 <CollatorSelection<T> as SessionManager<_>>::new_session(0)264 } verify {265 if c > r && non_removals >= T::MinCandidates::get() {266 assert!(<Candidates<T>>::get().len() < pre_length);267 } else if c > r && non_removals < T::MinCandidates::get() {268 assert!(<Candidates<T>>::get().len() == T::MinCandidates::get() as usize);269 } else {270 assert!(<Candidates<T>>::get().len() == pre_length);271 }272 }273}274275impl_benchmark_test_suite!(CollatorSelection, crate::mock::new_test_ext(), crate::mock::Test,);