1234567891011121314151617181920212223242526272829303132333435use frame_benchmarking::{account, benchmarks, impl_benchmark_test_suite, whitelisted_caller};36use frame_support::{37 assert_ok,38 traits::{39 fungible::{Inspect, Mutate},40 EnsureOrigin, Get,41 },42};43use frame_system::{pallet_prelude::*, EventRecord, RawOrigin};44use pallet_authorship::EventHandler;45use pallet_session::{self as session, SessionManager};46use parity_scale_codec::Decode;47use sp_std::prelude::*;4849use super::*;50#[allow(unused)]51use crate::{BalanceOf, Pallet as CollatorSelection};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 = balance_unit::<T>() * balance_factor.into();79 let _ = T::Currency::set_balance(&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_invulnerables<T: Config>(count: u32) {115 let candidates = (0..count)116 .map(|c| account("candidate", c, SEED))117 .collect::<Vec<_>>();118119 for who in candidates {120 <CollatorSelection<T>>::add_invulnerable(121 T::UpdateOrigin::try_successful_origin().unwrap(),122 who,123 )124 .unwrap();125 }126}127128fn register_candidates<T: Config>(count: u32) {129 let candidates = (0..count)130 .map(|c| account("candidate", c, SEED))131 .collect::<Vec<_>>();132 assert!(T::LicenseBond::get() > 0u32.into(), "Bond cannot be zero!");133134 for who in candidates {135 T::Currency::set_balance(&who, T::LicenseBond::get() * 2u32.into());136 <CollatorSelection<T>>::get_license(RawOrigin::Signed(who.clone()).into()).unwrap();137 <CollatorSelection<T>>::onboard(RawOrigin::Signed(who).into()).unwrap();138 }139}140141fn get_licenses<T: Config>(count: u32) {142 let candidates = (0..count)143 .map(|c| account("candidate", c, SEED))144 .collect::<Vec<_>>();145 assert!(T::LicenseBond::get() > 0u32.into(), "Bond cannot be zero!");146147 for who in candidates {148 T::Currency::set_balance(&who, T::LicenseBond::get() * 2u32.into());149 <CollatorSelection<T>>::get_license(RawOrigin::Signed(who.clone()).into()).unwrap();150 }151}152153154155fn balance_unit<T: Config>() -> BalanceOf<T> {156 T::LicenseBond::get()157}158159160const INITIAL_INVULNERABLES: u32 = 2;161162benchmarks! {163 where_clause { where164 T: Config + pallet_authorship::Config + session::Config165 }166167 168 169 170 add_invulnerable {171 let b in 1 .. T::MaxCollators::get() - INITIAL_INVULNERABLES - 1;172 register_validators::<T>(b);173 register_invulnerables::<T>(b);174175 176177 let new_invulnerable: T::AccountId = whitelisted_caller();178 let bond: BalanceOf<T> = balance_unit::<T>() * 2u32.into();179 <T as Config>::Currency::set_balance(&new_invulnerable, bond);180181 <session::Pallet<T>>::set_keys(182 RawOrigin::Signed(new_invulnerable.clone()).into(),183 keys::<T>(b + 1),184 Vec::new()185 ).unwrap();186187 let root_origin = T::UpdateOrigin::try_successful_origin().unwrap();188 }: {189 assert_ok!(190 <CollatorSelection<T>>::add_invulnerable(root_origin, new_invulnerable.clone())191 );192 }193 verify {194 assert_last_event::<T>(Event::InvulnerableAdded{invulnerable: new_invulnerable}.into());195 }196197 remove_invulnerable {198 let b in 1 .. T::MaxCollators::get() - INITIAL_INVULNERABLES - 1;199 register_validators::<T>(b);200 register_invulnerables::<T>(b);201202 let root_origin = T::UpdateOrigin::try_successful_origin().unwrap();203 let leaving = <Invulnerables<T>>::get().last().unwrap().clone();204 whitelist!(leaving);205 }: {206 assert_ok!(207 <CollatorSelection<T>>::remove_invulnerable(root_origin, leaving.clone())208 );209 }210 verify {211 assert_last_event::<T>(Event::InvulnerableRemoved{invulnerable: leaving}.into());212 }213214 get_license {215 let c in 1 .. T::MaxCollators::get() - 1;216217 register_validators::<T>(c);218 get_licenses::<T>(c);219220 let caller: T::AccountId = whitelisted_caller();221 let bond: BalanceOf<T> = balance_unit::<T>() * 2u32.into();222 T::Currency::set_balance(&caller, bond);223224 <session::Pallet<T>>::set_keys(225 RawOrigin::Signed(caller.clone()).into(),226 keys::<T>(c + 1),227 Vec::new()228 ).unwrap();229230 }: _(RawOrigin::Signed(caller.clone()))231 verify {232 assert_last_event::<T>(Event::LicenseObtained{account_id: caller, deposit: bond / 2u32.into()}.into());233 }234235 236 237 onboard {238 let c in 1 .. T::MaxCollators::get() - INITIAL_INVULNERABLES - 1;239240 register_validators::<T>(c);241 register_candidates::<T>(c);242243 let caller: T::AccountId = whitelisted_caller();244 let bond: BalanceOf<T> = balance_unit::<T>() * 2u32.into();245 T::Currency::set_balance(&caller, bond);246247 let origin = RawOrigin::Signed(caller.clone());248249 <session::Pallet<T>>::set_keys(250 origin.clone().into(),251 keys::<T>(c + 1),252 Vec::new()253 ).unwrap();254255 assert_ok!(256 <CollatorSelection<T>>::get_license(origin.clone().into())257 );258 }: _(origin)259 verify {260 assert_last_event::<T>(Event::CandidateAdded{account_id: caller}.into());261 }262263 264 offboard {265 let c in 1 .. T::MaxCollators::get() - INITIAL_INVULNERABLES;266267 register_validators::<T>(c);268 register_candidates::<T>(c);269270 let leaving = <Candidates<T>>::get().last().unwrap().clone();271 whitelist!(leaving);272 }: _(RawOrigin::Signed(leaving.clone()))273 verify {274 assert_last_event::<T>(Event::CandidateRemoved{account_id: leaving}.into());275 }276277 278 release_license {279 let c in 1 .. T::MaxCollators::get() - INITIAL_INVULNERABLES;280 let bond = balance_unit::<T>();281282 register_validators::<T>(c);283 register_candidates::<T>(c);284285 let leaving = <Candidates<T>>::get().last().unwrap().clone();286 whitelist!(leaving);287 }: _(RawOrigin::Signed(leaving.clone()))288 verify {289 assert_last_event::<T>(Event::LicenseReleased{account_id: leaving, deposit_returned: bond}.into());290 }291292 293 force_release_license {294 let c in 1 .. T::MaxCollators::get() - INITIAL_INVULNERABLES;295 let bond = balance_unit::<T>();296297 register_validators::<T>(c);298 register_candidates::<T>(c);299300 let leaving = <Candidates<T>>::get().last().unwrap().clone();301 whitelist!(leaving);302 let origin = T::UpdateOrigin::try_successful_origin().unwrap();303 }: {304 assert_ok!(305 <CollatorSelection<T>>::force_release_license(origin, leaving.clone())306 );307 }308 verify {309 assert_last_event::<T>(Event::LicenseReleased{account_id: leaving, deposit_returned: bond}.into());310 }311312 313 note_author {314 T::Currency::set_balance(315 &<CollatorSelection<T>>::account_id(),316 balance_unit::<T>() * 4u32.into(),317 );318 let author = account("author", 0, SEED);319 let new_block: BlockNumberFor<T>= 10u32.into();320321 frame_system::Pallet::<T>::set_block_number(new_block);322 assert!(T::Currency::balance(&author) == 0u32.into());323 }: {324 <CollatorSelection<T> as EventHandler<_, _>>::note_author(author.clone())325 } verify {326 assert!(T::Currency::balance(&author) > 0u32.into());327 assert_eq!(frame_system::Pallet::<T>::block_number(), new_block);328 }329330 331 new_session {332 let r in 1 .. T::MaxCollators::get() - INITIAL_INVULNERABLES;333 let c in 1 .. T::MaxCollators::get() - INITIAL_INVULNERABLES;334335 frame_system::Pallet::<T>::set_block_number(0u32.into());336337 register_validators::<T>(c);338 register_candidates::<T>(c);339340 let new_block: BlockNumberFor<T>= 1800u32.into();341 let zero_block: BlockNumberFor<T> = 0u32.into();342 let candidates = <Candidates<T>>::get();343344 let non_removals = c.saturating_sub(r);345346 for i in 0..c {347 <LastAuthoredBlock<T>>::insert(candidates[i as usize].clone(), zero_block);348 }349350 if non_removals > 0 {351 for i in 0..non_removals {352 <LastAuthoredBlock<T>>::insert(candidates[i as usize].clone(), new_block);353 }354 } else {355 for i in 0..c {356 <LastAuthoredBlock<T>>::insert(candidates[i as usize].clone(), new_block);357 }358 }359360 let pre_length = <Candidates<T>>::get().len();361362 frame_system::Pallet::<T>::set_block_number(new_block);363364 assert!(<Candidates<T>>::get().len() == c as usize);365 }: {366 <CollatorSelection<T> as SessionManager<_>>::new_session(0)367 } verify {368 if c > r {369 assert!(<Candidates<T>>::get().len() < pre_length);370 } else {371 assert!(<Candidates<T>>::get().len() == pre_length);372 }373 }374}375376impl_benchmark_test_suite!(377 CollatorSelection,378 crate::mock::new_test_ext(),379 crate::mock::Test,380);