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::*;5354const SEED: u32 = 0;555657macro_rules! whitelist {58 ($acc:ident) => {59 frame_benchmarking::benchmarking::add_to_whitelist(60 frame_system::Account::<T>::hashed_key_for(&$acc).into(),61 );62 };63}6465fn assert_last_event<T: Config>(generic_event: <T as Config>::RuntimeEvent) {66 let events = frame_system::Pallet::<T>::events();67 let system_event: <T as frame_system::Config>::RuntimeEvent = generic_event.into();68 69 let EventRecord { event, .. } = &events[events.len() - 1];70 assert_eq!(event, &system_event);71}7273fn create_funded_user<T: Config>(74 string: &'static str,75 n: u32,76 balance_factor: u32,77) -> T::AccountId {78 let user = account(string, n, SEED);79 let balance = balance_unit::<T>() * balance_factor.into();80 let _ = T::Currency::set_balance(&user, balance);81 user82}8384fn keys<T: Config + session::Config>(c: u32) -> <T as session::Config>::Keys {85 use rand::{RngCore, SeedableRng};8687 let keys = {88 let mut keys = [0u8; 128];8990 if c > 0 {91 let mut rng = rand::rngs::StdRng::seed_from_u64(c as u64);92 rng.fill_bytes(&mut keys);93 }9495 keys96 };9798 Decode::decode(&mut &keys[..]).unwrap()99}100101fn validator<T: Config + session::Config>(c: u32) -> (T::AccountId, <T as session::Config>::Keys) {102 (create_funded_user::<T>("candidate", c, 1000), keys::<T>(c))103}104105fn register_validators<T: Config + session::Config>(count: u32) -> Vec<T::AccountId> {106 let validators = (0..count).map(|c| validator::<T>(c)).collect::<Vec<_>>();107108 for (who, keys) in validators.clone() {109 <session::Pallet<T>>::set_keys(RawOrigin::Signed(who).into(), keys, Vec::new()).unwrap();110 }111112 validators.into_iter().map(|(who, _)| who).collect()113}114115fn register_invulnerables<T: Config>(count: u32) {116 let candidates = (0..count)117 .map(|c| account("candidate", c, SEED))118 .collect::<Vec<_>>();119120 for who in candidates {121 <CollatorSelection<T>>::add_invulnerable(122 T::UpdateOrigin::try_successful_origin().unwrap(),123 who,124 )125 .unwrap();126 }127}128129fn register_candidates<T: Config>(count: u32) {130 let candidates = (0..count)131 .map(|c| account("candidate", c, SEED))132 .collect::<Vec<_>>();133 assert!(T::LicenseBond::get() > 0u32.into(), "Bond cannot be zero!");134135 for who in candidates {136 T::Currency::set_balance(&who, T::LicenseBond::get() * 2u32.into());137 <CollatorSelection<T>>::get_license(RawOrigin::Signed(who.clone()).into()).unwrap();138 <CollatorSelection<T>>::onboard(RawOrigin::Signed(who).into()).unwrap();139 }140}141142fn get_licenses<T: Config>(count: u32) {143 let candidates = (0..count)144 .map(|c| account("candidate", c, SEED))145 .collect::<Vec<_>>();146 assert!(T::LicenseBond::get() > 0u32.into(), "Bond cannot be zero!");147148 for who in candidates {149 T::Currency::set_balance(&who, T::LicenseBond::get() * 2u32.into());150 <CollatorSelection<T>>::get_license(RawOrigin::Signed(who.clone()).into()).unwrap();151 }152}153154155156fn balance_unit<T: Config>() -> BalanceOf<T> {157 T::LicenseBond::get()158}159160161const INITIAL_INVULNERABLES: u32 = 2;162163benchmarks! {164 where_clause { where165 T: Config + pallet_authorship::Config + session::Config166 }167168 169 170 171 add_invulnerable {172 let b in 1 .. T::MaxCollators::get() - INITIAL_INVULNERABLES - 1;173 register_validators::<T>(b);174 register_invulnerables::<T>(b);175176 177178 let new_invulnerable: T::AccountId = whitelisted_caller();179 let bond: BalanceOf<T> = balance_unit::<T>() * 2u32.into();180 <T as Config>::Currency::set_balance(&new_invulnerable, bond);181182 <session::Pallet<T>>::set_keys(183 RawOrigin::Signed(new_invulnerable.clone()).into(),184 keys::<T>(b + 1),185 Vec::new()186 ).unwrap();187188 let root_origin = T::UpdateOrigin::try_successful_origin().unwrap();189 }: {190 assert_ok!(191 <CollatorSelection<T>>::add_invulnerable(root_origin, new_invulnerable.clone())192 );193 }194 verify {195 assert_last_event::<T>(Event::InvulnerableAdded{invulnerable: new_invulnerable}.into());196 }197198 remove_invulnerable {199 let b in 1 .. T::MaxCollators::get() - INITIAL_INVULNERABLES - 1;200 register_validators::<T>(b);201 register_invulnerables::<T>(b);202203 let root_origin = T::UpdateOrigin::try_successful_origin().unwrap();204 let leaving = <Invulnerables<T>>::get().last().unwrap().clone();205 whitelist!(leaving);206 }: {207 assert_ok!(208 <CollatorSelection<T>>::remove_invulnerable(root_origin, leaving.clone())209 );210 }211 verify {212 assert_last_event::<T>(Event::InvulnerableRemoved{invulnerable: leaving}.into());213 }214215 get_license {216 let c in 1 .. T::MaxCollators::get() - 1;217218 register_validators::<T>(c);219 get_licenses::<T>(c);220221 let caller: T::AccountId = whitelisted_caller();222 let bond: BalanceOf<T> = balance_unit::<T>() * 2u32.into();223 T::Currency::set_balance(&caller, bond);224225 <session::Pallet<T>>::set_keys(226 RawOrigin::Signed(caller.clone()).into(),227 keys::<T>(c + 1),228 Vec::new()229 ).unwrap();230231 }: _(RawOrigin::Signed(caller.clone()))232 verify {233 assert_last_event::<T>(Event::LicenseObtained{account_id: caller, deposit: bond / 2u32.into()}.into());234 }235236 237 238 onboard {239 let c in 1 .. T::MaxCollators::get() - INITIAL_INVULNERABLES - 1;240241 register_validators::<T>(c);242 register_candidates::<T>(c);243244 let caller: T::AccountId = whitelisted_caller();245 let bond: BalanceOf<T> = balance_unit::<T>() * 2u32.into();246 T::Currency::set_balance(&caller, bond);247248 let origin = RawOrigin::Signed(caller.clone());249250 <session::Pallet<T>>::set_keys(251 origin.clone().into(),252 keys::<T>(c + 1),253 Vec::new()254 ).unwrap();255256 assert_ok!(257 <CollatorSelection<T>>::get_license(origin.clone().into())258 );259 }: _(origin)260 verify {261 assert_last_event::<T>(Event::CandidateAdded{account_id: caller}.into());262 }263264 265 offboard {266 let c in 1 .. T::MaxCollators::get() - INITIAL_INVULNERABLES;267268 register_validators::<T>(c);269 register_candidates::<T>(c);270271 let leaving = <Candidates<T>>::get().last().unwrap().clone();272 whitelist!(leaving);273 }: _(RawOrigin::Signed(leaving.clone()))274 verify {275 assert_last_event::<T>(Event::CandidateRemoved{account_id: leaving}.into());276 }277278 279 release_license {280 let c in 1 .. T::MaxCollators::get() - INITIAL_INVULNERABLES;281 let bond = balance_unit::<T>();282283 register_validators::<T>(c);284 register_candidates::<T>(c);285286 let leaving = <Candidates<T>>::get().last().unwrap().clone();287 whitelist!(leaving);288 }: _(RawOrigin::Signed(leaving.clone()))289 verify {290 assert_last_event::<T>(Event::LicenseReleased{account_id: leaving, deposit_returned: bond}.into());291 }292293 294 force_release_license {295 let c in 1 .. T::MaxCollators::get() - INITIAL_INVULNERABLES;296 let bond = balance_unit::<T>();297298 register_validators::<T>(c);299 register_candidates::<T>(c);300301 let leaving = <Candidates<T>>::get().last().unwrap().clone();302 whitelist!(leaving);303 let origin = T::UpdateOrigin::try_successful_origin().unwrap();304 }: {305 assert_ok!(306 <CollatorSelection<T>>::force_release_license(origin, leaving.clone())307 );308 }309 verify {310 assert_last_event::<T>(Event::LicenseReleased{account_id: leaving, deposit_returned: bond}.into());311 }312313 314 note_author {315 T::Currency::set_balance(316 &<CollatorSelection<T>>::account_id(),317 balance_unit::<T>() * 4u32.into(),318 );319 let author = account("author", 0, SEED);320 let new_block: T::BlockNumber = 10u32.into();321322 frame_system::Pallet::<T>::set_block_number(new_block);323 assert!(T::Currency::balance(&author) == 0u32.into());324 }: {325 <CollatorSelection<T> as EventHandler<_, _>>::note_author(author.clone())326 } verify {327 assert!(T::Currency::balance(&author) > 0u32.into());328 assert_eq!(frame_system::Pallet::<T>::block_number(), new_block);329 }330331 332 new_session {333 let r in 1 .. T::MaxCollators::get() - INITIAL_INVULNERABLES;334 let c in 1 .. T::MaxCollators::get() - INITIAL_INVULNERABLES;335336 frame_system::Pallet::<T>::set_block_number(0u32.into());337338 register_validators::<T>(c);339 register_candidates::<T>(c);340341 let new_block: T::BlockNumber = 1800u32.into();342 let zero_block: T::BlockNumber = 0u32.into();343 let candidates = <Candidates<T>>::get();344345 let non_removals = c.saturating_sub(r);346347 for i in 0..c {348 <LastAuthoredBlock<T>>::insert(candidates[i as usize].clone(), zero_block);349 }350351 if non_removals > 0 {352 for i in 0..non_removals {353 <LastAuthoredBlock<T>>::insert(candidates[i as usize].clone(), new_block);354 }355 } else {356 for i in 0..c {357 <LastAuthoredBlock<T>>::insert(candidates[i as usize].clone(), new_block);358 }359 }360361 let pre_length = <Candidates<T>>::get().len();362363 frame_system::Pallet::<T>::set_block_number(new_block);364365 assert!(<Candidates<T>>::get().len() == c as usize);366 }: {367 <CollatorSelection<T> as SessionManager<_>>::new_session(0)368 } verify {369 if c > r {370 assert!(<Candidates<T>>::get().len() < pre_length);371 } else {372 assert!(<Candidates<T>>::get().len() == pre_length);373 }374 }375}376377impl_benchmark_test_suite!(378 CollatorSelection,379 crate::mock::new_test_ext(),380 crate::mock::Test,381);