1#![cfg(feature = "runtime-benchmarks")]
20
21mod call_builder;
22mod code;
23mod sandbox;
24use self::{
25 call_builder::CallSetup,
26 code::{body, ImportedMemory, Location, ModuleDefinition, WasmModule},
27 sandbox::Sandbox,
28};
29use crate::{
30 exec::{Key, SeedOf},
31 migration::{
32 codegen::LATEST_MIGRATION_VERSION, v09, v10, v11, v12, v13, v14, v15, v16, MigrationStep,
33 },
34 storage::WriteOutcome,
35 wasm::BenchEnv,
36 Pallet as Contracts, *,
37};
38use alloc::{vec, vec::Vec};
39use codec::{Encode, MaxEncodedLen};
40use frame_benchmarking::v2::*;
41use frame_support::{
42 self, assert_ok,
43 pallet_prelude::StorageVersion,
44 storage::child,
45 traits::{fungible::InspectHold, Currency},
46 weights::{Weight, WeightMeter},
47};
48use frame_system::RawOrigin;
49use pallet_balances;
50use pallet_contracts_uapi::{CallFlags, ReturnErrorCode};
51use sp_runtime::traits::{Bounded, Hash};
52use wasm_instrument::parity_wasm::elements::{Instruction, Local, ValueType};
53
54const API_BENCHMARK_RUNS: u32 = 1600;
60
61const INSTR_BENCHMARK_RUNS: u32 = 5000;
66
67const UNBALANCED_TRIE_LAYERS: u32 = 20;
69
70#[derive(Clone)]
72struct Contract<T: Config> {
73 caller: T::AccountId,
74 account_id: T::AccountId,
75 addr: AccountIdLookupOf<T>,
76 value: BalanceOf<T>,
77}
78
79impl<T> Contract<T>
80where
81 T: Config + pallet_balances::Config,
82 <BalanceOf<T> as HasCompact>::Type: Clone + Eq + PartialEq + Debug + TypeInfo + Encode,
83{
84 fn new(module: WasmModule<T>, data: Vec<u8>) -> Result<Contract<T>, &'static str> {
86 Self::with_index(0, module, data)
87 }
88
89 fn with_index(
91 index: u32,
92 module: WasmModule<T>,
93 data: Vec<u8>,
94 ) -> Result<Contract<T>, &'static str> {
95 Self::with_caller(account("instantiator", index, 0), module, data)
96 }
97
98 fn with_caller(
100 caller: T::AccountId,
101 module: WasmModule<T>,
102 data: Vec<u8>,
103 ) -> Result<Contract<T>, &'static str> {
104 let value = Pallet::<T>::min_balance();
105 T::Currency::set_balance(&caller, caller_funding::<T>());
106 let salt = vec![0xff];
107 let addr = Contracts::<T>::contract_address(&caller, &module.hash, &data, &salt);
108
109 Contracts::<T>::store_code_raw(module.code, caller.clone())?;
110 Contracts::<T>::instantiate(
111 RawOrigin::Signed(caller.clone()).into(),
112 value,
113 Weight::MAX,
114 None,
115 module.hash,
116 data,
117 salt,
118 )?;
119
120 let result =
121 Contract { caller, account_id: addr.clone(), addr: T::Lookup::unlookup(addr), value };
122
123 ContractInfoOf::<T>::insert(&result.account_id, result.info()?);
124
125 Ok(result)
126 }
127
128 fn with_storage(
130 code: WasmModule<T>,
131 stor_num: u32,
132 stor_size: u32,
133 ) -> Result<Self, &'static str> {
134 let contract = Contract::<T>::new(code, vec![])?;
135 let storage_items = (0..stor_num)
136 .map(|i| {
137 let hash = T::Hashing::hash_of(&i)
138 .as_ref()
139 .try_into()
140 .map_err(|_| "Hash too big for storage key")?;
141 Ok((hash, vec![42u8; stor_size as usize]))
142 })
143 .collect::<Result<Vec<_>, &'static str>>()?;
144 contract.store(&storage_items)?;
145 Ok(contract)
146 }
147
148 fn store(&self, items: &Vec<([u8; 32], Vec<u8>)>) -> Result<(), &'static str> {
150 let info = self.info()?;
151 for item in items {
152 info.write(&Key::Fix(item.0), Some(item.1.clone()), None, false)
153 .map_err(|_| "Failed to write storage to restoration dest")?;
154 }
155 <ContractInfoOf<T>>::insert(&self.account_id, info);
156 Ok(())
157 }
158
159 fn with_unbalanced_storage_trie(code: WasmModule<T>, key: &[u8]) -> Result<Self, &'static str> {
161 if (key.len() as u32) < UNBALANCED_TRIE_LAYERS.div_ceil(2) {
162 return Err("Key size too small to create the specified trie");
163 }
164
165 let value = vec![16u8; T::Schedule::get().limits.payload_len as usize];
166 let contract = Contract::<T>::new(code, vec![])?;
167 let info = contract.info()?;
168 let child_trie_info = info.child_trie_info();
169 child::put_raw(&child_trie_info, &key, &value);
170 for l in 0..UNBALANCED_TRIE_LAYERS {
171 let pos = l as usize / 2;
172 let mut key_new = key.to_vec();
173 for i in 0u8..16 {
174 key_new[pos] = if l % 2 == 0 {
175 (key_new[pos] & 0xF0) | i
176 } else {
177 (key_new[pos] & 0x0F) | (i << 4)
178 };
179
180 if key == &key_new {
181 continue
182 }
183 child::put_raw(&child_trie_info, &key_new, &value);
184 }
185 }
186 Ok(contract)
187 }
188
189 fn address_info(addr: &T::AccountId) -> Result<ContractInfo<T>, &'static str> {
191 ContractInfoOf::<T>::get(addr).ok_or("Expected contract to exist at this point.")
192 }
193
194 fn info(&self) -> Result<ContractInfo<T>, &'static str> {
196 Self::address_info(&self.account_id)
197 }
198
199 fn set_balance(&self, balance: BalanceOf<T>) {
201 T::Currency::set_balance(&self.account_id, balance);
202 }
203
204 fn code_exists(hash: &CodeHash<T>) -> bool {
206 <PristineCode<T>>::contains_key(hash) && <CodeInfoOf<T>>::contains_key(&hash)
207 }
208
209 fn code_removed(hash: &CodeHash<T>) -> bool {
211 !<PristineCode<T>>::contains_key(hash) && !<CodeInfoOf<T>>::contains_key(&hash)
212 }
213}
214
215fn caller_funding<T: Config>() -> BalanceOf<T> {
217 BalanceOf::<T>::max_value() / 10_000u32.into()
220}
221
222#[benchmarks(
223 where
224 <BalanceOf<T> as codec::HasCompact>::Type: Clone + Eq + PartialEq + core::fmt::Debug + scale_info::TypeInfo + codec::Encode,
225 T: Config + pallet_balances::Config,
226 BalanceOf<T>: From<<pallet_balances::Pallet<T> as Currency<T::AccountId>>::Balance>,
227 <pallet_balances::Pallet<T> as Currency<T::AccountId>>::Balance: From<BalanceOf<T>>,
228)]
229mod benchmarks {
230 use super::*;
231
232 #[benchmark(pov_mode = Measured)]
234 fn on_process_deletion_queue_batch() {
235 #[block]
236 {
237 ContractInfo::<T>::process_deletion_queue_batch(&mut WeightMeter::new())
238 }
239 }
240
241 #[benchmark(skip_meta, pov_mode = Measured)]
242 fn on_initialize_per_trie_key(k: Linear<0, 1024>) -> Result<(), BenchmarkError> {
243 let instance = Contract::<T>::with_storage(
244 WasmModule::dummy(),
245 k,
246 T::Schedule::get().limits.payload_len,
247 )?;
248 instance.info()?.queue_trie_for_deletion();
249
250 #[block]
251 {
252 ContractInfo::<T>::process_deletion_queue_batch(&mut WeightMeter::new())
253 }
254
255 Ok(())
256 }
257
258 #[benchmark(pov_mode = Measured)]
260 fn v9_migration_step(c: Linear<0, { T::MaxCodeLen::get() }>) {
261 v09::store_old_dummy_code::<T>(c as usize);
262 let mut m = v09::Migration::<T>::default();
263 #[block]
264 {
265 m.step(&mut WeightMeter::new());
266 }
267 }
268
269 #[benchmark(pov_mode = Measured)]
271 fn v10_migration_step() -> Result<(), BenchmarkError> {
272 let contract =
273 <Contract<T>>::with_caller(whitelisted_caller(), WasmModule::dummy(), vec![])?;
274
275 v10::store_old_contract_info::<T, pallet_balances::Pallet<T>>(
276 contract.account_id.clone(),
277 contract.info()?,
278 );
279 let mut m = v10::Migration::<T, pallet_balances::Pallet<T>>::default();
280
281 #[block]
282 {
283 m.step(&mut WeightMeter::new());
284 }
285
286 Ok(())
287 }
288
289 #[benchmark(pov_mode = Measured)]
292 fn v11_migration_step(k: Linear<0, 1024>) {
293 v11::fill_old_queue::<T>(k as usize);
294 let mut m = v11::Migration::<T>::default();
295
296 #[block]
297 {
298 m.step(&mut WeightMeter::new());
299 }
300 }
301
302 #[benchmark(pov_mode = Measured)]
306 fn v12_migration_step(c: Linear<0, { T::MaxCodeLen::get() }>) {
307 v12::store_old_dummy_code::<T, pallet_balances::Pallet<T>>(
308 c as usize,
309 account::<T::AccountId>("account", 0, 0),
310 );
311 let mut m = v12::Migration::<T, pallet_balances::Pallet<T>>::default();
312
313 #[block]
314 {
315 m.step(&mut WeightMeter::new());
316 }
317 }
318
319 #[benchmark(pov_mode = Measured)]
321 fn v13_migration_step() -> Result<(), BenchmarkError> {
322 let contract =
323 <Contract<T>>::with_caller(whitelisted_caller(), WasmModule::dummy(), vec![])?;
324
325 v13::store_old_contract_info::<T>(contract.account_id.clone(), contract.info()?);
326 let mut m = v13::Migration::<T>::default();
327
328 #[block]
329 {
330 m.step(&mut WeightMeter::new());
331 }
332 Ok(())
333 }
334
335 #[benchmark(pov_mode = Measured)]
338 fn v14_migration_step() {
339 let account = account::<T::AccountId>("account", 0, 0);
340 T::Currency::set_balance(&account, caller_funding::<T>());
341 v14::store_dummy_code::<T, pallet_balances::Pallet<T>>(account);
342 let mut m = v14::Migration::<T, pallet_balances::Pallet<T>>::default();
343
344 #[block]
345 {
346 m.step(&mut WeightMeter::new());
347 }
348 }
349
350 #[benchmark(pov_mode = Measured)]
352 fn v15_migration_step() -> Result<(), BenchmarkError> {
353 let contract =
354 <Contract<T>>::with_caller(whitelisted_caller(), WasmModule::dummy(), vec![])?;
355
356 v15::store_old_contract_info::<T>(contract.account_id.clone(), contract.info()?);
357 let mut m = v15::Migration::<T>::default();
358
359 #[block]
360 {
361 m.step(&mut WeightMeter::new());
362 }
363
364 Ok(())
365 }
366
367 #[benchmark(pov_mode = Measured)]
369 fn v16_migration_step() -> Result<(), BenchmarkError> {
370 let contract =
371 <Contract<T>>::with_caller(whitelisted_caller(), WasmModule::dummy(), vec![])?;
372
373 let info = contract.info()?;
374 let base_deposit = v16::store_old_contract_info::<T>(contract.account_id.clone(), &info);
375 let mut m = v16::Migration::<T>::default();
376
377 #[block]
378 {
379 m.step(&mut WeightMeter::new());
380 }
381 let ed = Pallet::<T>::min_balance();
382 let info = v16::ContractInfoOf::<T>::get(&contract.account_id).unwrap();
383 assert_eq!(info.storage_base_deposit, base_deposit - ed);
384 Ok(())
385 }
386
387 #[benchmark(pov_mode = Measured)]
389 fn migration_noop() {
390 let version = LATEST_MIGRATION_VERSION;
391 StorageVersion::new(version).put::<Pallet<T>>();
392 #[block]
393 {
394 Migration::<T>::migrate(&mut WeightMeter::new());
395 }
396 assert_eq!(StorageVersion::get::<Pallet<T>>(), version);
397 }
398
399 #[benchmark(pov_mode = Measured)]
401 fn migrate() {
402 let latest_version = LATEST_MIGRATION_VERSION;
403 StorageVersion::new(latest_version - 2).put::<Pallet<T>>();
404 <Migration<T, false> as frame_support::traits::OnRuntimeUpgrade>::on_runtime_upgrade();
405
406 #[extrinsic_call]
407 _(RawOrigin::Signed(whitelisted_caller()), Weight::MAX);
408
409 assert_eq!(StorageVersion::get::<Pallet<T>>(), latest_version - 1);
410 }
411
412 #[benchmark(pov_mode = Measured)]
415 fn on_runtime_upgrade_noop() {
416 let latest_version = LATEST_MIGRATION_VERSION;
417 StorageVersion::new(latest_version).put::<Pallet<T>>();
418 #[block]
419 {
420 <Migration<T, false> as frame_support::traits::OnRuntimeUpgrade>::on_runtime_upgrade();
421 }
422 assert!(MigrationInProgress::<T>::get().is_none());
423 }
424
425 #[benchmark(pov_mode = Measured)]
428 fn on_runtime_upgrade_in_progress() {
429 let latest_version = LATEST_MIGRATION_VERSION;
430 StorageVersion::new(latest_version - 2).put::<Pallet<T>>();
431 let v = vec![42u8].try_into().ok();
432 MigrationInProgress::<T>::set(v.clone());
433 #[block]
434 {
435 <Migration<T, false> as frame_support::traits::OnRuntimeUpgrade>::on_runtime_upgrade();
436 }
437 assert!(MigrationInProgress::<T>::get().is_some());
438 assert_eq!(MigrationInProgress::<T>::get(), v);
439 }
440
441 #[benchmark(pov_mode = Measured)]
444 fn on_runtime_upgrade() {
445 let latest_version = LATEST_MIGRATION_VERSION;
446 StorageVersion::new(latest_version - 2).put::<Pallet<T>>();
447 #[block]
448 {
449 <Migration<T, false> as frame_support::traits::OnRuntimeUpgrade>::on_runtime_upgrade();
450 }
451 assert!(MigrationInProgress::<T>::get().is_some());
452 }
453
454 #[benchmark(pov_mode = Measured)]
461 fn call_with_code_per_byte(
462 c: Linear<0, { T::MaxCodeLen::get() }>,
463 ) -> Result<(), BenchmarkError> {
464 let instance = Contract::<T>::with_caller(
465 whitelisted_caller(),
466 WasmModule::sized(c, Location::Deploy, false),
467 vec![],
468 )?;
469 let value = Pallet::<T>::min_balance();
470 let callee = instance.addr;
471
472 #[extrinsic_call]
473 call(RawOrigin::Signed(instance.caller.clone()), callee, value, Weight::MAX, None, vec![]);
474
475 Ok(())
476 }
477
478 #[benchmark(pov_mode = Measured)]
482 fn instantiate_with_code(
483 c: Linear<0, { T::MaxCodeLen::get() }>,
484 i: Linear<0, { code::max_pages::<T>() * 64 * 1024 }>,
485 s: Linear<0, { code::max_pages::<T>() * 64 * 1024 }>,
486 ) {
487 let input = vec![42u8; i as usize];
488 let salt = vec![42u8; s as usize];
489 let value = Pallet::<T>::min_balance();
490 let caller = whitelisted_caller();
491 T::Currency::set_balance(&caller, caller_funding::<T>());
492 let WasmModule { code, hash, .. } = WasmModule::<T>::sized(c, Location::Call, false);
493 let origin = RawOrigin::Signed(caller.clone());
494 let addr = Contracts::<T>::contract_address(&caller, &hash, &input, &salt);
495 #[extrinsic_call]
496 _(origin, value, Weight::MAX, None, code, input, salt);
497
498 let deposit =
499 T::Currency::balance_on_hold(&HoldReason::StorageDepositReserve.into(), &addr);
500 let code_deposit =
502 T::Currency::balance_on_hold(&HoldReason::CodeUploadDepositReserve.into(), &caller);
503 assert_eq!(
504 T::Currency::balance(&caller),
505 caller_funding::<T>() - value - deposit - code_deposit - Pallet::<T>::min_balance(),
506 );
507 assert_eq!(T::Currency::balance(&addr), value + Pallet::<T>::min_balance());
509 }
510
511 #[benchmark(pov_mode = Measured)]
514 fn instantiate(
515 i: Linear<0, { code::max_pages::<T>() * 64 * 1024 }>,
516 s: Linear<0, { code::max_pages::<T>() * 64 * 1024 }>,
517 ) -> Result<(), BenchmarkError> {
518 let input = vec![42u8; i as usize];
519 let salt = vec![42u8; s as usize];
520 let value = Pallet::<T>::min_balance();
521 let caller = whitelisted_caller();
522 T::Currency::set_balance(&caller, caller_funding::<T>());
523 let WasmModule { code, hash, .. } = WasmModule::<T>::dummy();
524 let addr = Contracts::<T>::contract_address(&caller, &hash, &input, &salt);
525 Contracts::<T>::store_code_raw(code, caller.clone())?;
526
527 #[extrinsic_call]
528 _(RawOrigin::Signed(caller.clone()), value, Weight::MAX, None, hash, input, salt);
529
530 let deposit =
531 T::Currency::balance_on_hold(&HoldReason::StorageDepositReserve.into(), &addr);
532 assert_eq!(
534 T::Currency::balance(&caller),
535 caller_funding::<T>() - value - deposit - Pallet::<T>::min_balance(),
536 );
537 assert_eq!(T::Currency::balance(&addr), value + Pallet::<T>::min_balance());
539
540 Ok(())
541 }
542
543 #[benchmark(pov_mode = Measured)]
551 fn call() -> Result<(), BenchmarkError> {
552 let data = vec![42u8; 1024];
553 let instance =
554 Contract::<T>::with_caller(whitelisted_caller(), WasmModule::dummy(), vec![])?;
555 let value = Pallet::<T>::min_balance();
556 let origin = RawOrigin::Signed(instance.caller.clone());
557 let callee = instance.addr.clone();
558 let before = T::Currency::balance(&instance.account_id);
559 #[extrinsic_call]
560 _(origin, callee, value, Weight::MAX, None, data);
561 let deposit = T::Currency::balance_on_hold(
562 &HoldReason::StorageDepositReserve.into(),
563 &instance.account_id,
564 );
565 assert_eq!(
567 T::Currency::balance(&instance.caller),
568 caller_funding::<T>() - instance.value - value - deposit - Pallet::<T>::min_balance(),
569 );
570 assert_eq!(T::Currency::balance(&instance.account_id), before + value);
572 instance.info()?;
574
575 Ok(())
576 }
577
578 #[benchmark(pov_mode = Measured)]
582 fn upload_code_determinism_enforced(c: Linear<0, { T::MaxCodeLen::get() }>) {
583 let caller = whitelisted_caller();
584 T::Currency::set_balance(&caller, caller_funding::<T>());
585 let WasmModule { code, hash, .. } = WasmModule::<T>::sized(c, Location::Call, false);
586 let origin = RawOrigin::Signed(caller.clone());
587 #[extrinsic_call]
588 upload_code(origin, code, None, Determinism::Enforced);
589 assert!(T::Currency::total_balance_on_hold(&caller) > 0u32.into());
591 assert!(<Contract<T>>::code_exists(&hash));
592 }
593
594 #[benchmark(pov_mode = Measured)]
598 fn upload_code_determinism_relaxed(c: Linear<0, { T::MaxCodeLen::get() }>) {
599 let caller = whitelisted_caller();
600 T::Currency::set_balance(&caller, caller_funding::<T>());
601 let WasmModule { code, hash, .. } = WasmModule::<T>::sized(c, Location::Call, true);
602 let origin = RawOrigin::Signed(caller.clone());
603 #[extrinsic_call]
604 upload_code(origin, code, None, Determinism::Relaxed);
605 assert!(T::Currency::total_balance_on_hold(&caller) > 0u32.into());
606 assert!(<Contract<T>>::code_exists(&hash));
607 assert_eq!(CodeInfoOf::<T>::get(&hash).unwrap().determinism(), Determinism::Relaxed);
609 }
610
611 #[benchmark(pov_mode = Measured)]
615 fn remove_code() -> Result<(), BenchmarkError> {
616 let caller = whitelisted_caller();
617 T::Currency::set_balance(&caller, caller_funding::<T>());
618 let WasmModule { code, hash, .. } = WasmModule::<T>::dummy();
619 let origin = RawOrigin::Signed(caller.clone());
620 let uploaded =
621 <Contracts<T>>::bare_upload_code(caller.clone(), code, None, Determinism::Enforced)?;
622 assert_eq!(uploaded.code_hash, hash);
623 assert_eq!(uploaded.deposit, T::Currency::total_balance_on_hold(&caller));
624 assert!(<Contract<T>>::code_exists(&hash));
625 #[extrinsic_call]
626 _(origin, hash);
627 assert_eq!(T::Currency::total_balance_on_hold(&caller), 0u32.into());
629 assert!(<Contract<T>>::code_removed(&hash));
630 Ok(())
631 }
632
633 #[benchmark(pov_mode = Measured)]
634 fn set_code() -> Result<(), BenchmarkError> {
635 let instance =
636 <Contract<T>>::with_caller(whitelisted_caller(), WasmModule::dummy(), vec![])?;
637 let WasmModule { code, hash, .. } = <WasmModule<T>>::dummy_with_bytes(128);
639 <Contracts<T>>::store_code_raw(code, instance.caller.clone())?;
640 let callee = instance.addr.clone();
641 assert_ne!(instance.info()?.code_hash, hash);
642 #[extrinsic_call]
643 _(RawOrigin::Root, callee, hash);
644 assert_eq!(instance.info()?.code_hash, hash);
645 Ok(())
646 }
647
648 #[benchmark(pov_mode = Measured)]
649 fn noop_host_fn(r: Linear<0, API_BENCHMARK_RUNS>) {
650 let mut setup = CallSetup::<T>::new(WasmModule::noop(r));
651 let (mut ext, module) = setup.ext();
652 let func = CallSetup::<T>::prepare_call(&mut ext, module, vec![]);
653 #[block]
654 {
655 func.call();
656 }
657 }
658
659 #[benchmark(pov_mode = Measured)]
660 fn seal_caller() {
661 let len = <T::AccountId as MaxEncodedLen>::max_encoded_len() as u32;
662 build_runtime!(runtime, memory: [len.to_le_bytes(), vec![0u8; len as _], ]);
663
664 let result;
665 #[block]
666 {
667 result = BenchEnv::seal0_caller(&mut runtime, &mut memory, 4, 0);
668 }
669
670 assert_ok!(result);
671 assert_eq!(
672 &<T::AccountId as Decode>::decode(&mut &memory[4..]).unwrap(),
673 runtime.ext().caller().account_id().unwrap()
674 );
675 }
676
677 #[benchmark(pov_mode = Measured)]
678 fn seal_is_contract() {
679 let Contract { account_id, .. } =
680 Contract::<T>::with_index(1, WasmModule::dummy(), vec![]).unwrap();
681
682 build_runtime!(runtime, memory: [account_id.encode(), ]);
683
684 let result;
685 #[block]
686 {
687 result = BenchEnv::seal0_is_contract(&mut runtime, &mut memory, 0);
688 }
689
690 assert_eq!(result.unwrap(), 1);
691 }
692
693 #[benchmark(pov_mode = Measured)]
694 fn seal_code_hash() {
695 let contract = Contract::<T>::with_index(1, WasmModule::dummy(), vec![]).unwrap();
696 let len = <CodeHash<T> as MaxEncodedLen>::max_encoded_len() as u32;
697 build_runtime!(runtime, memory: [len.to_le_bytes(), vec![0u8; len as _], contract.account_id.encode(), ]);
698
699 let result;
700 #[block]
701 {
702 result = BenchEnv::seal0_code_hash(&mut runtime, &mut memory, 4 + len, 4, 0);
703 }
704
705 assert_ok!(result);
706 assert_eq!(
707 <CodeHash<T> as Decode>::decode(&mut &memory[4..]).unwrap(),
708 contract.info().unwrap().code_hash
709 );
710 }
711
712 #[benchmark(pov_mode = Measured)]
713 fn seal_own_code_hash() {
714 let len = <CodeHash<T> as MaxEncodedLen>::max_encoded_len() as u32;
715 build_runtime!(runtime, contract, memory: [len.to_le_bytes(), vec![0u8; len as _], ]);
716 let result;
717 #[block]
718 {
719 result = BenchEnv::seal0_own_code_hash(&mut runtime, &mut memory, 4, 0);
720 }
721
722 assert_ok!(result);
723 assert_eq!(
724 <CodeHash<T> as Decode>::decode(&mut &memory[4..]).unwrap(),
725 contract.info().unwrap().code_hash
726 );
727 }
728
729 #[benchmark(pov_mode = Measured)]
730 fn seal_caller_is_origin() {
731 build_runtime!(runtime, memory: []);
732
733 let result;
734 #[block]
735 {
736 result = BenchEnv::seal0_caller_is_origin(&mut runtime, &mut memory);
737 }
738 assert_eq!(result.unwrap(), 1u32);
739 }
740
741 #[benchmark(pov_mode = Measured)]
742 fn seal_caller_is_root() {
743 let mut setup = CallSetup::<T>::default();
744 setup.set_origin(Origin::Root);
745 let (mut ext, _) = setup.ext();
746 let mut runtime = crate::wasm::Runtime::new(&mut ext, vec![]);
747
748 let result;
749 #[block]
750 {
751 result = BenchEnv::seal0_caller_is_root(&mut runtime, &mut [0u8; 0]);
752 }
753 assert_eq!(result.unwrap(), 1u32);
754 }
755
756 #[benchmark(pov_mode = Measured)]
757 fn seal_address() {
758 let len = <AccountIdOf<T> as MaxEncodedLen>::max_encoded_len() as u32;
759 build_runtime!(runtime, memory: [len.to_le_bytes(), vec![0u8; len as _], ]);
760
761 let result;
762 #[block]
763 {
764 result = BenchEnv::seal0_address(&mut runtime, &mut memory, 4, 0);
765 }
766 assert_ok!(result);
767 assert_eq!(
768 &<T::AccountId as Decode>::decode(&mut &memory[4..]).unwrap(),
769 runtime.ext().address()
770 );
771 }
772
773 #[benchmark(pov_mode = Measured)]
774 fn seal_gas_left() {
775 let len = 18u32;
777 assert!(<Weight as MaxEncodedLen>::max_encoded_len() as u32 != len);
778 build_runtime!(runtime, memory: [32u32.to_le_bytes(), vec![0u8; len as _], ]);
779
780 let result;
781 #[block]
782 {
783 result = BenchEnv::seal1_gas_left(&mut runtime, &mut memory, 4, 0);
784 }
785 assert_ok!(result);
786 assert_eq!(
787 <Weight as Decode>::decode(&mut &memory[4..]).unwrap(),
788 runtime.ext().gas_meter().gas_left()
789 );
790 }
791
792 #[benchmark(pov_mode = Measured)]
793 fn seal_balance() {
794 let len = <T::Balance as MaxEncodedLen>::max_encoded_len() as u32;
795 build_runtime!(runtime, memory: [len.to_le_bytes(), vec![0u8; len as _], ]);
796 let result;
797 #[block]
798 {
799 result = BenchEnv::seal0_seal_balance(&mut runtime, &mut memory, 4, 0);
800 }
801 assert_ok!(result);
802 assert_eq!(
803 <T::Balance as Decode>::decode(&mut &memory[4..]).unwrap(),
804 runtime.ext().balance().into()
805 );
806 }
807
808 #[benchmark(pov_mode = Measured)]
809 fn seal_value_transferred() {
810 let len = <T::Balance as MaxEncodedLen>::max_encoded_len() as u32;
811 build_runtime!(runtime, memory: [len.to_le_bytes(), vec![0u8; len as _], ]);
812 let result;
813 #[block]
814 {
815 result = BenchEnv::seal0_value_transferred(&mut runtime, &mut memory, 4, 0);
816 }
817 assert_ok!(result);
818 assert_eq!(
819 <T::Balance as Decode>::decode(&mut &memory[4..]).unwrap(),
820 runtime.ext().value_transferred().into()
821 );
822 }
823
824 #[benchmark(pov_mode = Measured)]
825 fn seal_minimum_balance() {
826 let len = <T::Balance as MaxEncodedLen>::max_encoded_len() as u32;
827 build_runtime!(runtime, memory: [len.to_le_bytes(), vec![0u8; len as _], ]);
828 let result;
829 #[block]
830 {
831 result = BenchEnv::seal0_minimum_balance(&mut runtime, &mut memory, 4, 0);
832 }
833 assert_ok!(result);
834 assert_eq!(
835 <T::Balance as Decode>::decode(&mut &memory[4..]).unwrap(),
836 runtime.ext().minimum_balance().into()
837 );
838 }
839
840 #[benchmark(pov_mode = Measured)]
841 fn seal_block_number() {
842 let len = <BlockNumberFor<T> as MaxEncodedLen>::max_encoded_len() as u32;
843 build_runtime!(runtime, memory: [len.to_le_bytes(), vec![0u8; len as _], ]);
844 let result;
845 #[block]
846 {
847 result = BenchEnv::seal0_seal_block_number(&mut runtime, &mut memory, 4, 0);
848 }
849 assert_ok!(result);
850 assert_eq!(
851 <BlockNumberFor<T>>::decode(&mut &memory[4..]).unwrap(),
852 runtime.ext().block_number()
853 );
854 }
855
856 #[benchmark(pov_mode = Measured)]
857 fn seal_now() {
858 let len = <MomentOf<T> as MaxEncodedLen>::max_encoded_len() as u32;
859 build_runtime!(runtime, memory: [len.to_le_bytes(), vec![0u8; len as _], ]);
860 let result;
861 #[block]
862 {
863 result = BenchEnv::seal0_seal_now(&mut runtime, &mut memory, 4, 0);
864 }
865 assert_ok!(result);
866 assert_eq!(<MomentOf<T>>::decode(&mut &memory[4..]).unwrap(), *runtime.ext().now());
867 }
868
869 #[benchmark(pov_mode = Measured)]
870 fn seal_weight_to_fee() {
871 let len = <T::Balance as MaxEncodedLen>::max_encoded_len() as u32;
872 build_runtime!(runtime, memory: [len.to_le_bytes(), vec![0u8; len as _], ]);
873 let weight = Weight::from_parts(500_000, 300_000);
874 let result;
875 #[block]
876 {
877 result = BenchEnv::seal1_weight_to_fee(
878 &mut runtime,
879 &mut memory,
880 weight.ref_time(),
881 weight.proof_size(),
882 4,
883 0,
884 );
885 }
886 assert_ok!(result);
887 assert_eq!(
888 <BalanceOf<T>>::decode(&mut &memory[4..]).unwrap(),
889 runtime.ext().get_weight_price(weight)
890 );
891 }
892
893 #[benchmark(pov_mode = Measured)]
894 fn seal_input(n: Linear<0, { code::max_pages::<T>() * 64 * 1024 - 4 }>) {
895 let mut setup = CallSetup::<T>::default();
896 let (mut ext, _) = setup.ext();
897 let mut runtime = crate::wasm::Runtime::new(&mut ext, vec![42u8; n as usize]);
898 let mut memory = memory!(n.to_le_bytes(), vec![0u8; n as usize],);
899 let result;
900 #[block]
901 {
902 result = BenchEnv::seal0_input(&mut runtime, &mut memory, 4, 0);
903 }
904 assert_ok!(result);
905 assert_eq!(&memory[4..], &vec![42u8; n as usize]);
906 }
907
908 #[benchmark(pov_mode = Measured)]
909 fn seal_return(n: Linear<0, { code::max_pages::<T>() * 64 * 1024 - 4 }>) {
910 build_runtime!(runtime, memory: [n.to_le_bytes(), vec![42u8; n as usize], ]);
911
912 let result;
913 #[block]
914 {
915 result = BenchEnv::seal0_seal_return(&mut runtime, &mut memory, 0, 0, n);
916 }
917
918 assert!(matches!(
919 result,
920 Err(crate::wasm::TrapReason::Return(crate::wasm::ReturnData { .. }))
921 ));
922 }
923
924 #[benchmark(pov_mode = Measured)]
925 fn seal_terminate(
926 n: Linear<0, { T::MaxDelegateDependencies::get() }>,
927 ) -> Result<(), BenchmarkError> {
928 let beneficiary = account::<T::AccountId>("beneficiary", 0, 0);
929 let caller = whitelisted_caller();
930
931 build_runtime!(runtime, memory: [beneficiary.encode(),]);
932
933 T::Currency::set_balance(&caller, caller_funding::<T>());
934
935 (0..n).for_each(|i| {
936 let new_code = WasmModule::<T>::dummy_with_bytes(65 + i);
937 Contracts::<T>::store_code_raw(new_code.code, caller.clone()).unwrap();
938 runtime.ext().lock_delegate_dependency(new_code.hash).unwrap();
939 });
940
941 let result;
942 #[block]
943 {
944 result = BenchEnv::seal1_terminate(&mut runtime, &mut memory, 0);
945 }
946
947 assert!(matches!(result, Err(crate::wasm::TrapReason::Termination)));
948
949 Ok(())
950 }
951
952 #[benchmark(pov_mode = Measured)]
956 fn seal_random() {
957 let subject_len = T::Schedule::get().limits.subject_len;
958 assert!(subject_len < 1024);
959
960 let output_len =
961 <(SeedOf<T>, BlockNumberFor<T>) as MaxEncodedLen>::max_encoded_len() as u32;
962
963 build_runtime!(runtime, memory: [
964 output_len.to_le_bytes(),
965 vec![42u8; subject_len as _],
966 vec![0u8; output_len as _],
967 ]);
968
969 let result;
970 #[block]
971 {
972 result = BenchEnv::seal0_random(
973 &mut runtime,
974 &mut memory,
975 4, subject_len, subject_len + 4, 0, );
980 }
981
982 assert_ok!(result);
983 assert_ok!(<(SeedOf<T>, BlockNumberFor<T>)>::decode(&mut &memory[subject_len as _..]));
984 }
985
986 #[benchmark(pov_mode = Measured)]
990 fn seal_deposit_event(
991 t: Linear<0, { T::Schedule::get().limits.event_topics }>,
992 n: Linear<0, { T::Schedule::get().limits.payload_len }>,
993 ) {
994 let topics = (0..t).map(|i| T::Hashing::hash_of(&i)).collect::<Vec<_>>().encode();
995 let topics_len = topics.len() as u32;
996
997 build_runtime!(runtime, memory: [
998 n.to_le_bytes(),
999 topics,
1000 vec![0u8; n as _],
1001 ]);
1002
1003 let result;
1004 #[block]
1005 {
1006 result = BenchEnv::seal0_deposit_event(
1007 &mut runtime,
1008 &mut memory,
1009 4, topics_len, 4 + topics_len, 0, );
1014 }
1015
1016 assert_ok!(result);
1017 }
1018
1019 #[benchmark]
1026 fn seal_debug_message(
1027 i: Linear<
1028 0,
1029 {
1030 (T::Schedule::get().limits.memory_pages * 64 * 1024)
1031 .min(T::MaxDebugBufferLen::get())
1032 },
1033 >,
1034 ) {
1035 let mut setup = CallSetup::<T>::default();
1036 setup.enable_debug_message();
1037 let (mut ext, _) = setup.ext();
1038 let mut runtime = crate::wasm::Runtime::new(&mut ext, vec![]);
1039 let mut memory = (0..i).zip((32..127).cycle()).map(|i| i.1).collect::<Vec<_>>();
1041
1042 let result;
1043 #[block]
1044 {
1045 result = BenchEnv::seal0_debug_message(&mut runtime, &mut memory, 0, i);
1046 }
1047 assert_ok!(result);
1048 assert_eq!(setup.debug_message().unwrap().len() as u32, i);
1049 }
1050
1051 #[benchmark(skip_meta, pov_mode = Measured)]
1052 fn get_storage_empty() -> Result<(), BenchmarkError> {
1053 let max_key_len = T::MaxStorageKeyLen::get();
1054 let key = vec![0u8; max_key_len as usize];
1055 let max_value_len = T::Schedule::get().limits.payload_len as usize;
1056 let value = vec![1u8; max_value_len];
1057
1058 let instance = Contract::<T>::new(WasmModule::dummy(), vec![])?;
1059 let info = instance.info()?;
1060 let child_trie_info = info.child_trie_info();
1061 info.bench_write_raw(&key, Some(value.clone()), false)
1062 .map_err(|_| "Failed to write to storage during setup.")?;
1063
1064 let result;
1065 #[block]
1066 {
1067 result = child::get_raw(&child_trie_info, &key);
1068 }
1069
1070 assert_eq!(result, Some(value));
1071 Ok(())
1072 }
1073
1074 #[benchmark(skip_meta, pov_mode = Measured)]
1075 fn get_storage_full() -> Result<(), BenchmarkError> {
1076 let max_key_len = T::MaxStorageKeyLen::get();
1077 let key = vec![0u8; max_key_len as usize];
1078 let max_value_len = T::Schedule::get().limits.payload_len;
1079 let value = vec![1u8; max_value_len as usize];
1080
1081 let instance = Contract::<T>::with_unbalanced_storage_trie(WasmModule::dummy(), &key)?;
1082 let info = instance.info()?;
1083 let child_trie_info = info.child_trie_info();
1084 info.bench_write_raw(&key, Some(value.clone()), false)
1085 .map_err(|_| "Failed to write to storage during setup.")?;
1086
1087 let result;
1088 #[block]
1089 {
1090 result = child::get_raw(&child_trie_info, &key);
1091 }
1092
1093 assert_eq!(result, Some(value));
1094 Ok(())
1095 }
1096
1097 #[benchmark(skip_meta, pov_mode = Measured)]
1098 fn set_storage_empty() -> Result<(), BenchmarkError> {
1099 let max_key_len = T::MaxStorageKeyLen::get();
1100 let key = vec![0u8; max_key_len as usize];
1101 let max_value_len = T::Schedule::get().limits.payload_len as usize;
1102 let value = vec![1u8; max_value_len];
1103
1104 let instance = Contract::<T>::new(WasmModule::dummy(), vec![])?;
1105 let info = instance.info()?;
1106 let child_trie_info = info.child_trie_info();
1107 info.bench_write_raw(&key, Some(vec![42u8; max_value_len]), false)
1108 .map_err(|_| "Failed to write to storage during setup.")?;
1109
1110 let val = Some(value.clone());
1111 let result;
1112 #[block]
1113 {
1114 result = info.bench_write_raw(&key, val, true);
1115 }
1116
1117 assert_ok!(result);
1118 assert_eq!(child::get_raw(&child_trie_info, &key).unwrap(), value);
1119 Ok(())
1120 }
1121
1122 #[benchmark(skip_meta, pov_mode = Measured)]
1123 fn set_storage_full() -> Result<(), BenchmarkError> {
1124 let max_key_len = T::MaxStorageKeyLen::get();
1125 let key = vec![0u8; max_key_len as usize];
1126 let max_value_len = T::Schedule::get().limits.payload_len;
1127 let value = vec![1u8; max_value_len as usize];
1128
1129 let instance = Contract::<T>::with_unbalanced_storage_trie(WasmModule::dummy(), &key)?;
1130 let info = instance.info()?;
1131 let child_trie_info = info.child_trie_info();
1132 info.bench_write_raw(&key, Some(vec![42u8; max_value_len as usize]), false)
1133 .map_err(|_| "Failed to write to storage during setup.")?;
1134
1135 let val = Some(value.clone());
1136 let result;
1137 #[block]
1138 {
1139 result = info.bench_write_raw(&key, val, true);
1140 }
1141
1142 assert_ok!(result);
1143 assert_eq!(child::get_raw(&child_trie_info, &key).unwrap(), value);
1144 Ok(())
1145 }
1146
1147 #[benchmark(skip_meta, pov_mode = Measured)]
1150 fn seal_set_storage(
1151 n: Linear<0, { T::Schedule::get().limits.payload_len }>,
1152 o: Linear<0, { T::Schedule::get().limits.payload_len }>,
1153 ) -> Result<(), BenchmarkError> {
1154 let max_key_len = T::MaxStorageKeyLen::get();
1155 let key = Key::<T>::try_from_var(vec![0u8; max_key_len as usize])
1156 .map_err(|_| "Key has wrong length")?;
1157 let value = vec![1u8; n as usize];
1158
1159 build_runtime!(runtime, instance, memory: [ key.to_vec(), value.clone(), ]);
1160 let info = instance.info()?;
1161
1162 info.write(&key, Some(vec![42u8; o as usize]), None, false)
1163 .map_err(|_| "Failed to write to storage during setup.")?;
1164
1165 let result;
1166 #[block]
1167 {
1168 result = BenchEnv::seal2_set_storage(
1169 &mut runtime,
1170 &mut memory,
1171 0, max_key_len, max_key_len, n, );
1176 }
1177
1178 assert_ok!(result);
1179 assert_eq!(info.read(&key).unwrap(), value);
1180 Ok(())
1181 }
1182
1183 #[benchmark(skip_meta, pov_mode = Measured)]
1184 fn seal_clear_storage(
1185 n: Linear<0, { T::Schedule::get().limits.payload_len }>,
1186 ) -> Result<(), BenchmarkError> {
1187 let max_key_len = T::MaxStorageKeyLen::get();
1188 let key = Key::<T>::try_from_var(vec![0u8; max_key_len as usize])
1189 .map_err(|_| "Key has wrong length")?;
1190 build_runtime!(runtime, instance, memory: [ key.to_vec(), ]);
1191 let info = instance.info()?;
1192
1193 info.write(&key, Some(vec![42u8; n as usize]), None, false)
1194 .map_err(|_| "Failed to write to storage during setup.")?;
1195
1196 let result;
1197 #[block]
1198 {
1199 result = BenchEnv::seal1_clear_storage(&mut runtime, &mut memory, 0, max_key_len);
1200 }
1201
1202 assert_ok!(result);
1203 assert!(info.read(&key).is_none());
1204 Ok(())
1205 }
1206
1207 #[benchmark(skip_meta, pov_mode = Measured)]
1208 fn seal_get_storage(
1209 n: Linear<0, { T::Schedule::get().limits.payload_len }>,
1210 ) -> Result<(), BenchmarkError> {
1211 let max_key_len = T::MaxStorageKeyLen::get();
1212 let key = Key::<T>::try_from_var(vec![0u8; max_key_len as usize])
1213 .map_err(|_| "Key has wrong length")?;
1214 build_runtime!(runtime, instance, memory: [ key.to_vec(), n.to_le_bytes(), vec![0u8; n as _], ]);
1215 let info = instance.info()?;
1216
1217 info.write(&key, Some(vec![42u8; n as usize]), None, false)
1218 .map_err(|_| "Failed to write to storage during setup.")?;
1219
1220 let out_ptr = max_key_len + 4;
1221 let result;
1222 #[block]
1223 {
1224 result = BenchEnv::seal1_get_storage(
1225 &mut runtime,
1226 &mut memory,
1227 0, max_key_len, out_ptr, max_key_len, );
1232 }
1233
1234 assert_ok!(result);
1235 assert_eq!(&info.read(&key).unwrap(), &memory[out_ptr as usize..]);
1236 Ok(())
1237 }
1238
1239 #[benchmark(skip_meta, pov_mode = Measured)]
1240 fn seal_contains_storage(
1241 n: Linear<0, { T::Schedule::get().limits.payload_len }>,
1242 ) -> Result<(), BenchmarkError> {
1243 let max_key_len = T::MaxStorageKeyLen::get();
1244 let key = Key::<T>::try_from_var(vec![0u8; max_key_len as usize])
1245 .map_err(|_| "Key has wrong length")?;
1246 build_runtime!(runtime, instance, memory: [ key.to_vec(), ]);
1247 let info = instance.info()?;
1248
1249 info.write(&key, Some(vec![42u8; n as usize]), None, false)
1250 .map_err(|_| "Failed to write to storage during setup.")?;
1251
1252 let result;
1253 #[block]
1254 {
1255 result = BenchEnv::seal1_contains_storage(&mut runtime, &mut memory, 0, max_key_len);
1256 }
1257
1258 assert_eq!(result.unwrap(), n);
1259 Ok(())
1260 }
1261
1262 #[benchmark(skip_meta, pov_mode = Measured)]
1263 fn seal_take_storage(
1264 n: Linear<0, { T::Schedule::get().limits.payload_len }>,
1265 ) -> Result<(), BenchmarkError> {
1266 let max_key_len = T::MaxStorageKeyLen::get();
1267 let key = Key::<T>::try_from_var(vec![0u8; max_key_len as usize])
1268 .map_err(|_| "Key has wrong length")?;
1269 build_runtime!(runtime, instance, memory: [ key.to_vec(), n.to_le_bytes(), vec![0u8; n as _], ]);
1270 let info = instance.info()?;
1271
1272 let value = vec![42u8; n as usize];
1273 info.write(&key, Some(value.clone()), None, false)
1274 .map_err(|_| "Failed to write to storage during setup.")?;
1275
1276 let out_ptr = max_key_len + 4;
1277 let result;
1278 #[block]
1279 {
1280 result = BenchEnv::seal0_take_storage(
1281 &mut runtime,
1282 &mut memory,
1283 0, max_key_len, out_ptr, max_key_len, );
1288 }
1289
1290 assert_ok!(result);
1291 assert!(&info.read(&key).is_none());
1292 assert_eq!(&value, &memory[out_ptr as usize..]);
1293 Ok(())
1294 }
1295
1296 #[benchmark(pov_mode = Ignored)]
1301 fn set_transient_storage_empty() -> Result<(), BenchmarkError> {
1302 let max_value_len = T::Schedule::get().limits.payload_len;
1303 let max_key_len = T::MaxStorageKeyLen::get();
1304 let key = Key::<T>::try_from_var(vec![0u8; max_key_len as usize])
1305 .map_err(|_| "Key has wrong length")?;
1306 let value = Some(vec![42u8; max_value_len as _]);
1307 let mut setup = CallSetup::<T>::default();
1308 let (mut ext, _) = setup.ext();
1309 let mut runtime = crate::wasm::Runtime::new(&mut ext, vec![]);
1310 runtime.ext().transient_storage().meter().current_mut().limit = u32::MAX;
1311 let result;
1312 #[block]
1313 {
1314 result = runtime.ext().set_transient_storage(&key, value, false);
1315 }
1316
1317 assert_eq!(result, Ok(WriteOutcome::New));
1318 assert_eq!(runtime.ext().get_transient_storage(&key), Some(vec![42u8; max_value_len as _]));
1319 Ok(())
1320 }
1321
1322 #[benchmark(pov_mode = Ignored)]
1323 fn set_transient_storage_full() -> Result<(), BenchmarkError> {
1324 let max_value_len = T::Schedule::get().limits.payload_len;
1325 let max_key_len = T::MaxStorageKeyLen::get();
1326 let key = Key::<T>::try_from_var(vec![0u8; max_key_len as usize])
1327 .map_err(|_| "Key has wrong length")?;
1328 let value = Some(vec![42u8; max_value_len as _]);
1329 let mut setup = CallSetup::<T>::default();
1330 setup.set_transient_storage_size(T::MaxTransientStorageSize::get());
1331 let (mut ext, _) = setup.ext();
1332 let mut runtime = crate::wasm::Runtime::new(&mut ext, vec![]);
1333 runtime.ext().transient_storage().meter().current_mut().limit = u32::MAX;
1334 let result;
1335 #[block]
1336 {
1337 result = runtime.ext().set_transient_storage(&key, value, false);
1338 }
1339
1340 assert_eq!(result, Ok(WriteOutcome::New));
1341 assert_eq!(runtime.ext().get_transient_storage(&key), Some(vec![42u8; max_value_len as _]));
1342 Ok(())
1343 }
1344
1345 #[benchmark(pov_mode = Ignored)]
1346 fn get_transient_storage_empty() -> Result<(), BenchmarkError> {
1347 let max_value_len = T::Schedule::get().limits.payload_len;
1348 let max_key_len = T::MaxStorageKeyLen::get();
1349 let key = Key::<T>::try_from_var(vec![0u8; max_key_len as usize])
1350 .map_err(|_| "Key has wrong length")?;
1351
1352 let mut setup = CallSetup::<T>::default();
1353 let (mut ext, _) = setup.ext();
1354 let mut runtime = crate::wasm::Runtime::new(&mut ext, vec![]);
1355 runtime.ext().transient_storage().meter().current_mut().limit = u32::MAX;
1356 runtime
1357 .ext()
1358 .set_transient_storage(&key, Some(vec![42u8; max_value_len as _]), false)
1359 .map_err(|_| "Failed to write to transient storage during setup.")?;
1360 let result;
1361 #[block]
1362 {
1363 result = runtime.ext().get_transient_storage(&key);
1364 }
1365
1366 assert_eq!(result, Some(vec![42u8; max_value_len as _]));
1367 Ok(())
1368 }
1369
1370 #[benchmark(pov_mode = Ignored)]
1371 fn get_transient_storage_full() -> Result<(), BenchmarkError> {
1372 let max_value_len = T::Schedule::get().limits.payload_len;
1373 let max_key_len = T::MaxStorageKeyLen::get();
1374 let key = Key::<T>::try_from_var(vec![0u8; max_key_len as usize])
1375 .map_err(|_| "Key has wrong length")?;
1376
1377 let mut setup = CallSetup::<T>::default();
1378 setup.set_transient_storage_size(T::MaxTransientStorageSize::get());
1379 let (mut ext, _) = setup.ext();
1380 let mut runtime = crate::wasm::Runtime::new(&mut ext, vec![]);
1381 runtime.ext().transient_storage().meter().current_mut().limit = u32::MAX;
1382 runtime
1383 .ext()
1384 .set_transient_storage(&key, Some(vec![42u8; max_value_len as _]), false)
1385 .map_err(|_| "Failed to write to transient storage during setup.")?;
1386 let result;
1387 #[block]
1388 {
1389 result = runtime.ext().get_transient_storage(&key);
1390 }
1391
1392 assert_eq!(result, Some(vec![42u8; max_value_len as _]));
1393 Ok(())
1394 }
1395
1396 #[benchmark(pov_mode = Ignored)]
1398 fn rollback_transient_storage() -> Result<(), BenchmarkError> {
1399 let max_value_len = T::Schedule::get().limits.payload_len;
1400 let max_key_len = T::MaxStorageKeyLen::get();
1401 let key = Key::<T>::try_from_var(vec![0u8; max_key_len as usize])
1402 .map_err(|_| "Key has wrong length")?;
1403
1404 let mut setup = CallSetup::<T>::default();
1405 setup.set_transient_storage_size(T::MaxTransientStorageSize::get());
1406 let (mut ext, _) = setup.ext();
1407 let mut runtime = crate::wasm::Runtime::new(&mut ext, vec![]);
1408 runtime.ext().transient_storage().meter().current_mut().limit = u32::MAX;
1409 runtime.ext().transient_storage().start_transaction();
1410 runtime
1411 .ext()
1412 .set_transient_storage(&key, Some(vec![42u8; max_value_len as _]), false)
1413 .map_err(|_| "Failed to write to transient storage during setup.")?;
1414 #[block]
1415 {
1416 runtime.ext().transient_storage().rollback_transaction();
1417 }
1418
1419 assert_eq!(runtime.ext().get_transient_storage(&key), None);
1420 Ok(())
1421 }
1422
1423 #[benchmark(pov_mode = Measured)]
1426 fn seal_set_transient_storage(
1427 n: Linear<0, { T::Schedule::get().limits.payload_len }>,
1428 o: Linear<0, { T::Schedule::get().limits.payload_len }>,
1429 ) -> Result<(), BenchmarkError> {
1430 let max_key_len = T::MaxStorageKeyLen::get();
1431 let key = Key::<T>::try_from_var(vec![0u8; max_key_len as usize])
1432 .map_err(|_| "Key has wrong length")?;
1433 let value = vec![1u8; n as usize];
1434 build_runtime!(runtime, memory: [ key.to_vec(), value.clone(), ]);
1435 runtime.ext().transient_storage().meter().current_mut().limit = u32::MAX;
1436 runtime
1437 .ext()
1438 .set_transient_storage(&key, Some(vec![42u8; o as usize]), false)
1439 .map_err(|_| "Failed to write to transient storage during setup.")?;
1440
1441 let result;
1442 #[block]
1443 {
1444 result = BenchEnv::seal0_set_transient_storage(
1445 &mut runtime,
1446 &mut memory,
1447 0, max_key_len, max_key_len, n, );
1452 }
1453
1454 assert_ok!(result);
1455 assert_eq!(runtime.ext().get_transient_storage(&key).unwrap(), value);
1456 Ok(())
1457 }
1458
1459 #[benchmark(pov_mode = Measured)]
1460 fn seal_clear_transient_storage(
1461 n: Linear<0, { T::Schedule::get().limits.payload_len }>,
1462 ) -> Result<(), BenchmarkError> {
1463 let max_key_len = T::MaxStorageKeyLen::get();
1464 let key = Key::<T>::try_from_var(vec![0u8; max_key_len as usize])
1465 .map_err(|_| "Key has wrong length")?;
1466 build_runtime!(runtime, memory: [ key.to_vec(), ]);
1467 runtime.ext().transient_storage().meter().current_mut().limit = u32::MAX;
1468 runtime
1469 .ext()
1470 .set_transient_storage(&key, Some(vec![42u8; n as usize]), false)
1471 .map_err(|_| "Failed to write to transient storage during setup.")?;
1472
1473 let result;
1474 #[block]
1475 {
1476 result =
1477 BenchEnv::seal0_clear_transient_storage(&mut runtime, &mut memory, 0, max_key_len);
1478 }
1479
1480 assert_ok!(result);
1481 assert!(runtime.ext().get_transient_storage(&key).is_none());
1482 Ok(())
1483 }
1484
1485 #[benchmark(pov_mode = Measured)]
1486 fn seal_get_transient_storage(
1487 n: Linear<0, { T::Schedule::get().limits.payload_len }>,
1488 ) -> Result<(), BenchmarkError> {
1489 let max_key_len = T::MaxStorageKeyLen::get();
1490 let key = Key::<T>::try_from_var(vec![0u8; max_key_len as usize])
1491 .map_err(|_| "Key has wrong length")?;
1492 build_runtime!(runtime, memory: [ key.to_vec(), n.to_le_bytes(), vec![0u8; n as _], ]);
1493 runtime.ext().transient_storage().meter().current_mut().limit = u32::MAX;
1494 runtime
1495 .ext()
1496 .set_transient_storage(&key, Some(vec![42u8; n as usize]), false)
1497 .map_err(|_| "Failed to write to transient storage during setup.")?;
1498
1499 let out_ptr = max_key_len + 4;
1500 let result;
1501 #[block]
1502 {
1503 result = BenchEnv::seal0_get_transient_storage(
1504 &mut runtime,
1505 &mut memory,
1506 0, max_key_len, out_ptr, max_key_len, );
1511 }
1512
1513 assert_ok!(result);
1514 assert_eq!(
1515 &runtime.ext().get_transient_storage(&key).unwrap(),
1516 &memory[out_ptr as usize..]
1517 );
1518 Ok(())
1519 }
1520
1521 #[benchmark(pov_mode = Measured)]
1522 fn seal_contains_transient_storage(
1523 n: Linear<0, { T::Schedule::get().limits.payload_len }>,
1524 ) -> Result<(), BenchmarkError> {
1525 let max_key_len = T::MaxStorageKeyLen::get();
1526 let key = Key::<T>::try_from_var(vec![0u8; max_key_len as usize])
1527 .map_err(|_| "Key has wrong length")?;
1528 build_runtime!(runtime, memory: [ key.to_vec(), ]);
1529 runtime.ext().transient_storage().meter().current_mut().limit = u32::MAX;
1530 runtime
1531 .ext()
1532 .set_transient_storage(&key, Some(vec![42u8; n as usize]), false)
1533 .map_err(|_| "Failed to write to transient storage during setup.")?;
1534
1535 let result;
1536 #[block]
1537 {
1538 result = BenchEnv::seal0_contains_transient_storage(
1539 &mut runtime,
1540 &mut memory,
1541 0,
1542 max_key_len,
1543 );
1544 }
1545
1546 assert_eq!(result.unwrap(), n);
1547 Ok(())
1548 }
1549
1550 #[benchmark(pov_mode = Measured)]
1551 fn seal_take_transient_storage(
1552 n: Linear<0, { T::Schedule::get().limits.payload_len }>,
1553 ) -> Result<(), BenchmarkError> {
1554 let n = T::Schedule::get().limits.payload_len;
1555 let max_key_len = T::MaxStorageKeyLen::get();
1556 let key = Key::<T>::try_from_var(vec![0u8; max_key_len as usize])
1557 .map_err(|_| "Key has wrong length")?;
1558 build_runtime!(runtime, memory: [ key.to_vec(), n.to_le_bytes(), vec![0u8; n as _], ]);
1559 runtime.ext().transient_storage().meter().current_mut().limit = u32::MAX;
1560 let value = vec![42u8; n as usize];
1561 runtime
1562 .ext()
1563 .set_transient_storage(&key, Some(value.clone()), false)
1564 .map_err(|_| "Failed to write to transient storage during setup.")?;
1565
1566 let out_ptr = max_key_len + 4;
1567 let result;
1568 #[block]
1569 {
1570 result = BenchEnv::seal0_take_transient_storage(
1571 &mut runtime,
1572 &mut memory,
1573 0, max_key_len, out_ptr, max_key_len, );
1578 }
1579
1580 assert_ok!(result);
1581 assert!(&runtime.ext().get_transient_storage(&key).is_none());
1582 assert_eq!(&value, &memory[out_ptr as usize..]);
1583 Ok(())
1584 }
1585
1586 #[benchmark(pov_mode = Measured)]
1588 fn seal_transfer() {
1589 let account = account::<T::AccountId>("receiver", 0, 0);
1590 let value = Pallet::<T>::min_balance();
1591 assert!(value > 0u32.into());
1592
1593 let mut setup = CallSetup::<T>::default();
1594 setup.set_balance(value);
1595 let (mut ext, _) = setup.ext();
1596 let mut runtime = crate::wasm::Runtime::new(&mut ext, vec![]);
1597
1598 let account_bytes = account.encode();
1599 let account_len = account_bytes.len() as u32;
1600 let value_bytes = value.encode();
1601 let value_len = value_bytes.len() as u32;
1602 let mut memory = memory!(account_bytes, value_bytes,);
1603
1604 let result;
1605 #[block]
1606 {
1607 result = BenchEnv::seal0_transfer(
1608 &mut runtime,
1609 &mut memory,
1610 0, account_len,
1612 account_len,
1613 value_len,
1614 );
1615 }
1616
1617 assert_ok!(result);
1618 }
1619
1620 #[benchmark(pov_mode = Measured)]
1623 fn seal_call(t: Linear<0, 1>, i: Linear<0, { code::max_pages::<T>() * 64 * 1024 }>) {
1624 let Contract { account_id: callee, .. } =
1625 Contract::<T>::with_index(1, WasmModule::dummy(), vec![]).unwrap();
1626 let callee_bytes = callee.encode();
1627 let callee_len = callee_bytes.len() as u32;
1628
1629 let value: BalanceOf<T> = t.into();
1630 let value_bytes = value.encode();
1631
1632 let deposit: BalanceOf<T> = (u32::MAX - 100).into();
1633 let deposit_bytes = deposit.encode();
1634 let deposit_len = deposit_bytes.len() as u32;
1635
1636 let mut setup = CallSetup::<T>::default();
1637 setup.set_storage_deposit_limit(deposit);
1638 setup.set_data(vec![42; i as usize]);
1639 setup.set_origin(Origin::from_account_id(setup.contract().account_id.clone()));
1640
1641 let (mut ext, _) = setup.ext();
1642 let mut runtime = crate::wasm::Runtime::new(&mut ext, vec![]);
1643 let mut memory = memory!(callee_bytes, deposit_bytes, value_bytes,);
1644
1645 let result;
1646 #[block]
1647 {
1648 result = BenchEnv::seal2_call(
1649 &mut runtime,
1650 &mut memory,
1651 CallFlags::CLONE_INPUT.bits(), 0, 0, 0, callee_len, callee_len + deposit_len, 0, 0, SENTINEL, 0, );
1662 }
1663
1664 assert_ok!(result);
1665 }
1666
1667 #[benchmark(pov_mode = Measured)]
1668 fn seal_delegate_call() -> Result<(), BenchmarkError> {
1669 let hash = Contract::<T>::with_index(1, WasmModule::dummy(), vec![])?.info()?.code_hash;
1670
1671 let mut setup = CallSetup::<T>::default();
1672 setup.set_origin(Origin::from_account_id(setup.contract().account_id.clone()));
1673
1674 let (mut ext, _) = setup.ext();
1675 let mut runtime = crate::wasm::Runtime::new(&mut ext, vec![]);
1676 let mut memory = memory!(hash.encode(),);
1677
1678 let result;
1679 #[block]
1680 {
1681 result = BenchEnv::seal0_delegate_call(
1682 &mut runtime,
1683 &mut memory,
1684 0, 0, 0, 0, SENTINEL, 0,
1690 );
1691 }
1692
1693 assert_ok!(result);
1694 Ok(())
1695 }
1696
1697 #[benchmark(pov_mode = Measured)]
1701 fn seal_instantiate(
1702 i: Linear<0, { (code::max_pages::<T>() - 1) * 64 * 1024 }>,
1703 s: Linear<0, { (code::max_pages::<T>() - 1) * 64 * 1024 }>,
1704 ) -> Result<(), BenchmarkError> {
1705 let hash = Contract::<T>::with_index(1, WasmModule::dummy(), vec![])?.info()?.code_hash;
1706 let hash_bytes = hash.encode();
1707 let hash_len = hash_bytes.len() as u32;
1708
1709 let value: BalanceOf<T> = 1u32.into();
1710 let value_bytes = value.encode();
1711 let value_len = value_bytes.len() as u32;
1712
1713 let deposit: BalanceOf<T> = 0u32.into();
1714 let deposit_bytes = deposit.encode();
1715 let deposit_len = deposit_bytes.len() as u32;
1716
1717 let mut setup = CallSetup::<T>::default();
1718 setup.set_origin(Origin::from_account_id(setup.contract().account_id.clone()));
1719 setup.set_balance(value + (Pallet::<T>::min_balance() * 2u32.into()));
1720
1721 let account_id = &setup.contract().account_id.clone();
1722 let (mut ext, _) = setup.ext();
1723 let mut runtime = crate::wasm::Runtime::new(&mut ext, vec![]);
1724
1725 let input = vec![42u8; i as _];
1726 let salt = vec![42u8; s as _];
1727 let addr = Contracts::<T>::contract_address(&account_id, &hash, &input, &salt);
1728 let mut memory = memory!(hash_bytes, deposit_bytes, value_bytes, input, salt,);
1729
1730 let mut offset = {
1731 let mut current = 0u32;
1732 move |after: u32| {
1733 current += after;
1734 current
1735 }
1736 };
1737
1738 assert!(ContractInfoOf::<T>::get(&addr).is_none());
1739
1740 let result;
1741 #[block]
1742 {
1743 result = BenchEnv::seal2_instantiate(
1744 &mut runtime,
1745 &mut memory,
1746 0, 0, 0, offset(hash_len), offset(deposit_len), offset(value_len), i, SENTINEL, 0, SENTINEL, 0, offset(i), s, );
1760 }
1761
1762 assert_ok!(result);
1763 assert!(ContractInfoOf::<T>::get(&addr).is_some());
1764 assert_eq!(T::Currency::balance(&addr), Pallet::<T>::min_balance() + value);
1765 Ok(())
1766 }
1767
1768 #[benchmark(pov_mode = Measured)]
1770 fn seal_hash_sha2_256(n: Linear<0, { code::max_pages::<T>() * 64 * 1024 }>) {
1771 build_runtime!(runtime, memory: [[0u8; 32], vec![0u8; n as usize], ]);
1772
1773 let result;
1774 #[block]
1775 {
1776 result = BenchEnv::seal0_hash_sha2_256(&mut runtime, &mut memory, 32, n, 0);
1777 }
1778 assert_eq!(sp_io::hashing::sha2_256(&memory[32..]), &memory[0..32]);
1779 assert_ok!(result);
1780 }
1781
1782 #[benchmark(pov_mode = Measured)]
1784 fn seal_hash_keccak_256(n: Linear<0, { code::max_pages::<T>() * 64 * 1024 }>) {
1785 build_runtime!(runtime, memory: [[0u8; 32], vec![0u8; n as usize], ]);
1786
1787 let result;
1788 #[block]
1789 {
1790 result = BenchEnv::seal0_hash_keccak_256(&mut runtime, &mut memory, 32, n, 0);
1791 }
1792 assert_eq!(sp_io::hashing::keccak_256(&memory[32..]), &memory[0..32]);
1793 assert_ok!(result);
1794 }
1795
1796 #[benchmark(pov_mode = Measured)]
1798 fn seal_hash_blake2_256(n: Linear<0, { code::max_pages::<T>() * 64 * 1024 }>) {
1799 build_runtime!(runtime, memory: [[0u8; 32], vec![0u8; n as usize], ]);
1800
1801 let result;
1802 #[block]
1803 {
1804 result = BenchEnv::seal0_hash_blake2_256(&mut runtime, &mut memory, 32, n, 0);
1805 }
1806 assert_eq!(sp_io::hashing::blake2_256(&memory[32..]), &memory[0..32]);
1807 assert_ok!(result);
1808 }
1809
1810 #[benchmark(pov_mode = Measured)]
1812 fn seal_hash_blake2_128(n: Linear<0, { code::max_pages::<T>() * 64 * 1024 }>) {
1813 build_runtime!(runtime, memory: [[0u8; 16], vec![0u8; n as usize], ]);
1814
1815 let result;
1816 #[block]
1817 {
1818 result = BenchEnv::seal0_hash_blake2_128(&mut runtime, &mut memory, 16, n, 0);
1819 }
1820 assert_eq!(sp_io::hashing::blake2_128(&memory[16..]), &memory[0..16]);
1821 assert_ok!(result);
1822 }
1823
1824 #[benchmark(pov_mode = Measured)]
1827 fn seal_sr25519_verify(n: Linear<0, { T::MaxCodeLen::get() - 255 }>) {
1828 let message = (0..n).zip((32u8..127u8).cycle()).map(|(_, c)| c).collect::<Vec<_>>();
1829 let message_len = message.len() as u32;
1830
1831 let key_type = sp_core::crypto::KeyTypeId(*b"code");
1832 let pub_key = sp_io::crypto::sr25519_generate(key_type, None);
1833 let sig =
1834 sp_io::crypto::sr25519_sign(key_type, &pub_key, &message).expect("Generates signature");
1835 let sig = AsRef::<[u8; 64]>::as_ref(&sig).to_vec();
1836 let sig_len = sig.len() as u32;
1837
1838 build_runtime!(runtime, memory: [sig, pub_key.to_vec(), message, ]);
1839
1840 let result;
1841 #[block]
1842 {
1843 result = BenchEnv::seal0_sr25519_verify(
1844 &mut runtime,
1845 &mut memory,
1846 0, sig_len, message_len, sig_len + pub_key.len() as u32, );
1851 }
1852
1853 assert_eq!(result.unwrap(), ReturnErrorCode::Success);
1854 }
1855
1856 #[benchmark(pov_mode = Measured)]
1857 fn seal_ecdsa_recover() {
1858 let message_hash = sp_io::hashing::blake2_256("Hello world".as_bytes());
1859 let key_type = sp_core::crypto::KeyTypeId(*b"code");
1860 let signature = {
1861 let pub_key = sp_io::crypto::ecdsa_generate(key_type, None);
1862 let sig = sp_io::crypto::ecdsa_sign_prehashed(key_type, &pub_key, &message_hash)
1863 .expect("Generates signature");
1864 AsRef::<[u8; 65]>::as_ref(&sig).to_vec()
1865 };
1866
1867 build_runtime!(runtime, memory: [signature, message_hash, [0u8; 33], ]);
1868
1869 let result;
1870 #[block]
1871 {
1872 result = BenchEnv::seal0_ecdsa_recover(
1873 &mut runtime,
1874 &mut memory,
1875 0, 65, 65 + 32, );
1879 }
1880
1881 assert_eq!(result.unwrap(), ReturnErrorCode::Success);
1882 }
1883
1884 #[benchmark(pov_mode = Measured)]
1888 fn seal_ecdsa_to_eth_address() {
1889 let key_type = sp_core::crypto::KeyTypeId(*b"code");
1890 let pub_key_bytes = sp_io::crypto::ecdsa_generate(key_type, None).0;
1891 build_runtime!(runtime, memory: [[0u8; 20], pub_key_bytes,]);
1892
1893 let result;
1894 #[block]
1895 {
1896 result = BenchEnv::seal0_ecdsa_to_eth_address(
1897 &mut runtime,
1898 &mut memory,
1899 20, 0, );
1902 }
1903
1904 assert_ok!(result);
1905 assert_eq!(&memory[..20], runtime.ext().ecdsa_to_eth_address(&pub_key_bytes).unwrap());
1906 }
1907
1908 #[benchmark(pov_mode = Measured)]
1909 fn seal_set_code_hash() -> Result<(), BenchmarkError> {
1910 let code_hash =
1911 Contract::<T>::with_index(1, WasmModule::dummy(), vec![])?.info()?.code_hash;
1912
1913 build_runtime!(runtime, memory: [ code_hash.encode(),]);
1914
1915 let result;
1916 #[block]
1917 {
1918 result = BenchEnv::seal0_set_code_hash(&mut runtime, &mut memory, 0);
1919 }
1920
1921 assert_ok!(result);
1922 Ok(())
1923 }
1924
1925 #[benchmark(pov_mode = Measured)]
1926 fn lock_delegate_dependency() -> Result<(), BenchmarkError> {
1927 let code_hash = Contract::<T>::with_index(1, WasmModule::dummy_with_bytes(1), vec![])?
1928 .info()?
1929 .code_hash;
1930
1931 build_runtime!(runtime, memory: [ code_hash.encode(),]);
1932
1933 let result;
1934 #[block]
1935 {
1936 result = BenchEnv::seal0_lock_delegate_dependency(&mut runtime, &mut memory, 0);
1937 }
1938
1939 assert_ok!(result);
1940 Ok(())
1941 }
1942
1943 #[benchmark]
1944 fn unlock_delegate_dependency() -> Result<(), BenchmarkError> {
1945 let code_hash = Contract::<T>::with_index(1, WasmModule::dummy_with_bytes(1), vec![])?
1946 .info()?
1947 .code_hash;
1948
1949 build_runtime!(runtime, memory: [ code_hash.encode(),]);
1950 BenchEnv::seal0_lock_delegate_dependency(&mut runtime, &mut memory, 0).unwrap();
1951
1952 let result;
1953 #[block]
1954 {
1955 result = BenchEnv::seal0_unlock_delegate_dependency(&mut runtime, &mut memory, 0);
1956 }
1957
1958 assert_ok!(result);
1959 Ok(())
1960 }
1961
1962 #[benchmark(pov_mode = Measured)]
1963 fn seal_reentrance_count() {
1964 build_runtime!(runtime, memory: []);
1965 let result;
1966 #[block]
1967 {
1968 result = BenchEnv::seal0_reentrance_count(&mut runtime, &mut memory)
1969 }
1970
1971 assert_eq!(result.unwrap(), 0);
1972 }
1973
1974 #[benchmark(pov_mode = Measured)]
1975 fn seal_account_reentrance_count() {
1976 let Contract { account_id, .. } =
1977 Contract::<T>::with_index(1, WasmModule::dummy(), vec![]).unwrap();
1978 build_runtime!(runtime, memory: [account_id.encode(),]);
1979
1980 let result;
1981 #[block]
1982 {
1983 result = BenchEnv::seal0_account_reentrance_count(&mut runtime, &mut memory, 0);
1984 }
1985
1986 assert_eq!(result.unwrap(), 0);
1987 }
1988
1989 #[benchmark(pov_mode = Measured)]
1990 fn seal_instantiation_nonce() {
1991 build_runtime!(runtime, memory: []);
1992
1993 let result;
1994 #[block]
1995 {
1996 result = BenchEnv::seal0_instantiation_nonce(&mut runtime, &mut memory);
1997 }
1998
1999 assert_eq!(result.unwrap(), 1);
2000 }
2001
2002 #[benchmark(pov_mode = Ignored)]
2009 fn instr_i64_load_store(r: Linear<0, INSTR_BENCHMARK_RUNS>) -> Result<(), BenchmarkError> {
2010 use rand::prelude::*;
2011
2012 let mut rng = rand_pcg::Pcg32::seed_from_u64(8446744073709551615);
2014
2015 let memory = ImportedMemory::max::<T>();
2016 let bytes_per_page = 65536;
2017 let bytes_per_memory = memory.max_pages * bytes_per_page;
2018 let mut sbox = Sandbox::from(&WasmModule::<T>::from(ModuleDefinition {
2019 memory: Some(memory),
2020 call_body: Some(body::repeated_with_locals_using(
2021 &[Local::new(1, ValueType::I64)],
2022 r,
2023 || {
2024 let c0: i32 = rng.gen_range(0..bytes_per_memory as i32);
2028 let c1: i32 = rng.gen_range(0..bytes_per_memory as i32);
2029 [
2030 Instruction::I32Const(c0), Instruction::I64Load8S(0, 0),
2032 Instruction::SetLocal(0), Instruction::I32Const(c1), Instruction::GetLocal(0), Instruction::I64Store8(0, 0),
2037 ]
2038 },
2039 )),
2040 ..Default::default()
2041 }));
2042 #[block]
2043 {
2044 sbox.invoke();
2045 }
2046 Ok(())
2047 }
2048
2049 #[benchmark(extra, pov_mode = Ignored)]
2052 fn print_schedule() -> Result<(), BenchmarkError> {
2053 let max_weight = <T as frame_system::Config>::BlockWeights::get().max_block;
2054 let (weight_per_key, key_budget) =
2055 ContractInfo::<T>::deletion_budget(&mut WeightMeter::with_limit(max_weight));
2056 let schedule = T::Schedule::get();
2057 log::info!(target: LOG_TARGET, "
2058 {schedule:#?}
2059 ###############################################
2060 Lazy deletion weight per key: {weight_per_key}
2061 Lazy deletion keys per block: {key_budget}
2062 ");
2063 #[block]
2064 {}
2065
2066 Err(BenchmarkError::Skip)
2067 }
2068
2069 impl_benchmark_test_suite!(
2070 Contracts,
2071 crate::tests::ExtBuilder::default().build(),
2072 crate::tests::Test,
2073 );
2074}