git.delta.rocks / unique-network / refs/commits / b4ec6cd8c8b0

difftreelog

source

pallets/collator-selection/src/benchmarking.rs11.7 KiBsourcehistory
1// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.2// This file is part of Unique Network.34// Unique Network is free software: you can redistribute it and/or modify5// it under the terms of the GNU General Public License as published by6// the Free Software Foundation, either version 3 of the License, or7// (at your option) any later version.89// Unique Network is distributed in the hope that it will be useful,10// but WITHOUT ANY WARRANTY; without even the implied warranty of11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the12// GNU General Public License for more details.1314// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.1617// Original license:18// Copyright (C) 2021 Parity Technologies (UK) Ltd.19// SPDX-License-Identifier: Apache-2.02021// Licensed under the Apache License, Version 2.0 (the "License");22// you may not use this file except in compliance with the License.23// You may obtain a copy of the License at24//25// 	http://www.apache.org/licenses/LICENSE-2.026//27// Unless required by applicable law or agreed to in writing, software28// distributed under the License is distributed on an "AS IS" BASIS,29// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.30// See the License for the specific language governing permissions and31// limitations under the License.3233//! Benchmarking setup for pallet-collator-selection3435use 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::*;5455const SEED: u32 = 0;5657// TODO: remove if this is given in substrate commit.58macro_rules! whitelist {59	($acc:ident) => {60		frame_benchmarking::benchmarking::add_to_whitelist(61			frame_system::Account::<T>::hashed_key_for(&$acc).into(),62		);63	};64}6566fn assert_last_event<T: Config>(generic_event: <T as Config>::RuntimeEvent) {67	let events = frame_system::Pallet::<T>::events();68	let system_event: <T as frame_system::Config>::RuntimeEvent = generic_event.into();69	// compare to the last event record70	let EventRecord { event, .. } = &events[events.len() - 1];71	assert_eq!(event, &system_event);72}7374fn create_funded_user<T: Config>(75	string: &'static str,76	n: u32,77	balance_factor: u32,78) -> T::AccountId {79	let user = account(string, n, SEED);80	let balance = T::Currency::minimum_balance() * balance_factor.into();81	let _ = T::Currency::make_free_balance_be(&user, balance);82	user83}8485fn keys<T: Config + session::Config>(c: u32) -> <T as session::Config>::Keys {86	use rand::{RngCore, SeedableRng};8788	let keys = {89		let mut keys = [0u8; 128];9091		if c > 0 {92			let mut rng = rand::rngs::StdRng::seed_from_u64(c as u64);93			rng.fill_bytes(&mut keys);94		}9596		keys97	};9899	Decode::decode(&mut &keys[..]).unwrap()100}101102fn validator<T: Config + session::Config>(c: u32) -> (T::AccountId, <T as session::Config>::Keys) {103	(create_funded_user::<T>("candidate", c, 1000), keys::<T>(c))104}105106fn register_validators<T: Config + session::Config>(count: u32) -> Vec<T::AccountId> {107	let validators = (0..count).map(|c| validator::<T>(c)).collect::<Vec<_>>();108109	for (who, keys) in validators.clone() {110		<session::Pallet<T>>::set_keys(RawOrigin::Signed(who).into(), keys, Vec::new()).unwrap();111	}112113	validators.into_iter().map(|(who, _)| who).collect()114}115116fn register_invulnerables<T: Config + configuration::Config>(count: u32) {117	let candidates = (0..count)118		.map(|c| account("candidate", c, SEED))119		.collect::<Vec<_>>();120121	for who in candidates {122		<CollatorSelection<T>>::add_invulnerable(123			T::UpdateOrigin::try_successful_origin().unwrap(),124			who,125		)126		.unwrap();127	}128}129130fn register_candidates<T: Config + configuration::Config>(count: u32) {131	let candidates = (0..count)132		.map(|c| account("candidate", c, SEED))133		.collect::<Vec<_>>();134	assert!(135		<LicenseBond<T>>::get() > 0u32.into(),136		"Bond cannot be zero!"137	);138139	for who in candidates {140		T::Currency::make_free_balance_be(&who, <LicenseBond<T>>::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 + configuration::Config>(count: u32) {147	let candidates = (0..count)148		.map(|c| account("candidate", c, SEED))149		.collect::<Vec<_>>();150	assert!(151		<LicenseBond<T>>::get() > 0u32.into(),152		"Bond cannot be zero!"153	);154155	for who in candidates {156		T::Currency::make_free_balance_be(&who, <LicenseBond<T>>::get() * 2u32.into());157		<CollatorSelection<T>>::get_license(RawOrigin::Signed(who.clone()).into()).unwrap();158	}159}160161benchmarks! {162	where_clause { where T: pallet_authorship::Config + session::Config + configuration::Config }163164	// todo:collator this and all the following do not work for some reason, going all the way up to 10 in length165	// Both invulnerables and candidates count together against MaxCollators.166	// Maybe try putting it in braces? 1 .. (T::MaxCollators::get() - 2)167	add_invulnerable {168		let b in 1 .. T::MaxCollators::get() - 3;169		register_validators::<T>(b);170		register_invulnerables::<T>(b);171172		// log::info!("{} {}", <Invulnerables<T>>::get().len(), b);173174		let new_invulnerable: T::AccountId = whitelisted_caller();175		let bond: BalanceOf<T> = T::Currency::minimum_balance() * 2u32.into();176		T::Currency::make_free_balance_be(&new_invulnerable, bond.clone());177178		<session::Pallet<T>>::set_keys(179			RawOrigin::Signed(new_invulnerable.clone()).into(),180			keys::<T>(b + 1),181			Vec::new()182		).unwrap();183184		let root_origin = T::UpdateOrigin::try_successful_origin().unwrap();185	}: {186		assert_ok!(187			<CollatorSelection<T>>::add_invulnerable(root_origin, new_invulnerable.clone())188		);189	}190	verify {191		assert_last_event::<T>(Event::InvulnerableAdded{invulnerable: new_invulnerable}.into());192	}193194	remove_invulnerable {195		let b in 1 .. T::MaxCollators::get();196		register_validators::<T>(b);197		register_invulnerables::<T>(b);198199		let root_origin = T::UpdateOrigin::try_successful_origin().unwrap();200		let leaving = <Invulnerables<T>>::get().last().unwrap().clone();201		whitelist!(leaving);202	}: {203		assert_ok!(204			<CollatorSelection<T>>::remove_invulnerable(root_origin, leaving.clone())205		);206	}207	verify {208		assert_last_event::<T>(Event::InvulnerableRemoved{invulnerable: leaving}.into());209	}210211	get_license {212		let c in 1 .. T::MaxCollators::get();213214		<LicenseBond<T>>::put(T::Currency::minimum_balance());215216		register_validators::<T>(c);217		get_licenses::<T>(c);218219		let caller: T::AccountId = whitelisted_caller();220		let bond: BalanceOf<T> = T::Currency::minimum_balance() * 2u32.into();221		T::Currency::make_free_balance_be(&caller, bond.clone());222223		<session::Pallet<T>>::set_keys(224			RawOrigin::Signed(caller.clone()).into(),225			keys::<T>(c + 1),226			Vec::new()227		).unwrap();228229	}: _(RawOrigin::Signed(caller.clone()))230	verify {231		assert_last_event::<T>(Event::LicenseObtained{account_id: caller, deposit: bond / 2u32.into()}.into());232	}233234	// worst case is when we have all the max-candidate slots filled except one, and we fill that235	// one.236	onboard {237		let c in 1 .. 5;238239		<LicenseBond<T>>::put(T::Currency::minimum_balance());240		<DesiredCollators<T>>::put(c + 2);241242		register_validators::<T>(c);243		register_candidates::<T>(c);244245		let caller: T::AccountId = whitelisted_caller();246		let bond: BalanceOf<T> = T::Currency::minimum_balance() * 2u32.into();247		T::Currency::make_free_balance_be(&caller, bond.clone());248249		let origin = RawOrigin::Signed(caller.clone());250251		<session::Pallet<T>>::set_keys(252			origin.clone().into(),253			keys::<T>(c + 1),254			Vec::new()255		).unwrap();256257		assert_ok!(258			<CollatorSelection<T>>::get_license(origin.clone().into())259		);260	}: _(origin)261	verify {262		assert_last_event::<T>(Event::CandidateAdded{account_id: caller}.into());263	}264265	// worst case is the last candidate leaving.266	offboard {267		let c in 1 .. T::MaxCollators::get();268		<LicenseBond<T>>::put(T::Currency::minimum_balance());269		<DesiredCollators<T>>::put(c + 2);270271		register_validators::<T>(c);272		register_candidates::<T>(c);273274		let leaving = <Candidates<T>>::get().last().unwrap().clone();275		whitelist!(leaving);276	}: _(RawOrigin::Signed(leaving.clone()))277	verify {278		assert_last_event::<T>(Event::CandidateRemoved{account_id: leaving}.into());279	}280281	// worst case is the last candidate leaving.282	release_license {283		let c in 1 .. T::MaxCollators::get();284		let bond = T::Currency::minimum_balance();285		<LicenseBond<T>>::put(bond);286		<DesiredCollators<T>>::put(c);287288		register_validators::<T>(c);289		register_candidates::<T>(c);290291		let leaving = <Candidates<T>>::get().last().unwrap().clone();292		whitelist!(leaving);293	}: _(RawOrigin::Signed(leaving.clone()))294	verify {295		assert_last_event::<T>(Event::LicenseReleased{account_id: leaving, deposit_returned: bond}.into());296	}297298	// worst case is the last candidate leaving.299	force_release_license {300		let c in 1 .. T::MaxCollators::get();301		let bond = T::Currency::minimum_balance();302		<LicenseBond<T>>::put(bond);303		<DesiredCollators<T>>::put(c);304305		register_validators::<T>(c);306		register_candidates::<T>(c);307308		let leaving = <Candidates<T>>::get().last().unwrap().clone();309		whitelist!(leaving);310		let origin = T::UpdateOrigin::try_successful_origin().unwrap();311	}: {312		assert_ok!(313			<CollatorSelection<T>>::force_release_license(origin, leaving.clone())314		);315	}316	verify {317		assert_last_event::<T>(Event::LicenseReleased{account_id: leaving, deposit_returned: bond}.into());318	}319320	// worst case is paying a non-existing candidate account.321	note_author {322		<LicenseBond<T>>::put(T::Currency::minimum_balance());323		T::Currency::make_free_balance_be(324			&<CollatorSelection<T>>::account_id(),325			T::Currency::minimum_balance() * 4u32.into(),326		);327		let author = account("author", 0, SEED);328		let new_block: T::BlockNumber = 10u32.into();329330		frame_system::Pallet::<T>::set_block_number(new_block);331		assert!(T::Currency::free_balance(&author) == 0u32.into());332	}: {333		<CollatorSelection<T> as EventHandler<_, _>>::note_author(author.clone())334	} verify {335		assert!(T::Currency::free_balance(&author) > 0u32.into());336		assert_eq!(frame_system::Pallet::<T>::block_number(), new_block);337	}338339	// worst case for new session.340	new_session {341		let r in 1 .. T::MaxCollators::get();342		let c in 1 .. T::MaxCollators::get();343344		<LicenseBond<T>>::put(T::Currency::minimum_balance());345		<DesiredCollators<T>>::put(c);346		frame_system::Pallet::<T>::set_block_number(0u32.into());347348		register_validators::<T>(c);349		register_candidates::<T>(c);350351		let new_block: T::BlockNumber = 1800u32.into();352		let zero_block: T::BlockNumber = 0u32.into();353		let candidates = <Candidates<T>>::get();354355		let non_removals = c.saturating_sub(r);356357		for i in 0..c {358			<LastAuthoredBlock<T>>::insert(candidates[i as usize].clone(), zero_block);359		}360361		if non_removals > 0 {362			for i in 0..non_removals {363				<LastAuthoredBlock<T>>::insert(candidates[i as usize].clone(), new_block);364			}365		} else {366			for i in 0..c {367				<LastAuthoredBlock<T>>::insert(candidates[i as usize].clone(), new_block);368			}369		}370371		let pre_length = <Candidates<T>>::get().len();372373		frame_system::Pallet::<T>::set_block_number(new_block);374375		assert!(<Candidates<T>>::get().len() == c as usize);376	}: {377		<CollatorSelection<T> as SessionManager<_>>::new_session(0)378	} verify {379		if c > r {380			assert!(<Candidates<T>>::get().len() < pre_length);381		} else {382			assert!(<Candidates<T>>::get().len() == pre_length);383		}384	}385}386387impl_benchmark_test_suite!(388	CollatorSelection,389	crate::mock::new_test_ext(),390	crate::mock::Test,391);