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)116 .map(|c| account("candidate", c, SEED))117 .collect::<Vec<_>>();118 assert!(119 <LicenseBond<T>>::get() > 0u32.into(),120 "Bond cannot be zero!"121 );122123 for who in candidates {124 T::Currency::make_free_balance_be(&who, <LicenseBond<T>>::get() * 2u32.into());125 <CollatorSelection<T>>::register_as_candidate(RawOrigin::Signed(who).into()).unwrap();126 }127}128129benchmarks! {130 where_clause { where T: pallet_authorship::Config + session::Config }131132 set_invulnerables {133 let b in 1 .. T::MaxCollators::get();134 let new_invulnerables = register_validators::<T>(b);135 let origin = T::UpdateOrigin::successful_origin();136 }: {137 assert_ok!(138 <CollatorSelection<T>>::set_invulnerables(origin, new_invulnerables.clone())139 );140 }141 verify {142 assert_last_event::<T>(Event::NewInvulnerables{invulnerables: new_invulnerables}.into());143 }144145 set_desired_collators {146 let max: u32 = 999;147 let origin = T::UpdateOrigin::successful_origin();148 }: {149 assert_ok!(150 <CollatorSelection<T>>::set_desired_collators(origin, max.clone())151 );152 }153 verify {154 assert_last_event::<T>(Event::NewDesiredCollators{desired_collators: max}.into());155 }156157 set_license_bond {158 let bond_amount: BalanceOf<T> = T::Currency::minimum_balance() * 10u32.into();159 let origin = T::UpdateOrigin::successful_origin();160 }: {161 assert_ok!(162 <CollatorSelection<T>>::set_license_bond(origin, bond_amount.clone())163 );164 }165 verify {166 assert_last_event::<T>(Event::NewLicenseBond{bond_amount}.into());167 }168169 170 171 register_as_candidate {172 let c in 1 .. T::MaxCollators::get();173174 <LicenseBond<T>>::put(T::Currency::minimum_balance());175 <DesiredCollators<T>>::put(c + 1);176177 register_validators::<T>(c);178 register_candidates::<T>(c);179180 let caller: T::AccountId = whitelisted_caller();181 let bond: BalanceOf<T> = T::Currency::minimum_balance() * 2u32.into();182 T::Currency::make_free_balance_be(&caller, bond.clone());183184 <session::Pallet<T>>::set_keys(185 RawOrigin::Signed(caller.clone()).into(),186 keys::<T>(c + 1),187 Vec::new()188 ).unwrap();189190 }: _(RawOrigin::Signed(caller.clone()))191 verify {192 assert_last_event::<T>(Event::CandidateAdded{account_id: caller, deposit: bond / 2u32.into()}.into());193 }194195 196 leave_intent {197 let c in (T::MinCandidates::get() + 1) .. T::MaxCollators::get();198 <LicenseBond<T>>::put(T::Currency::minimum_balance());199 <DesiredCollators<T>>::put(c);200201 register_validators::<T>(c);202 register_candidates::<T>(c);203204 let leaving = <Candidates<T>>::get().last().unwrap().who.clone();205 whitelist!(leaving);206 }: _(RawOrigin::Signed(leaving.clone()))207 verify {208 209 assert_last_event::<T>(Event::CandidateRemoved{account_id: leaving, deposit_returned: bond / 2u32.into() }.into());210 }211212 213 note_author {214 <LicenseBond<T>>::put(T::Currency::minimum_balance());215 T::Currency::make_free_balance_be(216 &<CollatorSelection<T>>::account_id(),217 T::Currency::minimum_balance() * 4u32.into(),218 );219 let author = account("author", 0, SEED);220 let new_block: T::BlockNumber = 10u32.into();221222 frame_system::Pallet::<T>::set_block_number(new_block);223 assert!(T::Currency::free_balance(&author) == 0u32.into());224 }: {225 <CollatorSelection<T> as EventHandler<_, _>>::note_author(author.clone())226 } verify {227 assert!(T::Currency::free_balance(&author) > 0u32.into());228 assert_eq!(frame_system::Pallet::<T>::block_number(), new_block);229 }230231 232 new_session {233 let r in 1 .. T::MaxCollators::get();234 let c in 1 .. T::MaxCollators::get();235236 <LicenseBond<T>>::put(T::Currency::minimum_balance());237 <DesiredCollators<T>>::put(c);238 frame_system::Pallet::<T>::set_block_number(0u32.into());239240 register_validators::<T>(c);241 register_candidates::<T>(c);242243 let new_block: T::BlockNumber = 1800u32.into();244 let zero_block: T::BlockNumber = 0u32.into();245 let candidates = <Candidates<T>>::get();246247 let non_removals = c.saturating_sub(r);248249 for i in 0..c {250 <LastAuthoredBlock<T>>::insert(candidates[i as usize].who.clone(), zero_block);251 }252253 if non_removals > 0 {254 for i in 0..non_removals {255 <LastAuthoredBlock<T>>::insert(candidates[i as usize].who.clone(), new_block);256 }257 } else {258 for i in 0..c {259 <LastAuthoredBlock<T>>::insert(candidates[i as usize].who.clone(), new_block);260 }261 }262263 let pre_length = <Candidates<T>>::get().len();264265 frame_system::Pallet::<T>::set_block_number(new_block);266267 assert!(<Candidates<T>>::get().len() == c as usize);268 }: {269 <CollatorSelection<T> as SessionManager<_>>::new_session(0)270 } verify {271 if c > r && non_removals >= T::MinCandidates::get() {272 assert!(<Candidates<T>>::get().len() < pre_length);273 } else if c > r && non_removals < T::MinCandidates::get() {274 assert!(<Candidates<T>>::get().len() == T::MinCandidates::get() as usize);275 } else {276 assert!(<Candidates<T>>::get().len() == pre_length);277 }278 }279}280281impl_benchmark_test_suite!(282 CollatorSelection,283 crate::mock::new_test_ext(),284 crate::mock::Test,285);