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::{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 pallet_configuration::{53 self as configuration, BalanceOf,54 CollatorSelectionDesiredCollatorsOverride as DesiredCollators,55 CollatorSelectionLicenseBondOverride as LicenseBond,56};57use sp_std::prelude::*;5859const SEED: u32 = 0;606162macro_rules! whitelist {63 ($acc:ident) => {64 frame_benchmarking::benchmarking::add_to_whitelist(65 frame_system::Account::<T>::hashed_key_for(&$acc).into(),66 );67 };68}6970fn assert_last_event<T: Config>(generic_event: <T as Config>::RuntimeEvent) {71 let events = frame_system::Pallet::<T>::events();72 let system_event: <T as frame_system::Config>::RuntimeEvent = generic_event.into();73 74 let EventRecord { event, .. } = &events[events.len() - 1];75 assert_eq!(event, &system_event);76}7778fn create_funded_user<T: Config>(79 string: &'static str,80 n: u32,81 balance_factor: u32,82) -> T::AccountId {83 let user = account(string, n, SEED);84 let balance = balance_unit::<T>() * balance_factor.into();85 let _ = T::Currency::set_balance(&user, balance);86 user87}8889fn keys<T: Config + session::Config>(c: u32) -> <T as session::Config>::Keys {90 use rand::{RngCore, SeedableRng};9192 let keys = {93 let mut keys = [0u8; 128];9495 if c > 0 {96 let mut rng = rand::rngs::StdRng::seed_from_u64(c as u64);97 rng.fill_bytes(&mut keys);98 }99100 keys101 };102103 Decode::decode(&mut &keys[..]).unwrap()104}105106fn validator<T: Config + session::Config>(c: u32) -> (T::AccountId, <T as session::Config>::Keys) {107 (create_funded_user::<T>("candidate", c, 1000), keys::<T>(c))108}109110fn register_validators<T: Config + session::Config>(count: u32) -> Vec<T::AccountId> {111 let validators = (0..count).map(|c| validator::<T>(c)).collect::<Vec<_>>();112113 for (who, keys) in validators.clone() {114 <session::Pallet<T>>::set_keys(RawOrigin::Signed(who).into(), keys, Vec::new()).unwrap();115 }116117 validators.into_iter().map(|(who, _)| who).collect()118}119120fn register_invulnerables<T: Config + configuration::Config>(count: u32) {121 let candidates = (0..count)122 .map(|c| account("candidate", c, SEED))123 .collect::<Vec<_>>();124125 for who in candidates {126 <CollatorSelection<T>>::add_invulnerable(127 T::UpdateOrigin::try_successful_origin().unwrap(),128 who,129 )130 .unwrap();131 }132}133134fn register_candidates<T: Config + configuration::Config>(count: u32) {135 let candidates = (0..count)136 .map(|c| account("candidate", c, SEED))137 .collect::<Vec<_>>();138 assert!(139 <LicenseBond<T>>::get() > 0u32.into(),140 "Bond cannot be zero!"141 );142143 for who in candidates {144 T::Currency::set_balance(&who, <LicenseBond<T>>::get() * 2u32.into());145 <CollatorSelection<T>>::get_license(RawOrigin::Signed(who.clone()).into()).unwrap();146 <CollatorSelection<T>>::onboard(RawOrigin::Signed(who).into()).unwrap();147 }148}149150fn get_licenses<T: Config + configuration::Config>(count: u32) {151 let candidates = (0..count)152 .map(|c| account("candidate", c, SEED))153 .collect::<Vec<_>>();154 assert!(155 <LicenseBond<T>>::get() > 0u32.into(),156 "Bond cannot be zero!"157 );158159 for who in candidates {160 T::Currency::set_balance(&who, <LicenseBond<T>>::get() * 2u32.into());161 <CollatorSelection<T>>::get_license(RawOrigin::Signed(who.clone()).into()).unwrap();162 }163}164165166167fn balance_unit<T: Config>() -> BalanceOf<T> {168 200u32.into()169}170171172const INITIAL_INVULNERABLES: u32 = 2;173174benchmarks! {175 where_clause { where176 T: pallet_authorship::Config + session::Config + configuration::Config177 }178179 180 181 182 add_invulnerable {183 let b in 1 .. T::MaxCollators::get() - INITIAL_INVULNERABLES - 1;184 register_validators::<T>(b);185 register_invulnerables::<T>(b);186187 188189 let new_invulnerable: T::AccountId = whitelisted_caller();190 let bond: BalanceOf<T> = balance_unit::<T>() * 2u32.into();191 T::Currency::set_balance(&new_invulnerable, bond.clone());192193 <session::Pallet<T>>::set_keys(194 RawOrigin::Signed(new_invulnerable.clone()).into(),195 keys::<T>(b + 1),196 Vec::new()197 ).unwrap();198199 let root_origin = T::UpdateOrigin::try_successful_origin().unwrap();200 }: {201 assert_ok!(202 <CollatorSelection<T>>::add_invulnerable(root_origin, new_invulnerable.clone())203 );204 }205 verify {206 assert_last_event::<T>(Event::InvulnerableAdded{invulnerable: new_invulnerable}.into());207 }208209 remove_invulnerable {210 let b in 1 .. T::MaxCollators::get() - INITIAL_INVULNERABLES - 1;211 register_validators::<T>(b);212 register_invulnerables::<T>(b);213214 let root_origin = T::UpdateOrigin::try_successful_origin().unwrap();215 let leaving = <Invulnerables<T>>::get().last().unwrap().clone();216 whitelist!(leaving);217 }: {218 assert_ok!(219 <CollatorSelection<T>>::remove_invulnerable(root_origin, leaving.clone())220 );221 }222 verify {223 assert_last_event::<T>(Event::InvulnerableRemoved{invulnerable: leaving}.into());224 }225226 get_license {227 let c in 1 .. T::MaxCollators::get() - 1;228229 <LicenseBond<T>>::put(balance_unit::<T>());230231 register_validators::<T>(c);232 get_licenses::<T>(c);233234 let caller: T::AccountId = whitelisted_caller();235 let bond: BalanceOf<T> = balance_unit::<T>() * 2u32.into();236 T::Currency::set_balance(&caller, bond.clone());237238 <session::Pallet<T>>::set_keys(239 RawOrigin::Signed(caller.clone()).into(),240 keys::<T>(c + 1),241 Vec::new()242 ).unwrap();243244 }: _(RawOrigin::Signed(caller.clone()))245 verify {246 assert_last_event::<T>(Event::LicenseObtained{account_id: caller, deposit: bond / 2u32.into()}.into());247 }248249 250 251 onboard {252 let c in 1 .. T::MaxCollators::get() - INITIAL_INVULNERABLES - 1;253254 <LicenseBond<T>>::put(balance_unit::<T>());255 <DesiredCollators<T>>::put(c + INITIAL_INVULNERABLES + 1);256257 register_validators::<T>(c);258 register_candidates::<T>(c);259260 let caller: T::AccountId = whitelisted_caller();261 let bond: BalanceOf<T> = balance_unit::<T>() * 2u32.into();262 T::Currency::set_balance(&caller, bond.clone());263264 let origin = RawOrigin::Signed(caller.clone());265266 <session::Pallet<T>>::set_keys(267 origin.clone().into(),268 keys::<T>(c + 1),269 Vec::new()270 ).unwrap();271272 assert_ok!(273 <CollatorSelection<T>>::get_license(origin.clone().into())274 );275 }: _(origin)276 verify {277 assert_last_event::<T>(Event::CandidateAdded{account_id: caller}.into());278 }279280 281 offboard {282 let c in 1 .. T::MaxCollators::get();283 <LicenseBond<T>>::put(balance_unit::<T>());284 <DesiredCollators<T>>::put(c + INITIAL_INVULNERABLES);285286 register_validators::<T>(c);287 register_candidates::<T>(c);288289 let leaving = <Candidates<T>>::get().last().unwrap().clone();290 whitelist!(leaving);291 }: _(RawOrigin::Signed(leaving.clone()))292 verify {293 assert_last_event::<T>(Event::CandidateRemoved{account_id: leaving}.into());294 }295296 297 release_license {298 let c in 1 .. T::MaxCollators::get();299 let bond = balance_unit::<T>();300 <LicenseBond<T>>::put(bond);301 <DesiredCollators<T>>::put(c + INITIAL_INVULNERABLES);302303 register_validators::<T>(c);304 register_candidates::<T>(c);305306 let leaving = <Candidates<T>>::get().last().unwrap().clone();307 whitelist!(leaving);308 }: _(RawOrigin::Signed(leaving.clone()))309 verify {310 assert_last_event::<T>(Event::LicenseReleased{account_id: leaving, deposit_returned: bond}.into());311 }312313 314 force_release_license {315 let c in 1 .. T::MaxCollators::get();316 let bond = balance_unit::<T>();317 <LicenseBond<T>>::put(bond);318 <DesiredCollators<T>>::put(c + INITIAL_INVULNERABLES);319320 register_validators::<T>(c);321 register_candidates::<T>(c);322323 let leaving = <Candidates<T>>::get().last().unwrap().clone();324 whitelist!(leaving);325 let origin = T::UpdateOrigin::try_successful_origin().unwrap();326 }: {327 assert_ok!(328 <CollatorSelection<T>>::force_release_license(origin, leaving.clone())329 );330 }331 verify {332 assert_last_event::<T>(Event::LicenseReleased{account_id: leaving, deposit_returned: bond}.into());333 }334335 336 note_author {337 <LicenseBond<T>>::put(balance_unit::<T>());338 T::Currency::set_balance(339 &<CollatorSelection<T>>::account_id(),340 balance_unit::<T>() * 4u32.into(),341 );342 let author = account("author", 0, SEED);343 let new_block: T::BlockNumber = 10u32.into();344345 frame_system::Pallet::<T>::set_block_number(new_block);346 assert!(T::Currency::balance(&author) == 0u32.into());347 }: {348 <CollatorSelection<T> as EventHandler<_, _>>::note_author(author.clone())349 } verify {350 assert!(T::Currency::balance(&author) > 0u32.into());351 assert_eq!(frame_system::Pallet::<T>::block_number(), new_block);352 }353354 355 new_session {356 let r in 1 .. T::MaxCollators::get();357 let c in 1 .. T::MaxCollators::get();358359 <LicenseBond<T>>::put(balance_unit::<T>());360 <DesiredCollators<T>>::put(c + INITIAL_INVULNERABLES);361 frame_system::Pallet::<T>::set_block_number(0u32.into());362363 register_validators::<T>(c);364 register_candidates::<T>(c);365366 let new_block: T::BlockNumber = 1800u32.into();367 let zero_block: T::BlockNumber = 0u32.into();368 let candidates = <Candidates<T>>::get();369370 let non_removals = c.saturating_sub(r);371372 for i in 0..c {373 <LastAuthoredBlock<T>>::insert(candidates[i as usize].clone(), zero_block);374 }375376 if non_removals > 0 {377 for i in 0..non_removals {378 <LastAuthoredBlock<T>>::insert(candidates[i as usize].clone(), new_block);379 }380 } else {381 for i in 0..c {382 <LastAuthoredBlock<T>>::insert(candidates[i as usize].clone(), new_block);383 }384 }385386 let pre_length = <Candidates<T>>::get().len();387388 frame_system::Pallet::<T>::set_block_number(new_block);389390 assert!(<Candidates<T>>::get().len() == c as usize);391 }: {392 <CollatorSelection<T> as SessionManager<_>>::new_session(0)393 } verify {394 if c > r {395 assert!(<Candidates<T>>::get().len() < pre_length);396 } else {397 assert!(<Candidates<T>>::get().len() == pre_length);398 }399 }400}401402impl_benchmark_test_suite!(403 CollatorSelection,404 crate::mock::new_test_ext(),405 crate::mock::Test,406);