#![cfg(feature = "runtime-benchmarks")]
use super::*;
use crate::Pallet as Balances;
use frame_benchmarking::v2::*;
use frame_system::RawOrigin;
use sp_runtime::traits::Bounded;
use types::ExtraFlags;
const SEED: u32 = 0;
const ED_MULTIPLIER: u32 = 10;
fn minimum_balance<T: Config<I>, I: 'static>() -> T::Balance {
if cfg!(feature = "insecure_zero_ed") {
100u32.into()
} else {
T::ExistentialDeposit::get()
}
}
#[instance_benchmarks]
mod benchmarks {
use super::*;
#[benchmark]
fn transfer_allow_death() {
let existential_deposit: T::Balance = minimum_balance::<T, I>();
let caller = whitelisted_caller();
let balance = existential_deposit.saturating_mul(ED_MULTIPLIER.into()).max(1u32.into());
let _ = <Balances<T, I> as Currency<_>>::make_free_balance_be(&caller, balance);
let recipient: T::AccountId = account("recipient", 0, SEED);
let recipient_lookup = T::Lookup::unlookup(recipient.clone());
let transfer_amount =
existential_deposit.saturating_mul((ED_MULTIPLIER - 1).into()) + 1u32.into();
#[extrinsic_call]
_(RawOrigin::Signed(caller.clone()), recipient_lookup, transfer_amount);
assert_eq!(Balances::<T, I>::free_balance(&caller), Zero::zero());
assert_eq!(Balances::<T, I>::free_balance(&recipient), transfer_amount);
}
#[benchmark(extra)]
fn transfer_best_case() {
let caller = whitelisted_caller();
let recipient: T::AccountId = account("recipient", 0, SEED);
let recipient_lookup = T::Lookup::unlookup(recipient.clone());
let _ =
<Balances<T, I> as Currency<_>>::make_free_balance_be(&caller, T::Balance::max_value());
let existential_deposit: T::Balance = minimum_balance::<T, I>();
let _ =
<Balances<T, I> as Currency<_>>::make_free_balance_be(&recipient, existential_deposit);
let transfer_amount = existential_deposit.saturating_mul(ED_MULTIPLIER.into());
#[extrinsic_call]
transfer_allow_death(RawOrigin::Signed(caller.clone()), recipient_lookup, transfer_amount);
assert!(!Balances::<T, I>::free_balance(&caller).is_zero());
assert!(!Balances::<T, I>::free_balance(&recipient).is_zero());
}
#[benchmark]
fn transfer_keep_alive() {
let caller = whitelisted_caller();
let recipient: T::AccountId = account("recipient", 0, SEED);
let recipient_lookup = T::Lookup::unlookup(recipient.clone());
let _ =
<Balances<T, I> as Currency<_>>::make_free_balance_be(&caller, T::Balance::max_value());
let existential_deposit: T::Balance = minimum_balance::<T, I>();
let transfer_amount = existential_deposit.saturating_mul(ED_MULTIPLIER.into());
#[extrinsic_call]
_(RawOrigin::Signed(caller.clone()), recipient_lookup, transfer_amount);
assert!(!Balances::<T, I>::free_balance(&caller).is_zero());
assert_eq!(Balances::<T, I>::free_balance(&recipient), transfer_amount);
}
#[benchmark]
fn force_set_balance_creating() {
let user: T::AccountId = account("user", 0, SEED);
let user_lookup = T::Lookup::unlookup(user.clone());
let existential_deposit: T::Balance = minimum_balance::<T, I>();
let balance_amount = existential_deposit.saturating_mul(ED_MULTIPLIER.into());
let _ = <Balances<T, I> as Currency<_>>::make_free_balance_be(&user, balance_amount);
#[extrinsic_call]
force_set_balance(RawOrigin::Root, user_lookup, balance_amount);
assert_eq!(Balances::<T, I>::free_balance(&user), balance_amount);
}
#[benchmark]
fn force_set_balance_killing() {
let user: T::AccountId = account("user", 0, SEED);
let user_lookup = T::Lookup::unlookup(user.clone());
let existential_deposit: T::Balance = minimum_balance::<T, I>();
let balance_amount = existential_deposit.saturating_mul(ED_MULTIPLIER.into());
let _ = <Balances<T, I> as Currency<_>>::make_free_balance_be(&user, balance_amount);
#[extrinsic_call]
force_set_balance(RawOrigin::Root, user_lookup, Zero::zero());
assert!(Balances::<T, I>::free_balance(&user).is_zero());
}
#[benchmark]
fn force_transfer() {
let existential_deposit: T::Balance = minimum_balance::<T, I>();
let source: T::AccountId = account("source", 0, SEED);
let source_lookup = T::Lookup::unlookup(source.clone());
let balance = existential_deposit.saturating_mul(ED_MULTIPLIER.into());
let _ = <Balances<T, I> as Currency<_>>::make_free_balance_be(&source, balance);
let recipient: T::AccountId = account("recipient", 0, SEED);
let recipient_lookup = T::Lookup::unlookup(recipient.clone());
let transfer_amount =
existential_deposit.saturating_mul((ED_MULTIPLIER - 1).into()) + 1u32.into();
#[extrinsic_call]
_(RawOrigin::Root, source_lookup, recipient_lookup, transfer_amount);
assert_eq!(Balances::<T, I>::free_balance(&source), Zero::zero());
assert_eq!(Balances::<T, I>::free_balance(&recipient), transfer_amount);
}
#[benchmark(extra)]
fn transfer_increasing_users(u: Linear<0, 1_000>) {
let existential_deposit: T::Balance = minimum_balance::<T, I>();
let caller = whitelisted_caller();
let balance = existential_deposit.saturating_mul(ED_MULTIPLIER.into());
let _ = <Balances<T, I> as Currency<_>>::make_free_balance_be(&caller, balance);
let recipient: T::AccountId = account("recipient", 0, SEED);
let recipient_lookup = T::Lookup::unlookup(recipient.clone());
let transfer_amount =
existential_deposit.saturating_mul((ED_MULTIPLIER - 1).into()) + 1u32.into();
for i in 0..u {
let new_user: T::AccountId = account("new_user", i, SEED);
let _ = <Balances<T, I> as Currency<_>>::make_free_balance_be(&new_user, balance);
}
#[extrinsic_call]
transfer_allow_death(RawOrigin::Signed(caller.clone()), recipient_lookup, transfer_amount);
assert_eq!(Balances::<T, I>::free_balance(&caller), Zero::zero());
assert_eq!(Balances::<T, I>::free_balance(&recipient), transfer_amount);
}
#[benchmark]
fn transfer_all() {
let caller = whitelisted_caller();
let recipient: T::AccountId = account("recipient", 0, SEED);
let recipient_lookup = T::Lookup::unlookup(recipient.clone());
let existential_deposit: T::Balance = minimum_balance::<T, I>();
let balance = existential_deposit.saturating_mul(ED_MULTIPLIER.into());
let _ = <Balances<T, I> as Currency<_>>::make_free_balance_be(&caller, balance);
#[extrinsic_call]
_(RawOrigin::Signed(caller.clone()), recipient_lookup, false);
assert!(Balances::<T, I>::free_balance(&caller).is_zero());
assert_eq!(Balances::<T, I>::free_balance(&recipient), balance);
}
#[benchmark]
fn force_unreserve() -> Result<(), BenchmarkError> {
let user: T::AccountId = account("user", 0, SEED);
let user_lookup = T::Lookup::unlookup(user.clone());
let ed = minimum_balance::<T, I>();
let balance = ed + ed;
let _ = <Balances<T, I> as Currency<_>>::make_free_balance_be(&user, balance);
<Balances<T, I> as ReservableCurrency<_>>::reserve(&user, ed)?;
assert_eq!(Balances::<T, I>::reserved_balance(&user), ed);
assert_eq!(Balances::<T, I>::free_balance(&user), ed);
#[extrinsic_call]
_(RawOrigin::Root, user_lookup, balance);
assert!(Balances::<T, I>::reserved_balance(&user).is_zero());
assert_eq!(Balances::<T, I>::free_balance(&user), ed + ed);
Ok(())
}
#[benchmark]
fn upgrade_accounts(u: Linear<1, 1_000>) {
let caller: T::AccountId = whitelisted_caller();
let who = (0..u)
.into_iter()
.map(|i| -> T::AccountId {
let user = account("old_user", i, SEED);
let account = AccountData {
free: minimum_balance::<T, I>(),
reserved: minimum_balance::<T, I>(),
frozen: Zero::zero(),
flags: ExtraFlags::old_logic(),
};
frame_system::Pallet::<T>::inc_providers(&user);
assert!(T::AccountStore::try_mutate_exists(&user, |a| -> DispatchResult {
*a = Some(account);
Ok(())
})
.is_ok());
assert!(!Balances::<T, I>::account(&user).flags.is_new_logic());
assert_eq!(frame_system::Pallet::<T>::providers(&user), 1);
assert_eq!(frame_system::Pallet::<T>::consumers(&user), 0);
user
})
.collect();
#[extrinsic_call]
_(RawOrigin::Signed(caller.clone()), who);
for i in 0..u {
let user: T::AccountId = account("old_user", i, SEED);
assert!(Balances::<T, I>::account(&user).flags.is_new_logic());
assert_eq!(frame_system::Pallet::<T>::providers(&user), 1);
assert_eq!(frame_system::Pallet::<T>::consumers(&user), 1);
}
}
#[benchmark]
fn force_adjust_total_issuance() {
let ti = TotalIssuance::<T, I>::get();
let delta = 123u32.into();
#[extrinsic_call]
_(RawOrigin::Root, AdjustmentDirection::Increase, delta);
assert_eq!(TotalIssuance::<T, I>::get(), ti + delta);
}
#[benchmark]
fn burn_allow_death() {
let existential_deposit = T::ExistentialDeposit::get();
let caller = whitelisted_caller();
let balance = existential_deposit.saturating_mul(ED_MULTIPLIER.into());
let _ = <Balances<T, I> as Currency<_>>::make_free_balance_be(&caller, balance);
let burn_amount = balance - existential_deposit + 1u32.into();
#[extrinsic_call]
burn(RawOrigin::Signed(caller.clone()), burn_amount, false);
assert_eq!(Balances::<T, I>::free_balance(&caller), Zero::zero());
}
#[benchmark]
fn burn_keep_alive() {
let existential_deposit = T::ExistentialDeposit::get();
let caller = whitelisted_caller();
let balance = existential_deposit.saturating_mul(ED_MULTIPLIER.into());
let _ = <Balances<T, I> as Currency<_>>::make_free_balance_be(&caller, balance);
let burn_amount = 1u32.into();
#[extrinsic_call]
burn(RawOrigin::Signed(caller.clone()), burn_amount, true);
assert_eq!(Balances::<T, I>::free_balance(&caller), balance - burn_amount);
}
impl_benchmark_test_suite! {
Balances,
crate::tests::ExtBuilder::default().build(),
crate::tests::Test,
}
}