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 pallet_configuration::{49 self as configuration, BalanceOf,50 CollatorSelectionDesiredCollatorsOverride as DesiredCollators,51 CollatorSelectionLicenseBondOverride as LicenseBond,52};53use sp_std::prelude::*;5455565758const 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 = T::Currency::minimum_balance() * balance_factor.into();84 let _ = T::Currency::make_free_balance_be(&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_candidates<T: Config + configuration::Config>(count: u32) {120 let candidates = (0..count)121 .map(|c| account("candidate", c, SEED))122 .collect::<Vec<_>>();123 assert!(124 <LicenseBond<T>>::get() > 0u32.into(),125 "Bond cannot be zero!"126 );127128 for who in candidates {129 T::Currency::make_free_balance_be(&who, <LicenseBond<T>>::get() * 2u32.into());130 <CollatorSelection<T>>::get_license(RawOrigin::Signed(who.clone()).into()).unwrap();131 <CollatorSelection<T>>::onboard(RawOrigin::Signed(who).into()).unwrap();132 }133}134135benchmarks! {136 where_clause { where T: pallet_authorship::Config + session::Config + configuration::Config }137138 add_invulnerable {139 let b in 1 .. T::MaxCollators::get();140 let new_invulnerable = register_validators::<T>(b)[0].clone();141 let origin = T::UpdateOrigin::successful_origin();142 }: {143 assert_ok!(144 <CollatorSelection<T>>::add_invulnerable(origin, new_invulnerable.clone())145 );146 }147 verify {148 assert_last_event::<T>(Event::InvulnerableAdded{invulnerable: new_invulnerable}.into());149 }150151 remove_invulnerable {152 let b in 1 .. T::MaxCollators::get();153 let new_invulnerable = register_validators::<T>(b)[0].clone();154 let origin = T::UpdateOrigin::successful_origin();155 assert_ok!(156 <CollatorSelection<T>>::add_invulnerable(origin.clone(), new_invulnerable.clone())157 );158 }: {159 assert_ok!(160 <CollatorSelection<T>>::remove_invulnerable(origin, new_invulnerable.clone())161 );162 }163 verify {164 assert_last_event::<T>(Event::InvulnerableRemoved{invulnerable: new_invulnerable}.into());165 }166167 168169170171172173174175176177178179180181182183184185186187188189190191 get_license {192 let c in 1 .. T::MaxCollators::get();193194 <LicenseBond<T>>::put(T::Currency::minimum_balance());195 <DesiredCollators<T>>::put(c + 1);196197 register_validators::<T>(c);198 register_candidates::<T>(c);199200 let caller: T::AccountId = whitelisted_caller();201 let bond: BalanceOf<T> = T::Currency::minimum_balance() * 2u32.into();202 T::Currency::make_free_balance_be(&caller, bond.clone());203204 <session::Pallet<T>>::set_keys(205 RawOrigin::Signed(caller.clone()).into(),206 keys::<T>(c + 1),207 Vec::new()208 ).unwrap();209210 }: _(RawOrigin::Signed(caller.clone()))211 verify {212 assert_last_event::<T>(Event::LicenseObtained{account_id: caller, deposit: bond / 2u32.into()}.into());213 }214215 216 217 onboard {218 let c in 1 .. T::MaxCollators::get();219220 <LicenseBond<T>>::put(T::Currency::minimum_balance());221 <DesiredCollators<T>>::put(c + 1);222223 register_validators::<T>(c);224 register_candidates::<T>(c);225226 let caller: T::AccountId = whitelisted_caller();227 let bond: BalanceOf<T> = T::Currency::minimum_balance() * 2u32.into();228 T::Currency::make_free_balance_be(&caller, bond.clone());229230 let origin = RawOrigin::Signed(caller.clone());231232 <session::Pallet<T>>::set_keys(233 origin.clone().into(),234 keys::<T>(c + 1),235 Vec::new()236 ).unwrap();237238 assert_ok!(239 <CollatorSelection<T>>::get_license(origin.clone().into())240 );241 }: _(origin)242 verify {243 assert_last_event::<T>(Event::CandidateAdded{account_id: caller}.into());244 }245246 247 offboard {248 let c in 1 .. T::MaxCollators::get();249 <LicenseBond<T>>::put(T::Currency::minimum_balance());250 <DesiredCollators<T>>::put(c);251252 register_validators::<T>(c);253 register_candidates::<T>(c);254255 let leaving = <Candidates<T>>::get().last().unwrap().clone();256 whitelist!(leaving);257 }: _(RawOrigin::Signed(leaving.clone()))258 verify {259 assert_last_event::<T>(Event::CandidateRemoved{account_id: leaving}.into());260 }261262 263 release_license {264 let c in 1 .. T::MaxCollators::get();265 let bond = T::Currency::minimum_balance();266 <LicenseBond<T>>::put(bond);267 <DesiredCollators<T>>::put(c);268269 register_validators::<T>(c);270 register_candidates::<T>(c);271272 let leaving = <Candidates<T>>::get().last().unwrap().clone();273 whitelist!(leaving);274 }: _(RawOrigin::Signed(leaving.clone()))275 verify {276 assert_last_event::<T>(Event::LicenseReleased{account_id: leaving, deposit_returned: bond}.into());277 }278279 280 force_release_license {281 let c in 1 .. T::MaxCollators::get();282 let bond = T::Currency::minimum_balance();283 <LicenseBond<T>>::put(bond);284 <DesiredCollators<T>>::put(c);285286 register_validators::<T>(c);287 register_candidates::<T>(c);288289 let leaving = <Candidates<T>>::get().last().unwrap().clone();290 whitelist!(leaving);291 let origin = T::UpdateOrigin::successful_origin();292 }: {293 assert_ok!(294 <CollatorSelection<T>>::force_release_license(origin, leaving.clone())295 );296 }297 verify {298 assert_last_event::<T>(Event::LicenseReleased{account_id: leaving, deposit_returned: bond}.into());299 }300301 302 note_author {303 <LicenseBond<T>>::put(T::Currency::minimum_balance());304 T::Currency::make_free_balance_be(305 &<CollatorSelection<T>>::account_id(),306 T::Currency::minimum_balance() * 4u32.into(),307 );308 let author = account("author", 0, SEED);309 let new_block: T::BlockNumber = 10u32.into();310311 frame_system::Pallet::<T>::set_block_number(new_block);312 assert!(T::Currency::free_balance(&author) == 0u32.into());313 }: {314 <CollatorSelection<T> as EventHandler<_, _>>::note_author(author.clone())315 } verify {316 assert!(T::Currency::free_balance(&author) > 0u32.into());317 assert_eq!(frame_system::Pallet::<T>::block_number(), new_block);318 }319320 321 new_session {322 let r in 1 .. T::MaxCollators::get();323 let c in 1 .. T::MaxCollators::get();324325 <LicenseBond<T>>::put(T::Currency::minimum_balance());326 <DesiredCollators<T>>::put(c);327 frame_system::Pallet::<T>::set_block_number(0u32.into());328329 register_validators::<T>(c);330 register_candidates::<T>(c);331332 let new_block: T::BlockNumber = 1800u32.into();333 let zero_block: T::BlockNumber = 0u32.into();334 let candidates = <Candidates<T>>::get();335336 let non_removals = c.saturating_sub(r);337338 for i in 0..c {339 <LastAuthoredBlock<T>>::insert(candidates[i as usize].clone(), zero_block);340 }341342 if non_removals > 0 {343 for i in 0..non_removals {344 <LastAuthoredBlock<T>>::insert(candidates[i as usize].clone(), new_block);345 }346 } else {347 for i in 0..c {348 <LastAuthoredBlock<T>>::insert(candidates[i as usize].clone(), new_block);349 }350 }351352 let pre_length = <Candidates<T>>::get().len();353354 frame_system::Pallet::<T>::set_block_number(new_block);355356 assert!(<Candidates<T>>::get().len() == c as usize);357 }: {358 <CollatorSelection<T> as SessionManager<_>>::new_session(0)359 } verify {360 if c > r {361 assert!(<Candidates<T>>::get().len() < pre_length);362 } else {363 assert!(<Candidates<T>>::get().len() == pre_length);364 }365 }366}367368impl_benchmark_test_suite!(369 CollatorSelection,370 crate::mock::new_test_ext(),371 crate::mock::Test,372);