referrerpolicy=no-referrer-when-downgrade

pallet_vesting_precompiles/
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//! Benchmarks for `pallet-vesting-precompiles`.
19//!
20//! Only the view functions (`vestingBalance`, `vestingBalanceOf`) are benchmarked here.
21//! The mutating calls (`vest`, `vestOther`) delegate to `pallet-vesting` dispatchables
22//! and charge the pallet's own benchmarked dispatch weight via
23//! `get_dispatch_info().call_weight`, so no separate benchmark is needed.
24
25#![cfg(feature = "runtime-benchmarks")]
26
27use crate::{
28	IVesting, Vesting, VestingBalance,
29	pallet::{Config, Pallet},
30};
31use alloy_core::sol_types::SolValue;
32use frame_benchmarking::v2::*;
33use frame_support::traits::{Get, VestingSchedule, fungible::Mutate};
34use pallet_revive::{
35	AddressMapper,
36	precompiles::{Precompile, U256},
37};
38use sp_runtime::traits::Zero;
39
40type FungibleOf<T> = <T as pallet_revive::Config>::Currency;
41
42/// Set up a vesting schedule for `who`.
43///
44/// Uses `MinVestedTransfer` as the locked amount to satisfy runtime constraints,
45/// and funds the account with enough balance to cover the lock.
46fn setup_vesting<T: Config>(who: &T::AccountId) -> VestingBalance<T>
47where
48	VestingBalance<T>: Into<U256>,
49	VestingBalance<T>: From<<T as pallet_revive::Config>::Balance>,
50	<T as pallet_revive::Config>::Balance: From<VestingBalance<T>>,
51{
52	let locked = T::MinVestedTransfer::get();
53	// Fund the account with 10x the locked amount.
54	let fund_amount: U256 = (locked * 10u32.into()).into();
55	let balance = fund_amount.try_into().ok().expect("balance fits");
56	FungibleOf::<T>::set_balance(who, balance);
57
58	let per_block = (locked / 20u32.into()).max(1u32.into());
59	let starting_block = Zero::zero();
60	<pallet_vesting::Pallet<T> as VestingSchedule<T::AccountId>>::add_vesting_schedule(
61		who,
62		locked,
63		per_block,
64		starting_block,
65	)
66	.expect("adding vesting schedule should succeed");
67
68	locked
69}
70
71#[benchmarks(
72	where
73		VestingBalance<T>: Into<U256>,
74		VestingBalance<T>: From<<T as pallet_revive::Config>::Balance>,
75		<T as pallet_revive::Config>::Balance: From<VestingBalance<T>>,
76)]
77mod benchmarks {
78	use super::*;
79	fn precompile_address<T: Config>() -> [u8; 20]
80	where
81		VestingBalance<T>: Into<U256>,
82		VestingBalance<T>: From<<T as pallet_revive::Config>::Balance>,
83		<T as pallet_revive::Config>::Balance: From<VestingBalance<T>>,
84	{
85		Vesting::<T>::MATCHER.base_address()
86	}
87
88	/// Benchmark `vestingBalance()`: query locked balance for the caller (with schedule).
89	#[benchmark]
90	fn vesting_balance() {
91		let mut call_setup = pallet_revive::call_builder::CallSetup::<T>::default();
92		let caller_account = call_setup.contract().caller.clone();
93
94		setup_vesting::<T>(&caller_account);
95
96		let input = IVesting::IVestingCalls::vestingBalance(IVesting::vestingBalanceCall {});
97		let address = precompile_address::<T>();
98		let (mut ext, _) = call_setup.ext();
99
100		let result;
101		#[block]
102		{
103			result = Vesting::<T>::call(&address, &input, &mut ext);
104		}
105		let raw_data = result.unwrap();
106		let balance = U256::from_big_endian(&<[u8; 32]>::abi_decode(&raw_data).unwrap());
107		assert!(balance > U256::zero(), "locked balance should be non-zero");
108	}
109
110	/// Benchmark `vestingBalanceOf(target)`: query locked balance for another account.
111	#[benchmark]
112	fn vesting_balance_of() {
113		let mut call_setup = pallet_revive::call_builder::CallSetup::<T>::default();
114
115		let target_addr = pallet_revive::precompiles::H160::from_low_u64_be(0xBEEF);
116		let target_account = T::AddressMapper::to_account_id(&target_addr);
117		setup_vesting::<T>(&target_account);
118
119		let input = IVesting::IVestingCalls::vestingBalanceOf(IVesting::vestingBalanceOfCall {
120			target: alloy_core::primitives::Address::from_slice(target_addr.as_bytes()),
121		});
122		let address = precompile_address::<T>();
123		let (mut ext, _) = call_setup.ext();
124
125		let result;
126		#[block]
127		{
128			result = Vesting::<T>::call(&address, &input, &mut ext);
129		}
130		let raw_data = result.unwrap();
131		let balance = U256::from_big_endian(&<[u8; 32]>::abi_decode(&raw_data).unwrap());
132		assert!(balance > U256::zero(), "locked balance should be non-zero");
133	}
134
135	impl_benchmark_test_suite!(Pallet, crate::mock::new_test_ext(), crate::mock::Test);
136}