#![cfg(feature = "runtime-benchmarks")]
use super::{Pallet as SafeMode, *};
use frame_benchmarking::v2::*;
use frame_support::traits::{fungible, UnfilteredDispatchable};
use frame_system::{Pallet as System, RawOrigin};
use sp_runtime::traits::{Bounded, One, Zero};
#[benchmarks(where T::Currency: fungible::Mutate<T::AccountId>)]
mod benchmarks {
use super::*;
#[benchmark]
fn on_initialize_noop() {
#[block]
{
SafeMode::<T>::on_initialize(1u32.into());
}
}
#[benchmark]
fn on_initialize_exit() {
EnteredUntil::<T>::put(&BlockNumberFor::<T>::zero());
assert!(SafeMode::<T>::is_entered());
#[block]
{
SafeMode::<T>::on_initialize(1u32.into());
}
assert!(!SafeMode::<T>::is_entered());
}
#[benchmark]
fn enter() -> Result<(), BenchmarkError> {
T::EnterDepositAmount::get().ok_or_else(|| BenchmarkError::Weightless)?;
let caller: T::AccountId = whitelisted_caller();
let origin = RawOrigin::Signed(caller.clone());
<T::Currency as fungible::Mutate<_>>::set_balance(&caller, init_bal::<T>());
#[extrinsic_call]
_(origin);
assert_eq!(
EnteredUntil::<T>::get().unwrap(),
System::<T>::block_number() + T::EnterDuration::get()
);
Ok(())
}
#[benchmark]
fn force_enter() -> Result<(), BenchmarkError> {
let force_origin =
T::ForceEnterOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?;
let duration = T::ForceEnterOrigin::ensure_origin(force_origin.clone()).unwrap();
#[extrinsic_call]
_(force_origin as T::RuntimeOrigin);
assert_eq!(EnteredUntil::<T>::get().unwrap(), System::<T>::block_number() + duration);
Ok(())
}
#[benchmark]
fn extend() -> Result<(), BenchmarkError> {
T::ExtendDepositAmount::get().ok_or_else(|| BenchmarkError::Weightless)?;
let alice: T::AccountId = whitelisted_caller();
<T::Currency as fungible::Mutate<_>>::set_balance(&alice, init_bal::<T>());
System::<T>::set_block_number(1u32.into());
assert!(SafeMode::<T>::do_enter(None, 1u32.into()).is_ok());
#[extrinsic_call]
_(RawOrigin::Signed(alice));
assert_eq!(
EnteredUntil::<T>::get().unwrap(),
System::<T>::block_number() + 1u32.into() + T::ExtendDuration::get()
);
Ok(())
}
#[benchmark]
fn force_extend() -> Result<(), BenchmarkError> {
let force_origin = T::ForceExtendOrigin::try_successful_origin()
.map_err(|_| BenchmarkError::Weightless)?;
System::<T>::set_block_number(1u32.into());
assert!(SafeMode::<T>::do_enter(None, 1u32.into()).is_ok());
let duration = T::ForceExtendOrigin::ensure_origin(force_origin.clone()).unwrap();
let call = Call::<T>::force_extend {};
#[block]
{
call.dispatch_bypass_filter(force_origin)?;
}
assert_eq!(
EnteredUntil::<T>::get().unwrap(),
System::<T>::block_number() + 1u32.into() + duration
);
Ok(())
}
#[benchmark]
fn force_exit() -> Result<(), BenchmarkError> {
let force_origin =
T::ForceExitOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?;
assert!(SafeMode::<T>::do_enter(None, 1u32.into()).is_ok());
#[extrinsic_call]
_(force_origin as T::RuntimeOrigin);
assert_eq!(EnteredUntil::<T>::get(), None);
Ok(())
}
#[benchmark]
fn release_deposit() -> Result<(), BenchmarkError> {
let delay = T::ReleaseDelay::get().ok_or_else(|| BenchmarkError::Weightless)?;
let alice: T::AccountId = whitelisted_caller();
let origin = RawOrigin::Signed(alice.clone());
<T::Currency as fungible::Mutate<_>>::set_balance(&alice, init_bal::<T>());
let block: BlockNumberFor<T> = 1u32.into();
let bal: BalanceOf<T> = 1u32.into();
Deposits::<T>::insert(&alice, &block, &bal);
T::Currency::hold(&HoldReason::EnterOrExtend.into(), &alice, bal)?;
EnteredUntil::<T>::put(&block);
assert!(SafeMode::<T>::do_exit(ExitReason::Force).is_ok());
System::<T>::set_block_number(delay + One::one() + 2u32.into());
System::<T>::on_initialize(System::<T>::block_number());
SafeMode::<T>::on_initialize(System::<T>::block_number());
#[extrinsic_call]
_(origin, alice.clone(), 1u32.into());
assert!(!Deposits::<T>::contains_key(&alice, &block));
assert_eq!(<T::Currency as fungible::Inspect<_>>::balance(&alice), init_bal::<T>());
Ok(())
}
#[benchmark]
fn force_release_deposit() -> Result<(), BenchmarkError> {
let force_origin = T::ForceDepositOrigin::try_successful_origin()
.map_err(|_| BenchmarkError::Weightless)?;
let alice: T::AccountId = whitelisted_caller();
<T::Currency as fungible::Mutate<_>>::set_balance(&alice, init_bal::<T>());
let block: BlockNumberFor<T> = 1u32.into();
let bal: BalanceOf<T> = 1u32.into();
Deposits::<T>::insert(&alice, &block, &bal);
T::Currency::hold(&&HoldReason::EnterOrExtend.into(), &alice, bal)?;
EnteredUntil::<T>::put(&block);
assert_eq!(
<T::Currency as fungible::Inspect<_>>::balance(&alice),
init_bal::<T>() - 1u32.into()
);
assert!(SafeMode::<T>::do_exit(ExitReason::Force).is_ok());
System::<T>::set_block_number(System::<T>::block_number() + One::one());
System::<T>::on_initialize(System::<T>::block_number());
SafeMode::<T>::on_initialize(System::<T>::block_number());
#[extrinsic_call]
_(force_origin as T::RuntimeOrigin, alice.clone(), block);
assert!(!Deposits::<T>::contains_key(&alice, block));
assert_eq!(<T::Currency as fungible::Inspect<_>>::balance(&alice), init_bal::<T>());
Ok(())
}
#[benchmark]
fn force_slash_deposit() -> Result<(), BenchmarkError> {
let force_origin = T::ForceDepositOrigin::try_successful_origin()
.map_err(|_| BenchmarkError::Weightless)?;
let alice: T::AccountId = whitelisted_caller();
<T::Currency as fungible::Mutate<_>>::set_balance(&alice, init_bal::<T>());
let block: BlockNumberFor<T> = 1u32.into();
let bal: BalanceOf<T> = 1u32.into();
Deposits::<T>::insert(&alice, &block, &bal);
T::Currency::hold(&&HoldReason::EnterOrExtend.into(), &alice, bal)?;
EnteredUntil::<T>::put(&block);
assert!(SafeMode::<T>::do_exit(ExitReason::Force).is_ok());
#[extrinsic_call]
_(force_origin as T::RuntimeOrigin, alice.clone(), block);
assert!(!Deposits::<T>::contains_key(&alice, block));
assert_eq!(
<T::Currency as fungible::Inspect<_>>::balance(&alice),
init_bal::<T>() - 1u32.into()
);
Ok(())
}
fn init_bal<T: Config>() -> BalanceOf<T> {
BalanceOf::<T>::max_value() / 10u32.into()
}
impl_benchmark_test_suite!(SafeMode, crate::mock::new_test_ext(), crate::mock::Test);
}