referrerpolicy=no-referrer-when-downgrade

frame_system_benchmarking/
extensions.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// Benchmarks for System Extensions
19
20#![cfg(feature = "runtime-benchmarks")]
21
22use alloc::vec;
23use frame_benchmarking::{account, v2::*, BenchmarkError};
24use frame_support::{
25	dispatch::{DispatchClass, DispatchInfo, PostDispatchInfo},
26	pallet_prelude::Zero,
27	weights::Weight,
28};
29use frame_system::{
30	pallet_prelude::*, CheckGenesis, CheckMortality, CheckNonZeroSender, CheckNonce,
31	CheckSpecVersion, CheckTxVersion, CheckWeight, Config, ExtensionsWeightInfo, Pallet as System,
32	RawOrigin, WeightReclaim,
33};
34use sp_runtime::{
35	generic::Era,
36	traits::{
37		AsSystemOriginSigner, AsTransactionAuthorizedOrigin, DispatchTransaction, Dispatchable, Get,
38	},
39};
40
41pub struct Pallet<T: Config>(System<T>);
42
43#[benchmarks(where
44	T: Send + Sync,
45    T::RuntimeCall: Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo>,
46	<T::RuntimeCall as Dispatchable>::RuntimeOrigin: AsSystemOriginSigner<T::AccountId> + AsTransactionAuthorizedOrigin + Clone,
47)]
48mod benchmarks {
49	use super::*;
50
51	#[benchmark]
52	fn check_genesis() -> Result<(), BenchmarkError> {
53		let len = 0_usize;
54		let caller = account("caller", 0, 0);
55		let info = DispatchInfo { call_weight: Weight::zero(), ..Default::default() };
56		let call: T::RuntimeCall = frame_system::Call::remark { remark: vec![] }.into();
57		frame_benchmarking::benchmarking::add_to_whitelist(
58			frame_system::BlockHash::<T>::hashed_key_for(BlockNumberFor::<T>::zero()).into(),
59		);
60
61		#[block]
62		{
63			CheckGenesis::<T>::new()
64				.test_run(RawOrigin::Signed(caller).into(), &call, &info, len, 0, |_| Ok(().into()))
65				.unwrap()
66				.unwrap();
67		}
68
69		Ok(())
70	}
71
72	#[benchmark]
73	fn check_mortality_mortal_transaction() -> Result<(), BenchmarkError> {
74		let len = 0_usize;
75		let ext = CheckMortality::<T>::from(Era::mortal(16, 256));
76		let block_number: BlockNumberFor<T> = 17u32.into();
77		System::<T>::set_block_number(block_number);
78		let prev_block: BlockNumberFor<T> = 16u32.into();
79		let default_hash: T::Hash = Default::default();
80		frame_system::BlockHash::<T>::insert(prev_block, default_hash);
81		let caller = account("caller", 0, 0);
82		let info = DispatchInfo {
83			call_weight: Weight::from_parts(100, 0),
84			class: DispatchClass::Normal,
85			..Default::default()
86		};
87		let call: T::RuntimeCall = frame_system::Call::remark { remark: vec![] }.into();
88		frame_benchmarking::benchmarking::add_to_whitelist(
89			frame_system::BlockHash::<T>::hashed_key_for(prev_block).into(),
90		);
91
92		#[block]
93		{
94			ext.test_run(RawOrigin::Signed(caller).into(), &call, &info, len, 0, |_| Ok(().into()))
95				.unwrap()
96				.unwrap();
97		}
98		Ok(())
99	}
100
101	#[benchmark]
102	fn check_mortality_immortal_transaction() -> Result<(), BenchmarkError> {
103		let len = 0_usize;
104		let ext = CheckMortality::<T>::from(Era::immortal());
105		let block_number: BlockNumberFor<T> = 17u32.into();
106		System::<T>::set_block_number(block_number);
107		let prev_block: BlockNumberFor<T> = 16u32.into();
108		let default_hash: T::Hash = Default::default();
109		frame_system::BlockHash::<T>::insert(prev_block, default_hash);
110		let genesis_block: BlockNumberFor<T> = 0u32.into();
111		frame_system::BlockHash::<T>::insert(genesis_block, default_hash);
112		let caller = account("caller", 0, 0);
113		let info = DispatchInfo {
114			call_weight: Weight::from_parts(100, 0),
115			class: DispatchClass::Normal,
116			..Default::default()
117		};
118		let call: T::RuntimeCall = frame_system::Call::remark { remark: vec![] }.into();
119		frame_benchmarking::benchmarking::add_to_whitelist(
120			frame_system::BlockHash::<T>::hashed_key_for(BlockNumberFor::<T>::zero()).into(),
121		);
122
123		#[block]
124		{
125			ext.test_run(RawOrigin::Signed(caller).into(), &call, &info, len, 0, |_| Ok(().into()))
126				.unwrap()
127				.unwrap();
128		}
129		Ok(())
130	}
131
132	#[benchmark]
133	fn check_non_zero_sender() -> Result<(), BenchmarkError> {
134		let len = 0_usize;
135		let ext = CheckNonZeroSender::<T>::new();
136		let caller = account("caller", 0, 0);
137		let info = DispatchInfo { call_weight: Weight::zero(), ..Default::default() };
138		let call: T::RuntimeCall = frame_system::Call::remark { remark: vec![] }.into();
139
140		#[block]
141		{
142			ext.test_run(RawOrigin::Signed(caller).into(), &call, &info, len, 0, |_| Ok(().into()))
143				.unwrap()
144				.unwrap();
145		}
146		Ok(())
147	}
148
149	#[benchmark]
150	fn check_nonce() -> Result<(), BenchmarkError> {
151		let caller: T::AccountId = account("caller", 0, 0);
152		let mut info = frame_system::AccountInfo::default();
153		info.nonce = 1u32.into();
154		info.providers = 1;
155		let expected_nonce = info.nonce + 1u32.into();
156		frame_system::Account::<T>::insert(caller.clone(), info);
157		let len = 0_usize;
158		let ext = CheckNonce::<T>::from(1u32.into());
159		let info = DispatchInfo { call_weight: Weight::zero(), ..Default::default() };
160		let call: T::RuntimeCall = frame_system::Call::remark { remark: vec![] }.into();
161
162		#[block]
163		{
164			ext.test_run(RawOrigin::Signed(caller.clone()).into(), &call, &info, len, 0, |_| {
165				Ok(().into())
166			})
167			.unwrap()
168			.unwrap();
169		}
170
171		let updated_info = frame_system::Account::<T>::get(caller.clone());
172		assert_eq!(updated_info.nonce, expected_nonce);
173		Ok(())
174	}
175
176	#[benchmark]
177	fn check_spec_version() -> Result<(), BenchmarkError> {
178		let len = 0_usize;
179		let caller = account("caller", 0, 0);
180		let info = DispatchInfo { call_weight: Weight::zero(), ..Default::default() };
181		let call: T::RuntimeCall = frame_system::Call::remark { remark: vec![] }.into();
182
183		#[block]
184		{
185			CheckSpecVersion::<T>::new()
186				.test_run(RawOrigin::Signed(caller).into(), &call, &info, len, 0, |_| Ok(().into()))
187				.unwrap()
188				.unwrap();
189		}
190		Ok(())
191	}
192
193	#[benchmark]
194	fn check_tx_version() -> Result<(), BenchmarkError> {
195		let len = 0_usize;
196		let caller = account("caller", 0, 0);
197		let info = DispatchInfo { call_weight: Weight::zero(), ..Default::default() };
198		let call: T::RuntimeCall = frame_system::Call::remark { remark: vec![] }.into();
199
200		#[block]
201		{
202			CheckTxVersion::<T>::new()
203				.test_run(RawOrigin::Signed(caller).into(), &call, &info, len, 0, |_| Ok(().into()))
204				.unwrap()
205				.unwrap();
206		}
207		Ok(())
208	}
209
210	#[benchmark]
211	fn check_weight() -> Result<(), BenchmarkError> {
212		let caller = account("caller", 0, 0);
213		let base_extrinsic = <T as frame_system::Config>::BlockWeights::get()
214			.get(DispatchClass::Normal)
215			.base_extrinsic;
216		let extension_weight = <T as frame_system::Config>::ExtensionsWeightInfo::check_weight();
217		let info = DispatchInfo {
218			call_weight: Weight::from_parts(base_extrinsic.ref_time() * 5, 0),
219			extension_weight,
220			class: DispatchClass::Normal,
221			..Default::default()
222		};
223		let call: T::RuntimeCall = frame_system::Call::remark { remark: vec![] }.into();
224		let post_info = PostDispatchInfo {
225			actual_weight: Some(Weight::from_parts(base_extrinsic.ref_time() * 2, 0)),
226			pays_fee: Default::default(),
227		};
228		let len = 0_usize;
229		let base_extrinsic = <T as frame_system::Config>::BlockWeights::get()
230			.get(DispatchClass::Normal)
231			.base_extrinsic;
232
233		let ext = CheckWeight::<T>::new();
234
235		let initial_block_weight = Weight::from_parts(base_extrinsic.ref_time() * 2, 0);
236		frame_system::BlockWeight::<T>::mutate(|current_weight| {
237			current_weight.set(Weight::zero(), DispatchClass::Mandatory);
238			current_weight.set(initial_block_weight, DispatchClass::Normal);
239		});
240
241		#[block]
242		{
243			ext.test_run(RawOrigin::Signed(caller).into(), &call, &info, len, 0, |_| Ok(post_info))
244				.unwrap()
245				.unwrap();
246		}
247
248		assert_eq!(
249			System::<T>::block_weight().total(),
250			initial_block_weight +
251				base_extrinsic +
252				post_info.actual_weight.unwrap().saturating_add(extension_weight),
253		);
254		Ok(())
255	}
256
257	#[benchmark]
258	fn weight_reclaim() -> Result<(), BenchmarkError> {
259		let caller = account("caller", 0, 0);
260		let base_extrinsic = <T as frame_system::Config>::BlockWeights::get()
261			.get(DispatchClass::Normal)
262			.base_extrinsic;
263		let extension_weight = <T as frame_system::Config>::ExtensionsWeightInfo::weight_reclaim();
264		let info = DispatchInfo {
265			call_weight: Weight::from_parts(base_extrinsic.ref_time() * 5, 0),
266			extension_weight,
267			class: DispatchClass::Normal,
268			..Default::default()
269		};
270		let call: T::RuntimeCall = frame_system::Call::remark { remark: vec![] }.into();
271		let post_info = PostDispatchInfo {
272			actual_weight: Some(Weight::from_parts(base_extrinsic.ref_time() * 2, 0)),
273			pays_fee: Default::default(),
274		};
275		let len = 0_usize;
276		let ext = WeightReclaim::<T>::new();
277
278		let initial_block_weight = Weight::from_parts(base_extrinsic.ref_time() * 2, 0);
279		frame_system::BlockWeight::<T>::mutate(|current_weight| {
280			current_weight.set(Weight::zero(), DispatchClass::Mandatory);
281			current_weight.set(initial_block_weight, DispatchClass::Normal);
282			current_weight.accrue(base_extrinsic + info.total_weight(), DispatchClass::Normal);
283		});
284
285		#[block]
286		{
287			ext.test_run(RawOrigin::Signed(caller).into(), &call, &info, len, 0, |_| Ok(post_info))
288				.unwrap()
289				.unwrap();
290		}
291
292		assert_eq!(
293			System::<T>::block_weight().total(),
294			initial_block_weight +
295				base_extrinsic +
296				post_info.actual_weight.unwrap().saturating_add(extension_weight),
297		);
298		Ok(())
299	}
300
301	impl_benchmark_test_suite!(Pallet, crate::mock::new_test_ext(), crate::mock::Test,);
302}