// This file is part of Substrate. // Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //! Membership pallet benchmarking. use super::{Pallet as Membership, *}; use frame_benchmarking::v1::{account, benchmarks_instance_pallet, whitelist, BenchmarkError}; use frame_support::{assert_ok, traits::EnsureOrigin}; use frame_system::RawOrigin; const SEED: u32 = 0; fn set_members, I: 'static>(members: Vec, prime: Option) { let reset_origin = T::ResetOrigin::try_successful_origin() .expect("ResetOrigin has no successful origin required for the benchmark"); let prime_origin = T::PrimeOrigin::try_successful_origin() .expect("PrimeOrigin has no successful origin required for the benchmark"); assert_ok!(Membership::::reset_members(reset_origin, members.clone())); if let Some(prime) = prime.map(|i| members[i].clone()) { let prime_lookup = T::Lookup::unlookup(prime); assert_ok!(Membership::::set_prime(prime_origin, prime_lookup)); } else { assert_ok!(Membership::::clear_prime(prime_origin)); } } benchmarks_instance_pallet! { add_member { let m in 1 .. (T::MaxMembers::get() - 1); let members = (0..m).map(|i| account("member", i, SEED)).collect::>(); set_members::(members, None); let new_member = account::("add", m, SEED); let new_member_lookup = T::Lookup::unlookup(new_member.clone()); }: { assert_ok!(Membership::::add_member( T::AddOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?, new_member_lookup, )); } verify { assert!(Members::::get().contains(&new_member)); #[cfg(test)] crate::mock::clean(); } // the case of no prime or the prime being removed is surely cheaper than the case of // reporting a new prime via `MembershipChanged`. remove_member { let m in 2 .. T::MaxMembers::get(); let members = (0..m).map(|i| account("member", i, SEED)).collect::>(); set_members::(members.clone(), Some(members.len() - 1)); let to_remove = members.first().cloned().unwrap(); let to_remove_lookup = T::Lookup::unlookup(to_remove.clone()); }: { assert_ok!(Membership::::remove_member( T::RemoveOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?, to_remove_lookup, )); } verify { assert!(!Members::::get().contains(&to_remove)); // prime is rejigged assert!(Prime::::get().is_some() && T::MembershipChanged::get_prime().is_some()); #[cfg(test)] crate::mock::clean(); } // we remove a non-prime to make sure it needs to be set again. swap_member { let m in 2 .. T::MaxMembers::get(); let members = (0..m).map(|i| account("member", i, SEED)).collect::>(); set_members::(members.clone(), Some(members.len() - 1)); let add = account::("member", m, SEED); let add_lookup = T::Lookup::unlookup(add.clone()); let remove = members.first().cloned().unwrap(); let remove_lookup = T::Lookup::unlookup(remove.clone()); }: { assert_ok!(Membership::::swap_member( T::SwapOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?, remove_lookup, add_lookup, )); } verify { assert!(!Members::::get().contains(&remove)); assert!(Members::::get().contains(&add)); // prime is rejigged assert!(Prime::::get().is_some() && T::MembershipChanged::get_prime().is_some()); #[cfg(test)] crate::mock::clean(); } // er keep the prime common between incoming and outgoing to make sure it is rejigged. reset_members { let m in 1 .. T::MaxMembers::get(); let members = (1..m+1).map(|i| account("member", i, SEED)).collect::>(); set_members::(members.clone(), Some(members.len() - 1)); let mut new_members = (m..2*m).map(|i| account("member", i, SEED)).collect::>(); }: { assert_ok!(Membership::::reset_members( T::ResetOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?, new_members.clone(), )); } verify { new_members.sort(); assert_eq!(Members::::get(), new_members); // prime is rejigged assert!(Prime::::get().is_some() && T::MembershipChanged::get_prime().is_some()); #[cfg(test)] crate::mock::clean(); } change_key { let m in 1 .. T::MaxMembers::get(); // worse case would be to change the prime let members = (0..m).map(|i| account("member", i, SEED)).collect::>(); let prime = members.last().cloned().unwrap(); set_members::(members.clone(), Some(members.len() - 1)); let add = account::("member", m, SEED); let add_lookup = T::Lookup::unlookup(add.clone()); whitelist!(prime); }: { assert_ok!(Membership::::change_key(RawOrigin::Signed(prime.clone()).into(), add_lookup)); } verify { assert!(!Members::::get().contains(&prime)); assert!(Members::::get().contains(&add)); // prime is rejigged assert_eq!(Prime::::get().unwrap(), add); #[cfg(test)] crate::mock::clean(); } set_prime { let m in 1 .. T::MaxMembers::get(); let members = (0..m).map(|i| account("member", i, SEED)).collect::>(); let prime = members.last().cloned().unwrap(); let prime_lookup = T::Lookup::unlookup(prime.clone()); set_members::(members, None); }: { assert_ok!(Membership::::set_prime( T::PrimeOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?, prime_lookup, )); } verify { assert!(Prime::::get().is_some()); assert!(::get_prime().is_some()); #[cfg(test)] crate::mock::clean(); } clear_prime { let members = (0..T::MaxMembers::get()).map(|i| account("member", i, SEED)).collect::>(); let prime = members.last().cloned().unwrap(); set_members::(members, None); }: { assert_ok!(Membership::::clear_prime( T::PrimeOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?, )); } verify { assert!(Prime::::get().is_none()); assert!(::get_prime().is_none()); #[cfg(test)] crate::mock::clean(); } impl_benchmark_test_suite!(Membership, crate::mock::new_bench_ext(), crate::mock::Test); }