// 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. //! Staking pallet benchmarking. use super::*; #[allow(unused_imports)] use crate::Pallet as RankedCollective; use frame_benchmarking::v1::{ account, benchmarks_instance_pallet, whitelisted_caller, BenchmarkError, }; use frame_support::{assert_ok, traits::UnfilteredDispatchable}; use frame_system::RawOrigin as SystemOrigin; const SEED: u32 = 0; fn assert_last_event, I: 'static>(generic_event: >::RuntimeEvent) { frame_system::Pallet::::assert_last_event(generic_event.into()); } fn assert_has_event, I: 'static>(generic_event: >::RuntimeEvent) { frame_system::Pallet::::assert_has_event(generic_event.into()); } fn make_member, I: 'static>(rank: Rank) -> T::AccountId { let who = account::("member", MemberCount::::get(0), SEED); let who_lookup = T::Lookup::unlookup(who.clone()); assert_ok!(Pallet::::add_member( T::AddOrigin::try_successful_origin() .expect("AddOrigin has no successful origin required for the benchmark"), who_lookup.clone(), )); for _ in 0..rank { assert_ok!(Pallet::::promote_member( T::PromoteOrigin::try_successful_origin() .expect("PromoteOrigin has no successful origin required for the benchmark"), who_lookup.clone(), )); } who } benchmarks_instance_pallet! { add_member { let who = account::("member", 0, SEED); let who_lookup = T::Lookup::unlookup(who.clone()); let origin = T::AddOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; let call = Call::::add_member { who: who_lookup }; }: { call.dispatch_bypass_filter(origin)? } verify { assert_eq!(MemberCount::::get(0), 1); assert_last_event::(Event::MemberAdded { who }.into()); } remove_member { let r in 0 .. 10; let rank = r as u16; let first = make_member::(rank); let who = make_member::(rank); let who_lookup = T::Lookup::unlookup(who.clone()); let last = make_member::(rank); let last_index = (0..=rank).map(|r| IdToIndex::::get(r, &last).unwrap()).collect::>(); let origin = T::RemoveOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; let call = Call::::remove_member { who: who_lookup, min_rank: rank }; }: { call.dispatch_bypass_filter(origin)? } verify { for r in 0..=rank { assert_eq!(MemberCount::::get(r), 2); assert_ne!(last_index[r as usize], IdToIndex::::get(r, &last).unwrap()); } assert_last_event::(Event::MemberRemoved { who, rank }.into()); } promote_member { let r in 0 .. 10; let rank = r as u16; let who = make_member::(rank); let who_lookup = T::Lookup::unlookup(who.clone()); let origin = T::PromoteOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; let call = Call::::promote_member { who: who_lookup }; }: { call.dispatch_bypass_filter(origin)? } verify { assert_eq!(Members::::get(&who).unwrap().rank, rank + 1); assert_last_event::(Event::RankChanged { who, rank: rank + 1 }.into()); } demote_member { let r in 0 .. 10; let rank = r as u16; let first = make_member::(rank); let who = make_member::(rank); let who_lookup = T::Lookup::unlookup(who.clone()); let last = make_member::(rank); let last_index = IdToIndex::::get(rank, &last).unwrap(); let origin = T::DemoteOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; let call = Call::::demote_member { who: who_lookup }; }: { call.dispatch_bypass_filter(origin)? } verify { assert_eq!(Members::::get(&who).map(|x| x.rank), rank.checked_sub(1)); assert_eq!(MemberCount::::get(rank), 2); assert_ne!(last_index, IdToIndex::::get(rank, &last).unwrap()); assert_last_event::(match rank { 0 => Event::MemberRemoved { who, rank: 0 }, r => Event::RankChanged { who, rank: r - 1 }, }.into()); } vote { let class = T::Polls::classes().into_iter().next().unwrap(); let rank = T::MinRankOfClass::convert(class.clone()); let caller = make_member::(rank); let caller_lookup = T::Lookup::unlookup(caller.clone()); let poll = T::Polls::create_ongoing(class).expect("Must always be able to create a poll for rank 0"); // Vote once. assert_ok!(Pallet::::vote(SystemOrigin::Signed(caller.clone()).into(), poll, true)); }: _(SystemOrigin::Signed(caller.clone()), poll, false) verify { let tally = Tally::from_parts(0, 0, 1); let ev = Event::Voted { who: caller, poll, vote: VoteRecord::Nay(1), tally }; assert_last_event::(ev.into()); } cleanup_poll { let n in 0 .. 100; // Create a poll let class = T::Polls::classes().into_iter().next().unwrap(); let rank = T::MinRankOfClass::convert(class.clone()); let poll = T::Polls::create_ongoing(class).expect("Must always be able to create a poll"); // Vote in the poll by each of `n` members for i in 0..n { let who = make_member::(rank); assert_ok!(Pallet::::vote(SystemOrigin::Signed(who).into(), poll, true)); } // End the poll. T::Polls::end_ongoing(poll, false).expect("Must always be able to end a poll"); assert_eq!(Voting::::iter_prefix(poll).count(), n as usize); }: _(SystemOrigin::Signed(whitelisted_caller()), poll, n) verify { assert_eq!(Voting::::iter().count(), 0); } exchange_member { let who = make_member::(1); T::BenchmarkSetup::ensure_member(&who); let who_lookup = T::Lookup::unlookup(who.clone()); let new_who = account::("new-member", 0, SEED); let new_who_lookup = T::Lookup::unlookup(new_who.clone()); let origin = T::ExchangeOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; let call = Call::::exchange_member { who: who_lookup, new_who: new_who_lookup }; }: { call.dispatch_bypass_filter(origin)? } verify { assert_eq!(Members::::get(&new_who).unwrap().rank, 1); assert_eq!(Members::::get(&who), None); assert_has_event::(Event::MemberExchanged { who, new_who }.into()); } impl_benchmark_test_suite!(RankedCollective, crate::tests::ExtBuilder::default().build(), crate::tests::Test); }