1234567891011121314151617181920212223242526272829303132333435use super::*;3637#[allow(unused)]38use crate::{Pallet as CollatorSelection, BalanceOf};39use frame_benchmarking::{account, benchmarks, impl_benchmark_test_suite, whitelisted_caller};40use frame_support::{41 assert_ok,42 codec::Decode,43 traits::{44 EnsureOrigin,45 fungible::{Inspect, Mutate},46 Get,47 },48};49use frame_system::{EventRecord, RawOrigin};50use pallet_authorship::EventHandler;51use pallet_session::{self as session, SessionManager};52use sp_std::prelude::*;5354use super::*;55#[allow(unused)]56use crate::{BalanceOf, Pallet as CollatorSelection};5758const SEED: u32 = 0;596061macro_rules! whitelist {62 ($acc:ident) => {63 frame_benchmarking::benchmarking::add_to_whitelist(64 frame_system::Account::<T>::hashed_key_for(&$acc).into(),65 );66 };67}6869fn assert_last_event<T: Config>(generic_event: <T as Config>::RuntimeEvent) {70 let events = frame_system::Pallet::<T>::events();71 let system_event: <T as frame_system::Config>::RuntimeEvent = generic_event.into();72 73 let EventRecord { event, .. } = &events[events.len() - 1];74 assert_eq!(event, &system_event);75}7677fn create_funded_user<T: Config>(78 string: &'static str,79 n: u32,80 balance_factor: u32,81) -> T::AccountId {82 let user = account(string, n, SEED);83 let balance = balance_unit::<T>() * balance_factor.into();84 let _ = T::Currency::set_balance(&user, balance);85 user86}8788fn keys<T: Config + session::Config>(c: u32) -> <T as session::Config>::Keys {89 use rand::{RngCore, SeedableRng};9091 let keys = {92 let mut keys = [0u8; 128];9394 if c > 0 {95 let mut rng = rand::rngs::StdRng::seed_from_u64(c as u64);96 rng.fill_bytes(&mut keys);97 }9899 keys100 };101102 Decode::decode(&mut &keys[..]).unwrap()103}104105fn validator<T: Config + session::Config>(c: u32) -> (T::AccountId, <T as session::Config>::Keys) {106 (create_funded_user::<T>("candidate", c, 1000), keys::<T>(c))107}108109fn register_validators<T: Config + session::Config>(count: u32) -> Vec<T::AccountId> {110 let validators = (0..count).map(|c| validator::<T>(c)).collect::<Vec<_>>();111112 for (who, keys) in validators.clone() {113 <session::Pallet<T>>::set_keys(RawOrigin::Signed(who).into(), keys, Vec::new()).unwrap();114 }115116 validators.into_iter().map(|(who, _)| who).collect()117}118119fn register_invulnerables<T: Config>(count: u32) {120 let candidates = (0..count)121 .map(|c| account("candidate", c, SEED))122 .collect::<Vec<_>>();123124 for who in candidates {125 <CollatorSelection<T>>::add_invulnerable(126 T::UpdateOrigin::try_successful_origin().unwrap(),127 who,128 )129 .unwrap();130 }131}132133fn register_candidates<T: Config>(count: u32) {134 let candidates = (0..count)135 .map(|c| account("candidate", c, SEED))136 .collect::<Vec<_>>();137 assert!(T::LicenseBond::get() > 0u32.into(), "Bond cannot be zero!");138139 for who in candidates {140 T::Currency::set_balance(&who, T::LicenseBond::get() * 2u32.into());141 <CollatorSelection<T>>::get_license(RawOrigin::Signed(who.clone()).into()).unwrap();142 <CollatorSelection<T>>::onboard(RawOrigin::Signed(who).into()).unwrap();143 }144}145146fn get_licenses<T: Config>(count: u32) {147 let candidates = (0..count)148 .map(|c| account("candidate", c, SEED))149 .collect::<Vec<_>>();150 assert!(T::LicenseBond::get() > 0u32.into(), "Bond cannot be zero!");151152 for who in candidates {153 T::Currency::set_balance(&who, T::LicenseBond::get() * 2u32.into());154 <CollatorSelection<T>>::get_license(RawOrigin::Signed(who.clone()).into()).unwrap();155 }156}157158159160fn balance_unit<T: Config>() -> BalanceOf<T> {161 T::LicenseBond::get()162}163164165const INITIAL_INVULNERABLES: u32 = 2;166167benchmarks! {168 where_clause { where169 T: Config + pallet_authorship::Config + session::Config170 }171172 173 174 175 add_invulnerable {176 let b in 1 .. T::MaxCollators::get() - INITIAL_INVULNERABLES - 1;177 register_validators::<T>(b);178 register_invulnerables::<T>(b);179180 181182 let new_invulnerable: T::AccountId = whitelisted_caller();183 let bond: BalanceOf<T> = balance_unit::<T>() * 2u32.into();184 <T as Config>::Currency::set_balance(&new_invulnerable, bond);185186 <session::Pallet<T>>::set_keys(187 RawOrigin::Signed(new_invulnerable.clone()).into(),188 keys::<T>(b + 1),189 Vec::new()190 ).unwrap();191192 let root_origin = T::UpdateOrigin::try_successful_origin().unwrap();193 }: {194 assert_ok!(195 <CollatorSelection<T>>::add_invulnerable(root_origin, new_invulnerable.clone())196 );197 }198 verify {199 assert_last_event::<T>(Event::InvulnerableAdded{invulnerable: new_invulnerable}.into());200 }201202 remove_invulnerable {203 let b in 1 .. T::MaxCollators::get() - INITIAL_INVULNERABLES - 1;204 register_validators::<T>(b);205 register_invulnerables::<T>(b);206207 let root_origin = T::UpdateOrigin::try_successful_origin().unwrap();208 let leaving = <Invulnerables<T>>::get().last().unwrap().clone();209 whitelist!(leaving);210 }: {211 assert_ok!(212 <CollatorSelection<T>>::remove_invulnerable(root_origin, leaving.clone())213 );214 }215 verify {216 assert_last_event::<T>(Event::InvulnerableRemoved{invulnerable: leaving}.into());217 }218219 get_license {220 let c in 1 .. T::MaxCollators::get() - 1;221222 register_validators::<T>(c);223 get_licenses::<T>(c);224225 let caller: T::AccountId = whitelisted_caller();226 let bond: BalanceOf<T> = balance_unit::<T>() * 2u32.into();227 T::Currency::set_balance(&caller, bond);228229 <session::Pallet<T>>::set_keys(230 RawOrigin::Signed(caller.clone()).into(),231 keys::<T>(c + 1),232 Vec::new()233 ).unwrap();234235 }: _(RawOrigin::Signed(caller.clone()))236 verify {237 assert_last_event::<T>(Event::LicenseObtained{account_id: caller, deposit: bond / 2u32.into()}.into());238 }239240 241 242 onboard {243 let c in 1 .. T::MaxCollators::get() - INITIAL_INVULNERABLES - 1;244245 register_validators::<T>(c);246 register_candidates::<T>(c);247248 let caller: T::AccountId = whitelisted_caller();249 let bond: BalanceOf<T> = balance_unit::<T>() * 2u32.into();250 T::Currency::set_balance(&caller, bond);251252 let origin = RawOrigin::Signed(caller.clone());253254 <session::Pallet<T>>::set_keys(255 origin.clone().into(),256 keys::<T>(c + 1),257 Vec::new()258 ).unwrap();259260 assert_ok!(261 <CollatorSelection<T>>::get_license(origin.clone().into())262 );263 }: _(origin)264 verify {265 assert_last_event::<T>(Event::CandidateAdded{account_id: caller}.into());266 }267268 269 offboard {270 let c in 1 .. T::MaxCollators::get() - INITIAL_INVULNERABLES;271272 register_validators::<T>(c);273 register_candidates::<T>(c);274275 let leaving = <Candidates<T>>::get().last().unwrap().clone();276 whitelist!(leaving);277 }: _(RawOrigin::Signed(leaving.clone()))278 verify {279 assert_last_event::<T>(Event::CandidateRemoved{account_id: leaving}.into());280 }281282 283 release_license {284 let c in 1 .. T::MaxCollators::get() - INITIAL_INVULNERABLES;285 let bond = balance_unit::<T>();286287 register_validators::<T>(c);288 register_candidates::<T>(c);289290 let leaving = <Candidates<T>>::get().last().unwrap().clone();291 whitelist!(leaving);292 }: _(RawOrigin::Signed(leaving.clone()))293 verify {294 assert_last_event::<T>(Event::LicenseReleased{account_id: leaving, deposit_returned: bond}.into());295 }296297 298 force_release_license {299 let c in 1 .. T::MaxCollators::get() - INITIAL_INVULNERABLES;300 let bond = balance_unit::<T>();301302 register_validators::<T>(c);303 register_candidates::<T>(c);304305 let leaving = <Candidates<T>>::get().last().unwrap().clone();306 whitelist!(leaving);307 let origin = T::UpdateOrigin::try_successful_origin().unwrap();308 }: {309 assert_ok!(310 <CollatorSelection<T>>::force_release_license(origin, leaving.clone())311 );312 }313 verify {314 assert_last_event::<T>(Event::LicenseReleased{account_id: leaving, deposit_returned: bond}.into());315 }316317 318 note_author {319 T::Currency::set_balance(320 &<CollatorSelection<T>>::account_id(),321 balance_unit::<T>() * 4u32.into(),322 );323 let author = account("author", 0, SEED);324 let new_block: BlockNumberFor<T>= 10u32.into();325326 frame_system::Pallet::<T>::set_block_number(new_block);327 assert!(T::Currency::balance(&author) == 0u32.into());328 }: {329 <CollatorSelection<T> as EventHandler<_, _>>::note_author(author.clone())330 } verify {331 assert!(T::Currency::balance(&author) > 0u32.into());332 assert_eq!(frame_system::Pallet::<T>::block_number(), new_block);333 }334335 336 new_session {337 let r in 1 .. T::MaxCollators::get() - INITIAL_INVULNERABLES;338 let c in 1 .. T::MaxCollators::get() - INITIAL_INVULNERABLES;339340 frame_system::Pallet::<T>::set_block_number(0u32.into());341342 register_validators::<T>(c);343 register_candidates::<T>(c);344345 let new_block: BlockNumberFor<T>= 1800u32.into();346 let zero_block: T::BlockNumber = 0u32.into();347 let candidates = <Candidates<T>>::get();348349 let non_removals = c.saturating_sub(r);350351 for i in 0..c {352 <LastAuthoredBlock<T>>::insert(candidates[i as usize].clone(), zero_block);353 }354355 if non_removals > 0 {356 for i in 0..non_removals {357 <LastAuthoredBlock<T>>::insert(candidates[i as usize].clone(), new_block);358 }359 } else {360 for i in 0..c {361 <LastAuthoredBlock<T>>::insert(candidates[i as usize].clone(), new_block);362 }363 }364365 let pre_length = <Candidates<T>>::get().len();366367 frame_system::Pallet::<T>::set_block_number(new_block);368369 assert!(<Candidates<T>>::get().len() == c as usize);370 }: {371 <CollatorSelection<T> as SessionManager<_>>::new_session(0)372 } verify {373 if c > r {374 assert!(<Candidates<T>>::get().len() < pre_length);375 } else {376 assert!(<Candidates<T>>::get().len() == pre_length);377 }378 }379}380381impl_benchmark_test_suite!(382 CollatorSelection,383 crate::mock::new_test_ext(),384 crate::mock::Test,385);