// 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. //! Treasury pallet benchmarking. #![cfg(feature = "runtime-benchmarks")] use super::{Pallet as Treasury, *}; use frame_benchmarking::v1::{account, benchmarks_instance_pallet, BenchmarkError}; use frame_support::{ ensure, traits::{EnsureOrigin, OnInitialize, UnfilteredDispatchable}, }; use frame_system::RawOrigin; const SEED: u32 = 0; // Create the pre-requisite information needed to create a treasury `propose_spend`. fn setup_proposal, I: 'static>( u: u32, ) -> (T::AccountId, BalanceOf, AccountIdLookupOf) { let caller = account("caller", u, SEED); let value: BalanceOf = T::ProposalBondMinimum::get().saturating_mul(100u32.into()); let _ = T::Currency::make_free_balance_be(&caller, value); let beneficiary = account("beneficiary", u, SEED); let beneficiary_lookup = T::Lookup::unlookup(beneficiary); (caller, value, beneficiary_lookup) } // Create proposals that are approved for use in `on_initialize`. fn create_approved_proposals, I: 'static>(n: u32) -> Result<(), &'static str> { for i in 0..n { let (caller, value, lookup) = setup_proposal::(i); #[allow(deprecated)] Treasury::::propose_spend(RawOrigin::Signed(caller).into(), value, lookup)?; let proposal_id = >::get() - 1; #[allow(deprecated)] Treasury::::approve_proposal(RawOrigin::Root.into(), proposal_id)?; } ensure!(>::get().len() == n as usize, "Not all approved"); Ok(()) } fn setup_pot_account, I: 'static>() { let pot_account = Treasury::::account_id(); let value = T::Currency::minimum_balance().saturating_mul(1_000_000_000u32.into()); let _ = T::Currency::make_free_balance_be(&pot_account, value); } fn assert_last_event, I: 'static>(generic_event: >::RuntimeEvent) { frame_system::Pallet::::assert_last_event(generic_event.into()); } benchmarks_instance_pallet! { // This benchmark is short-circuited if `SpendOrigin` cannot provide // a successful origin, in which case `spend` is un-callable and can use weight=0. spend { let (_, value, beneficiary_lookup) = setup_proposal::(SEED); let origin = T::SpendOrigin::try_successful_origin(); let beneficiary = T::Lookup::lookup(beneficiary_lookup.clone()).unwrap(); let call = Call::::spend { amount: value, beneficiary: beneficiary_lookup }; }: { if let Ok(origin) = origin.clone() { call.dispatch_bypass_filter(origin)?; } } verify { if origin.is_ok() { assert_last_event::(Event::SpendApproved { proposal_index: 0, amount: value, beneficiary }.into()) } } propose_spend { let (caller, value, beneficiary_lookup) = setup_proposal::(SEED); // Whitelist caller account from further DB operations. let caller_key = frame_system::Account::::hashed_key_for(&caller); frame_benchmarking::benchmarking::add_to_whitelist(caller_key.into()); }: _(RawOrigin::Signed(caller), value, beneficiary_lookup) reject_proposal { let (caller, value, beneficiary_lookup) = setup_proposal::(SEED); #[allow(deprecated)] Treasury::::propose_spend( RawOrigin::Signed(caller).into(), value, beneficiary_lookup )?; let proposal_id = Treasury::::proposal_count() - 1; let reject_origin = T::RejectOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; }: _(reject_origin, proposal_id) approve_proposal { let p in 0 .. T::MaxApprovals::get() - 1; create_approved_proposals::(p)?; let (caller, value, beneficiary_lookup) = setup_proposal::(SEED); #[allow(deprecated)] Treasury::::propose_spend( RawOrigin::Signed(caller).into(), value, beneficiary_lookup )?; let proposal_id = Treasury::::proposal_count() - 1; let approve_origin = T::ApproveOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; }: _(approve_origin, proposal_id) remove_approval { let (caller, value, beneficiary_lookup) = setup_proposal::(SEED); #[allow(deprecated)] Treasury::::propose_spend( RawOrigin::Signed(caller).into(), value, beneficiary_lookup )?; let proposal_id = Treasury::::proposal_count() - 1; #[allow(deprecated)] Treasury::::approve_proposal(RawOrigin::Root.into(), proposal_id)?; let reject_origin = T::RejectOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; }: _(reject_origin, proposal_id) on_initialize_proposals { let p in 0 .. T::MaxApprovals::get(); setup_pot_account::(); create_approved_proposals::(p)?; }: { Treasury::::on_initialize(frame_system::pallet_prelude::BlockNumberFor::::zero()); } impl_benchmark_test_suite!(Treasury, crate::tests::new_test_ext(), crate::tests::Test); }