From 6ec82c7a83294e6027dc6e793510a787d9181a02 Mon Sep 17 00:00:00 2001 From: Falco Hirschenberger <falco.hirschenberger@gmail.com> Date: Mon, 27 Sep 2021 17:17:38 +0200 Subject: [PATCH] Add weight for decoding the call to benchmarks (#9781) * First two bechmarks converted * Add decoding weight to benchmarks. * Update frame/democracy/src/benchmarking.rs * Adapt to new Call-ing convention * Resolve conflicts and change more calls * Remove error impl for codec and use plain `expect` for error handling instead * Compile fix * Spaces to tabs * Update frame/democracy/src/benchmarking.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * Add origin-type specifier to benchmarks macro * formatting * Update frame/benchmarking/src/lib.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * Change manual to automatic benchmark syntax * Formatting * Revert "Change manual to automatic benchmark syntax" This reverts commit ea5b5d906b318b6525c1e6d2bd05c5011595c21a. Because tests are lost and cleanup code in the verify function is not run on failing calls. Co-authored-by: Guillaume Thiolliere <gui.thiolliere@gmail.com> Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> --- substrate/frame/benchmarking/src/lib.rs | 33 ++++++++++++---- substrate/frame/benchmarking/src/utils.rs | 1 - substrate/frame/democracy/src/benchmarking.rs | 38 +++++++------------ .../src/benchmarking.rs | 1 - .../elections-phragmen/src/benchmarking.rs | 15 +++++++- substrate/frame/gilt/src/benchmarking.rs | 15 +++----- substrate/frame/im-online/src/benchmarking.rs | 8 ++-- substrate/frame/lottery/src/benchmarking.rs | 13 ++----- substrate/frame/staking/src/benchmarking.rs | 11 +++++- 9 files changed, 75 insertions(+), 60 deletions(-) diff --git a/substrate/frame/benchmarking/src/lib.rs b/substrate/frame/benchmarking/src/lib.rs index 6c124a8a757..4a6c5e15ae2 100644 --- a/substrate/frame/benchmarking/src/lib.rs +++ b/substrate/frame/benchmarking/src/lib.rs @@ -131,6 +131,13 @@ macro_rules! whitelist { /// let c = 0 .. 10 => setup_c_in_some_other_way(&caller, c); /// }: baz(Origin::Signed(caller)) /// +/// // You may optionally specify the origin type if it can't be determined automatically like +/// // this. +/// baz3 { +/// let caller = account::<T>(b"caller", 0, benchmarks_seed); +/// let l in 1 .. MAX_LENGTH => initialize_l(l); +/// }: baz<T::Origin>(Origin::Signed(caller), vec![0u8; l]) +/// /// // this is benchmarking some code that is not a dispatchable. /// populate_a_set { /// let x in 0 .. 10_000; @@ -305,7 +312,7 @@ macro_rules! benchmarks_iter { ( $( $names:tt )* ) // This contains $( $( { $instance } )? $name:ident )* ( $( $names_extra:tt )* ) ( $( $names_skip_meta:tt )* ) - $name:ident { $( $code:tt )* }: _ ( $origin:expr $( , $arg:expr )* ) + $name:ident { $( $code:tt )* }: _ $(< $origin_type:ty>)? ( $origin:expr $( , $arg:expr )* ) verify $postcode:block $( $rest:tt )* ) => { @@ -315,7 +322,7 @@ macro_rules! benchmarks_iter { ( $( $names )* ) ( $( $names_extra )* ) ( $( $names_skip_meta )* ) - $name { $( $code )* }: $name ( $origin $( , $arg )* ) + $name { $( $code )* }: $name $(< $origin_type >)? ( $origin $( , $arg )* ) verify $postcode $( $rest )* } @@ -327,7 +334,7 @@ macro_rules! benchmarks_iter { ( $( $names:tt )* ) ( $( $names_extra:tt )* ) ( $( $names_skip_meta:tt )* ) - $name:ident { $( $code:tt )* }: $dispatch:ident ( $origin:expr $( , $arg:expr )* ) + $name:ident { $( $code:tt )* }: $dispatch:ident $(<$origin_type:ty>)? ( $origin:expr $( , $arg:expr )* ) verify $postcode:block $( $rest:tt )* ) => { @@ -350,15 +357,14 @@ macro_rules! benchmarks_iter { &__call ); }: { - let call_decoded = < + let __call_decoded = < Call<T $(, $instance )?> as $crate::frame_support::codec::Decode >::decode(&mut &__benchmarked_call_encoded[..]) .expect("call is encoded above, encoding must be correct"); - - < - Call<T $(, $instance)? > as $crate::frame_support::traits::UnfilteredDispatchable - >::dispatch_bypass_filter(call_decoded, $origin.into())?; + let __origin = $crate::to_origin!($origin $(, $origin_type)?); + <Call<T $(, $instance)? > as $crate::frame_support::traits::UnfilteredDispatchable + >::dispatch_bypass_filter(__call_decoded, __origin)?; } verify $postcode $( $rest )* @@ -488,6 +494,17 @@ macro_rules! benchmarks_iter { }; } +#[macro_export] +#[doc(hidden)] +macro_rules! to_origin { + ($origin:expr) => { + $origin.into() + }; + ($origin:expr, $origin_type:ty) => { + <T::Origin as From<$origin_type>>::from($origin) + }; +} + #[macro_export] #[doc(hidden)] macro_rules! benchmark_backend { diff --git a/substrate/frame/benchmarking/src/utils.rs b/substrate/frame/benchmarking/src/utils.rs index 158f5c5b575..c24ad2f64e1 100644 --- a/substrate/frame/benchmarking/src/utils.rs +++ b/substrate/frame/benchmarking/src/utils.rs @@ -16,7 +16,6 @@ // limitations under the License. //! Interfaces, types and utils for benchmarking a FRAME runtime. - use codec::{Decode, Encode}; use frame_support::{ dispatch::{DispatchError, DispatchErrorWithPostInfo}, diff --git a/substrate/frame/democracy/src/benchmarking.rs b/substrate/frame/democracy/src/benchmarking.rs index 7d4d7aee140..a00e6f4686f 100644 --- a/substrate/frame/democracy/src/benchmarking.rs +++ b/substrate/frame/democracy/src/benchmarking.rs @@ -22,6 +22,7 @@ use super::*; use frame_benchmarking::{account, benchmarks, impl_benchmark_test_suite, whitelist_account}; use frame_support::{ assert_noop, assert_ok, + codec::Decode, traits::{ schedule::DispatchTime, Currency, EnsureOrigin, Get, OnInitialize, UnfilteredDispatchable, }, @@ -194,9 +195,8 @@ benchmarks! { emergency_cancel { let origin = T::CancellationOrigin::successful_origin(); let referendum_index = add_referendum::<T>(0)?; - let call = Call::<T>::emergency_cancel { ref_index: referendum_index }; assert_ok!(Democracy::<T>::referendum_status(referendum_index)); - }: { call.dispatch_bypass_filter(origin)? } + }: _<T::Origin>(origin, referendum_index) verify { // Referendum has been canceled assert_noop!( @@ -219,14 +219,11 @@ benchmarks! { assert_ok!( Democracy::<T>::external_propose(T::ExternalOrigin::successful_origin(), hash.clone()) ); - + let origin = T::BlacklistOrigin::successful_origin(); // Add a referendum of our proposal. let referendum_index = add_referendum::<T>(0)?; assert_ok!(Democracy::<T>::referendum_status(referendum_index)); - - let call = Call::<T>::blacklist { proposal_hash: hash, maybe_ref_index: Some(referendum_index) }; - let origin = T::BlacklistOrigin::successful_origin(); - }: { call.dispatch_bypass_filter(origin)? } + }: _<T::Origin>(origin, hash, Some(referendum_index)) verify { // Referendum has been canceled assert_noop!( @@ -246,9 +243,7 @@ benchmarks! { proposal_hash, (T::BlockNumber::zero(), vec![T::AccountId::default(); v as usize]) ); - - let call = Call::<T>::external_propose { proposal_hash }; - }: { call.dispatch_bypass_filter(origin)? } + }: _<T::Origin>(origin, proposal_hash) verify { // External proposal created ensure!(<NextExternal<T>>::exists(), "External proposal didn't work"); @@ -257,8 +252,7 @@ benchmarks! { external_propose_majority { let origin = T::ExternalMajorityOrigin::successful_origin(); let proposal_hash = T::Hashing::hash_of(&0); - let call = Call::<T>::external_propose_majority { proposal_hash }; - }: { call.dispatch_bypass_filter(origin)? } + }: _<T::Origin>(origin, proposal_hash) verify { // External proposal created ensure!(<NextExternal<T>>::exists(), "External proposal didn't work"); @@ -267,8 +261,7 @@ benchmarks! { external_propose_default { let origin = T::ExternalDefaultOrigin::successful_origin(); let proposal_hash = T::Hashing::hash_of(&0); - let call = Call::<T>::external_propose_default { proposal_hash }; - }: { call.dispatch_bypass_filter(origin)? } + }: _<T::Origin>(origin, proposal_hash) verify { // External proposal created ensure!(<NextExternal<T>>::exists(), "External proposal didn't work"); @@ -283,13 +276,7 @@ benchmarks! { let origin_fast_track = T::FastTrackOrigin::successful_origin(); let voting_period = T::FastTrackVotingPeriod::get(); let delay = 0u32; - let call = Call::<T>::fast_track { - proposal_hash, - voting_period: voting_period.into(), - delay: delay.into() - }; - - }: { call.dispatch_bypass_filter(origin_fast_track)? } + }: _<T::Origin>(origin_fast_track, proposal_hash, voting_period.into(), delay.into()) verify { assert_eq!(Democracy::<T>::referendum_count(), 1, "referendum not created") } @@ -310,10 +297,9 @@ benchmarks! { vetoers.sort(); Blacklist::<T>::insert(proposal_hash, (T::BlockNumber::zero(), vetoers)); - let call = Call::<T>::veto_external { proposal_hash }; let origin = T::VetoOrigin::successful_origin(); ensure!(NextExternal::<T>::get().is_some(), "no external proposal"); - }: { call.dispatch_bypass_filter(origin)? } + }: _<T::Origin>(origin, proposal_hash) verify { assert!(NextExternal::<T>::get().is_none()); let (_, new_vetoers) = <Blacklist<T>>::get(&proposal_hash).ok_or("no blacklist")?; @@ -774,9 +760,13 @@ benchmarks! { Some(PreimageStatus::Available { .. }) => (), _ => return Err("preimage not available".into()) } + let origin = RawOrigin::Root.into(); + let call = Call::<T>::enact_proposal { proposal_hash, index: 0 }.encode(); }: { assert_eq!( - Democracy::<T>::enact_proposal(RawOrigin::Root.into(), proposal_hash, 0), + <Call<T> as Decode>::decode(&mut &*call) + .expect("call is encoded above, encoding must be correct") + .dispatch_bypass_filter(origin), Err(Error::<T>::PreimageInvalid.into()) ); } diff --git a/substrate/frame/election-provider-multi-phase/src/benchmarking.rs b/substrate/frame/election-provider-multi-phase/src/benchmarking.rs index a5bb0d6351c..b8d7bc45c44 100644 --- a/substrate/frame/election-provider-multi-phase/src/benchmarking.rs +++ b/substrate/frame/election-provider-multi-phase/src/benchmarking.rs @@ -350,7 +350,6 @@ frame_benchmarking::benchmarks! { assert!(<MultiPhase<T>>::queued_solution().is_none()); <CurrentPhase<T>>::put(Phase::Unsigned((true, 1u32.into()))); - }: _(RawOrigin::None, Box::new(raw_solution), witness) verify { assert!(<MultiPhase<T>>::queued_solution().is_some()); diff --git a/substrate/frame/elections-phragmen/src/benchmarking.rs b/substrate/frame/elections-phragmen/src/benchmarking.rs index 7cb83b3dd77..6e3ce0234c4 100644 --- a/substrate/frame/elections-phragmen/src/benchmarking.rs +++ b/substrate/frame/elections-phragmen/src/benchmarking.rs @@ -24,7 +24,10 @@ use super::*; use frame_benchmarking::{ account, benchmarks, impl_benchmark_test_suite, whitelist, BenchmarkError, BenchmarkResult, }; -use frame_support::{dispatch::DispatchResultWithPostInfo, traits::OnInitialize}; +use frame_support::{ + dispatch::{DispatchResultWithPostInfo, UnfilteredDispatchable}, + traits::OnInitialize, +}; use frame_system::RawOrigin; use crate::Pallet as Elections; @@ -401,15 +404,23 @@ benchmarks! { let _ = fill_seats_up_to::<T>(m)?; let removing = as_lookup::<T>(<Elections<T>>::members_ids()[0].clone()); + let who = T::Lookup::lookup(removing.clone()).expect("member was added above"); + let call = Call::<T>::remove_member { who: removing, has_replacement: false }.encode(); }: { assert_eq!( - <Elections<T>>::remove_member(RawOrigin::Root.into(), removing, false).unwrap_err().error, + <Call<T> as Decode>::decode(&mut &*call) + .expect("call is encoded above, encoding must be correct") + .dispatch_bypass_filter(RawOrigin::Root.into()) + .unwrap_err() + .error, Error::<T>::InvalidReplacement.into(), ); } verify { // must still have enough members. assert_eq!(<Elections<T>>::members().len() as u32, T::DesiredMembers::get()); + // on fail, `who` must still be a member + assert!(<Elections<T>>::members_ids().contains(&who)); #[cfg(test)] { // reset members in between benchmark tests. diff --git a/substrate/frame/gilt/src/benchmarking.rs b/substrate/frame/gilt/src/benchmarking.rs index 55d34a35a7c..cfc503cf897 100644 --- a/substrate/frame/gilt/src/benchmarking.rs +++ b/substrate/frame/gilt/src/benchmarking.rs @@ -50,17 +50,12 @@ benchmarks! { place_bid_max { let caller: T::AccountId = whitelisted_caller(); + let origin = RawOrigin::Signed(caller.clone()); T::Currency::make_free_balance_be(&caller, BalanceOf::<T>::max_value()); for i in 0..T::MaxQueueLen::get() { - Gilt::<T>::place_bid(RawOrigin::Signed(caller.clone()).into(), T::MinFreeze::get(), 1)?; + Gilt::<T>::place_bid(origin.clone().into(), T::MinFreeze::get(), 1)?; } - }: { - Gilt::<T>::place_bid( - RawOrigin::Signed(caller.clone()).into(), - T::MinFreeze::get() * BalanceOf::<T>::from(2u32), - 1, - )? - } + }: place_bid(origin, T::MinFreeze::get() * BalanceOf::<T>::from(2u32), 1) verify { assert_eq!(QueueTotals::<T>::get()[0], ( T::MaxQueueLen::get(), @@ -81,9 +76,9 @@ benchmarks! { } set_target { - let call = Call::<T>::set_target { target: Default::default() }; let origin = T::AdminOrigin::successful_origin(); - }: { call.dispatch_bypass_filter(origin)? } + }: _<T::Origin>(origin, Default::default()) + verify {} thaw { let caller: T::AccountId = whitelisted_caller(); diff --git a/substrate/frame/im-online/src/benchmarking.rs b/substrate/frame/im-online/src/benchmarking.rs index 20812f03d28..b39b0057c48 100644 --- a/substrate/frame/im-online/src/benchmarking.rs +++ b/substrate/frame/im-online/src/benchmarking.rs @@ -93,10 +93,12 @@ benchmarks! { let e in 1 .. MAX_EXTERNAL_ADDRESSES; let (input_heartbeat, signature) = create_heartbeat::<T>(k, e)?; let call = Call::heartbeat { heartbeat: input_heartbeat, signature }; + let call_enc = call.encode(); }: { - ImOnline::<T>::validate_unsigned(TransactionSource::InBlock, &call) - .map_err(<&str>::from)?; - call.dispatch_bypass_filter(RawOrigin::None.into())?; + ImOnline::<T>::validate_unsigned(TransactionSource::InBlock, &call).map_err(<&str>::from)?; + <Call<T> as Decode>::decode(&mut &*call_enc) + .expect("call is encoded above, encoding must be correct") + .dispatch_bypass_filter(RawOrigin::None.into())?; } } diff --git a/substrate/frame/lottery/src/benchmarking.rs b/substrate/frame/lottery/src/benchmarking.rs index 3b7035c72de..7af20bbb0e1 100644 --- a/substrate/frame/lottery/src/benchmarking.rs +++ b/substrate/frame/lottery/src/benchmarking.rs @@ -22,7 +22,7 @@ use super::*; use frame_benchmarking::{account, benchmarks, impl_benchmark_test_suite, whitelisted_caller}; -use frame_support::traits::{EnsureOrigin, OnInitialize, UnfilteredDispatchable}; +use frame_support::traits::{EnsureOrigin, OnInitialize}; use frame_system::RawOrigin; use sp_runtime::traits::{Bounded, Zero}; @@ -73,11 +73,9 @@ benchmarks! { set_calls { let n in 0 .. T::MaxCalls::get() as u32; let calls = vec![frame_system::Call::<T>::remark { remark: vec![] }.into(); n as usize]; - - let call = Call::<T>::set_calls { calls }; let origin = T::ManagerOrigin::successful_origin(); assert!(CallIndices::<T>::get().is_empty()); - }: { call.dispatch_bypass_filter(origin)? } + }: _<T::Origin>(origin, calls) verify { if !n.is_zero() { assert!(!CallIndices::<T>::get().is_empty()); @@ -88,10 +86,8 @@ benchmarks! { let price = BalanceOf::<T>::max_value(); let end = 10u32.into(); let payout = 5u32.into(); - - let call = Call::<T>::start_lottery { price, length: end, delay: payout, repeat: true }; let origin = T::ManagerOrigin::successful_origin(); - }: { call.dispatch_bypass_filter(origin)? } + }: _<T::Origin>(origin, price, end, payout, true) verify { assert!(crate::Lottery::<T>::get().is_some()); } @@ -99,9 +95,8 @@ benchmarks! { stop_repeat { setup_lottery::<T>(true)?; assert_eq!(crate::Lottery::<T>::get().unwrap().repeat, true); - let call = Call::<T>::stop_repeat {}; let origin = T::ManagerOrigin::successful_origin(); - }: { call.dispatch_bypass_filter(origin)? } + }: _<T::Origin>(origin) verify { assert_eq!(crate::Lottery::<T>::get().unwrap().repeat, false); } diff --git a/substrate/frame/staking/src/benchmarking.rs b/substrate/frame/staking/src/benchmarking.rs index f3def720632..fe60d516e14 100644 --- a/substrate/frame/staking/src/benchmarking.rs +++ b/substrate/frame/staking/src/benchmarking.rs @@ -23,6 +23,7 @@ use testing_utils::*; use frame_election_provider_support::SortedListProvider; use frame_support::{ + dispatch::UnfilteredDispatchable, pallet_prelude::*, traits::{Currency, CurrencyToVote, Get, Imbalance}, }; @@ -764,9 +765,15 @@ benchmarks! { <ErasValidatorReward<T>>::insert(current_era, total_payout); let caller: T::AccountId = whitelisted_caller(); + let origin = RawOrigin::Signed(caller); + let calls: Vec<_> = payout_calls_arg.iter().map(|arg| + Call::<T>::payout_stakers { validator_stash: arg.0.clone(), era: arg.1 }.encode() + ).collect(); }: { - for arg in payout_calls_arg { - <Staking<T>>::payout_stakers(RawOrigin::Signed(caller.clone()).into(), arg.0, arg.1)?; + for call in calls { + <Call<T> as Decode>::decode(&mut &*call) + .expect("call is encoded above, encoding must be correct") + .dispatch_bypass_filter(origin.clone().into())?; } } -- GitLab