referrerpolicy=no-referrer-when-downgrade

pallet_meta_tx/
benchmarking.rs

1// This file is part of Substrate.
2
3// Copyright (C) Parity Technologies (UK) Ltd.
4// SPDX-License-Identifier: Apache-2.0
5
6// Licensed under the Apache License, Version 2.0 (the "License");
7// you may not use this file except in compliance with the License.
8// You may obtain a copy of the License at
9//
10// 	http://www.apache.org/licenses/LICENSE-2.0
11//
12// Unless required by applicable law or agreed to in writing, software
13// distributed under the License is distributed on an "AS IS" BASIS,
14// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15// See the License for the specific language governing permissions and
16// limitations under the License.
17
18#![cfg(feature = "runtime-benchmarks")]
19
20use super::*;
21use frame_benchmarking::v2::*;
22use frame_support::traits::UnfilteredDispatchable;
23use sp_runtime::impl_tx_ext_default;
24
25pub mod types {
26	use super::*;
27	use frame_support::traits::OriginTrait;
28	use sp_runtime::traits::DispatchInfoOf;
29
30	type CallOf<T> = <T as frame_system::Config>::RuntimeCall;
31
32	/// A weightless extension to facilitate the bare dispatch benchmark.
33	#[derive(TypeInfo, Eq, PartialEq, Clone, Encode, Decode, DecodeWithMemTracking)]
34	#[scale_info(skip_type_params(T))]
35	pub struct WeightlessExtension<T>(core::marker::PhantomData<T>);
36	impl<T: Config + Send + Sync> core::fmt::Debug for WeightlessExtension<T> {
37		fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
38			write!(f, "WeightlessExtension")
39		}
40	}
41	impl<T: Config + Send + Sync> Default for WeightlessExtension<T> {
42		fn default() -> Self {
43			WeightlessExtension(Default::default())
44		}
45	}
46	impl<T: Config + Send + Sync> TransactionExtension<CallOf<T>> for WeightlessExtension<T> {
47		const IDENTIFIER: &'static str = "WeightlessExtension";
48		type Implicit = ();
49		type Pre = ();
50		type Val = ();
51		fn weight(&self, _call: &CallOf<T>) -> Weight {
52			Weight::from_all(0)
53		}
54		fn validate(
55			&self,
56			mut origin: <CallOf<T> as Dispatchable>::RuntimeOrigin,
57			_: &CallOf<T>,
58			_: &DispatchInfoOf<CallOf<T>>,
59			_: usize,
60			_: (),
61			_: &impl Encode,
62			_: TransactionSource,
63		) -> Result<
64			(ValidTransaction, Self::Val, <CallOf<T> as Dispatchable>::RuntimeOrigin),
65			TransactionValidityError,
66		> {
67			origin.set_caller_from_signed(whitelisted_caller());
68			Ok((ValidTransaction::default(), (), origin))
69		}
70
71		impl_tx_ext_default!(CallOf<T>; prepare);
72	}
73}
74
75fn assert_last_event<T: Config>(generic_event: <T as Config>::RuntimeEvent) {
76	frame_system::Pallet::<T>::assert_last_event(generic_event.into());
77}
78
79#[benchmarks(
80	where
81		T: Config,
82		<T as Config>::Extension: Default,
83	)]
84mod benchmarks {
85	use codec::Compact;
86
87	use super::*;
88
89	#[benchmark]
90	fn bare_dispatch(n: Linear<8, 100>) {
91		let meta_call = frame_system::Call::<T>::remark { remark: vec![] }.into();
92		let meta_ext = T::Extension::default();
93		let meta_ext_weight = meta_ext.weight(&meta_call);
94
95		#[cfg(not(test))]
96		assert!(
97			meta_ext_weight.is_zero(),
98			"meta tx extension weight for the benchmarks must be zero. \
99			use `pallet_meta_tx::WeightlessExtension` as `pallet_meta_tx::Config::Extension` \
100			with the `runtime-benchmarks` feature enabled.",
101		);
102
103		let meta_tx = MetaTxFor::<T>::new(meta_call.clone(), 0u8, meta_ext.clone());
104
105		let caller = whitelisted_caller();
106		let origin: <T as frame_system::Config>::RuntimeOrigin =
107			frame_system::RawOrigin::Signed(caller).into();
108		let call = Call::<T>::dispatch {
109			meta_tx: Box::new(meta_tx.clone()),
110			meta_tx_encoded_len: meta_tx.encoded_size() as u32,
111		};
112
113		// Encoded size of meta tx is 4 bytes, 4 bytes is size of u16 compact number with max value
114		// 0xffff.
115		let length_of_compact_vec = ((n - 4) / 4) as usize;
116		let mut compact_vec = Vec::<Compact<u16>>::with_capacity(length_of_compact_vec);
117		for _ in 0..length_of_compact_vec {
118			compact_vec.push(Compact::from(0xffff));
119		}
120
121		#[block]
122		{
123			let _ = compact_vec.encode();
124			let _ = call.dispatch_bypass_filter(origin);
125		}
126
127		let info = meta_call.get_dispatch_info();
128		assert_last_event::<T>(
129			Event::Dispatched {
130				result: Ok(PostDispatchInfo {
131					actual_weight: Some(info.call_weight + meta_ext_weight),
132					pays_fee: Pays::Yes,
133				}),
134			}
135			.into(),
136		);
137	}
138
139	impl_benchmark_test_suite! {
140		Pallet,
141		crate::mock::new_test_ext(),
142		crate::mock::Runtime,
143	}
144}