referrerpolicy=no-referrer-when-downgrade

pallet_safe_mode/
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#![cfg(feature = "runtime-benchmarks")]
19
20use super::{Pallet as SafeMode, *};
21use frame::benchmarking::prelude::*;
22
23#[benchmarks(where T::Currency: fungible::Mutate<T::AccountId>)]
24mod benchmarks {
25	use super::*;
26
27	/// `on_initialize` doing nothing.
28	#[benchmark]
29	fn on_initialize_noop() {
30		#[block]
31		{
32			SafeMode::<T>::on_initialize(1u32.into());
33		}
34	}
35
36	/// `on_initialize` exiting since the until block is in the past.
37	#[benchmark]
38	fn on_initialize_exit() {
39		EnteredUntil::<T>::put(&BlockNumberFor::<T>::zero());
40		assert!(SafeMode::<T>::is_entered());
41
42		#[block]
43		{
44			SafeMode::<T>::on_initialize(1u32.into());
45		}
46
47		assert!(!SafeMode::<T>::is_entered());
48	}
49
50	/// Permissionless enter - if configured.
51	#[benchmark]
52	fn enter() -> Result<(), BenchmarkError> {
53		T::EnterDepositAmount::get().ok_or_else(|| BenchmarkError::Weightless)?;
54
55		let caller: T::AccountId = whitelisted_caller();
56		let origin = RawOrigin::Signed(caller.clone());
57		<T::Currency as fungible::Mutate<_>>::set_balance(&caller, init_bal::<T>());
58
59		#[extrinsic_call]
60		_(origin);
61
62		assert_eq!(
63			EnteredUntil::<T>::get().unwrap(),
64			frame_system::Pallet::<T>::block_number() + T::EnterDuration::get()
65		);
66		Ok(())
67	}
68
69	/// Forceful enter - if configured.
70	#[benchmark]
71	fn force_enter() -> Result<(), BenchmarkError> {
72		let force_origin =
73			T::ForceEnterOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?;
74
75		let duration = T::ForceEnterOrigin::ensure_origin(force_origin.clone()).unwrap();
76
77		#[extrinsic_call]
78		_(force_origin as T::RuntimeOrigin);
79
80		assert_eq!(
81			EnteredUntil::<T>::get().unwrap(),
82			frame_system::Pallet::<T>::block_number() + duration
83		);
84		Ok(())
85	}
86
87	/// Permissionless extend - if configured.
88	#[benchmark]
89	fn extend() -> Result<(), BenchmarkError> {
90		T::ExtendDepositAmount::get().ok_or_else(|| BenchmarkError::Weightless)?;
91
92		let alice: T::AccountId = whitelisted_caller();
93		<T::Currency as fungible::Mutate<_>>::set_balance(&alice, init_bal::<T>());
94
95		frame_system::Pallet::<T>::set_block_number(1u32.into());
96		assert!(SafeMode::<T>::do_enter(None, 1u32.into()).is_ok());
97
98		#[extrinsic_call]
99		_(RawOrigin::Signed(alice));
100
101		assert_eq!(
102			EnteredUntil::<T>::get().unwrap(),
103			frame_system::Pallet::<T>::block_number() + 1u32.into() + T::ExtendDuration::get()
104		);
105		Ok(())
106	}
107
108	/// Forceful extend - if configured.
109	#[benchmark]
110	fn force_extend() -> Result<(), BenchmarkError> {
111		let force_origin = T::ForceExtendOrigin::try_successful_origin()
112			.map_err(|_| BenchmarkError::Weightless)?;
113
114		frame_system::Pallet::<T>::set_block_number(1u32.into());
115		assert!(SafeMode::<T>::do_enter(None, 1u32.into()).is_ok());
116
117		let duration = T::ForceExtendOrigin::ensure_origin(force_origin.clone()).unwrap();
118		let call = Call::<T>::force_extend {};
119
120		#[block]
121		{
122			call.dispatch_bypass_filter(force_origin)?;
123		}
124
125		assert_eq!(
126			EnteredUntil::<T>::get().unwrap(),
127			frame_system::Pallet::<T>::block_number() + 1u32.into() + duration
128		);
129		Ok(())
130	}
131
132	/// Forceful exit - if configured.
133	#[benchmark]
134	fn force_exit() -> Result<(), BenchmarkError> {
135		let force_origin =
136			T::ForceExitOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?;
137		assert!(SafeMode::<T>::do_enter(None, 1u32.into()).is_ok());
138
139		#[extrinsic_call]
140		_(force_origin as T::RuntimeOrigin);
141
142		assert_eq!(EnteredUntil::<T>::get(), None);
143		Ok(())
144	}
145
146	/// Permissionless release of a deposit - if configured.
147	#[benchmark]
148	fn release_deposit() -> Result<(), BenchmarkError> {
149		let delay = T::ReleaseDelay::get().ok_or_else(|| BenchmarkError::Weightless)?;
150
151		let alice: T::AccountId = whitelisted_caller();
152		let origin = RawOrigin::Signed(alice.clone());
153
154		<T::Currency as fungible::Mutate<_>>::set_balance(&alice, init_bal::<T>());
155		// Mock the storage. This is needed in case the `EnterDepositAmount` is zero.
156		let block: BlockNumberFor<T> = 1u32.into();
157		let bal: BalanceOf<T> = 1u32.into();
158		Deposits::<T>::insert(&alice, &block, &bal);
159		T::Currency::hold(&HoldReason::EnterOrExtend.into(), &alice, bal)?;
160		EnteredUntil::<T>::put(&block);
161		assert!(SafeMode::<T>::do_exit(ExitReason::Force).is_ok());
162
163		frame_system::Pallet::<T>::set_block_number(delay + One::one() + 2u32.into());
164		frame_system::Pallet::<T>::on_initialize(frame_system::Pallet::<T>::block_number());
165		SafeMode::<T>::on_initialize(frame_system::Pallet::<T>::block_number());
166
167		#[extrinsic_call]
168		_(origin, alice.clone(), 1u32.into());
169
170		assert!(!Deposits::<T>::contains_key(&alice, &block));
171		assert_eq!(<T::Currency as fungible::Inspect<_>>::balance(&alice), init_bal::<T>());
172		Ok(())
173	}
174
175	/// Forceful release of a deposit - if configured.
176	#[benchmark]
177	fn force_release_deposit() -> Result<(), BenchmarkError> {
178		let force_origin = T::ForceDepositOrigin::try_successful_origin()
179			.map_err(|_| BenchmarkError::Weightless)?;
180
181		let alice: T::AccountId = whitelisted_caller();
182		<T::Currency as fungible::Mutate<_>>::set_balance(&alice, init_bal::<T>());
183
184		// Mock the storage. This is needed in case the `EnterDepositAmount` is zero.
185		let block: BlockNumberFor<T> = 1u32.into();
186		let bal: BalanceOf<T> = 1u32.into();
187		Deposits::<T>::insert(&alice, &block, &bal);
188		T::Currency::hold(&&HoldReason::EnterOrExtend.into(), &alice, bal)?;
189		EnteredUntil::<T>::put(&block);
190
191		assert_eq!(
192			<T::Currency as fungible::Inspect<_>>::balance(&alice),
193			init_bal::<T>() - 1u32.into()
194		);
195		assert!(SafeMode::<T>::do_exit(ExitReason::Force).is_ok());
196
197		frame_system::Pallet::<T>::set_block_number(
198			frame_system::Pallet::<T>::block_number() + One::one(),
199		);
200		frame_system::Pallet::<T>::on_initialize(frame_system::Pallet::<T>::block_number());
201		SafeMode::<T>::on_initialize(frame_system::Pallet::<T>::block_number());
202
203		#[extrinsic_call]
204		_(force_origin as T::RuntimeOrigin, alice.clone(), block);
205
206		assert!(!Deposits::<T>::contains_key(&alice, block));
207		assert_eq!(<T::Currency as fungible::Inspect<_>>::balance(&alice), init_bal::<T>());
208		Ok(())
209	}
210
211	#[benchmark]
212	fn force_slash_deposit() -> Result<(), BenchmarkError> {
213		let force_origin = T::ForceDepositOrigin::try_successful_origin()
214			.map_err(|_| BenchmarkError::Weightless)?;
215
216		let alice: T::AccountId = whitelisted_caller();
217		<T::Currency as fungible::Mutate<_>>::set_balance(&alice, init_bal::<T>());
218
219		// Mock the storage. This is needed in case the `EnterDepositAmount` is zero.
220		let block: BlockNumberFor<T> = 1u32.into();
221		let bal: BalanceOf<T> = 1u32.into();
222		Deposits::<T>::insert(&alice, &block, &bal);
223		T::Currency::hold(&&HoldReason::EnterOrExtend.into(), &alice, bal)?;
224		EnteredUntil::<T>::put(&block);
225		assert!(SafeMode::<T>::do_exit(ExitReason::Force).is_ok());
226
227		#[extrinsic_call]
228		_(force_origin as T::RuntimeOrigin, alice.clone(), block);
229
230		assert!(!Deposits::<T>::contains_key(&alice, block));
231		assert_eq!(
232			<T::Currency as fungible::Inspect<_>>::balance(&alice),
233			init_bal::<T>() - 1u32.into()
234		);
235		Ok(())
236	}
237
238	fn init_bal<T: Config>() -> BalanceOf<T> {
239		BalanceOf::<T>::max_value() / 10u32.into()
240	}
241
242	impl_benchmark_test_suite!(SafeMode, crate::mock::new_test_ext(), crate::mock::Test);
243}