frame_system_benchmarking/
extensions.rs1#![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}