1#![cfg(feature = "runtime-benchmarks")]
21
22use super::*;
23use frame::benchmarking::prelude::*;
24
25use crate::Pallet as Multisig;
26
27const SEED: u32 = 0;
28
29fn setup_multi<T: Config>(
30 s: u32,
31 z: u32,
32) -> Result<(Vec<T::AccountId>, Box<<T as Config>::RuntimeCall>), &'static str> {
33 let mut signatories: Vec<T::AccountId> = Vec::new();
34 for i in 0..s {
35 let signatory = account("signatory", i, SEED);
36 let balance = BalanceOf::<T>::max_value();
38 T::Currency::make_free_balance_be(&signatory, balance);
39 signatories.push(signatory);
40 }
41 signatories.sort();
42 let call: <T as Config>::RuntimeCall =
44 frame_system::Call::<T>::remark { remark: vec![0; z as usize] }.into();
45 Ok((signatories, Box::new(call)))
46}
47
48#[benchmarks]
49mod benchmarks {
50 use super::*;
51
52 #[benchmark]
54 fn as_multi_threshold_1(z: Linear<0, 10_000>) -> Result<(), BenchmarkError> {
55 let max_signatories = T::MaxSignatories::get().into();
56 let (mut signatories, _) = setup_multi::<T>(max_signatories, z)?;
57 let call: <T as Config>::RuntimeCall =
58 frame_system::Call::<T>::remark { remark: vec![0; z as usize] }.into();
59 let caller = signatories.pop().ok_or("signatories should have len 2 or more")?;
60 let caller_key = frame_system::Account::<T>::hashed_key_for(&caller);
62 add_to_whitelist(caller_key.into());
63
64 #[extrinsic_call]
65 _(RawOrigin::Signed(caller.clone()), signatories, Box::new(call));
66
67 Ok(())
69 }
70
71 #[benchmark]
74 fn as_multi_create(
75 s: Linear<2, { T::MaxSignatories::get() }>,
76 z: Linear<0, 10_000>,
77 ) -> Result<(), BenchmarkError> {
78 let (mut signatories, call) = setup_multi::<T>(s, z)?;
79 let call_hash = call.using_encoded(blake2_256);
80 let multi_account_id = Multisig::<T>::multi_account_id(&signatories, s.try_into().unwrap());
81 let caller = signatories.pop().ok_or("signatories should have len 2 or more")?;
82 let caller_key = frame_system::Account::<T>::hashed_key_for(&caller);
84 add_to_whitelist(caller_key.into());
85
86 #[extrinsic_call]
87 as_multi(RawOrigin::Signed(caller), s as u16, signatories, None, call, Weight::zero());
88
89 assert!(Multisigs::<T>::contains_key(multi_account_id, call_hash));
90
91 Ok(())
92 }
93
94 #[benchmark]
97 fn as_multi_approve(
98 s: Linear<3, { T::MaxSignatories::get() }>,
99 z: Linear<0, 10_000>,
100 ) -> Result<(), BenchmarkError> {
101 let (mut signatories, call) = setup_multi::<T>(s, z)?;
102 let call_hash = call.using_encoded(blake2_256);
103 let multi_account_id = Multisig::<T>::multi_account_id(&signatories, s.try_into().unwrap());
104 let mut signatories2 = signatories.clone();
105 let caller = signatories.pop().ok_or("signatories should have len 2 or more")?;
106 let timepoint = Multisig::<T>::timepoint();
108 Multisig::<T>::as_multi(
110 RawOrigin::Signed(caller).into(),
111 s as u16,
112 signatories,
113 None,
114 call.clone(),
115 Weight::zero(),
116 )?;
117 let caller2 = signatories2.remove(0);
118 let caller_key = frame_system::Account::<T>::hashed_key_for(&caller2);
120 add_to_whitelist(caller_key.into());
121
122 #[extrinsic_call]
123 as_multi(
124 RawOrigin::Signed(caller2),
125 s as u16,
126 signatories2,
127 Some(timepoint),
128 call,
129 Weight::zero(),
130 );
131
132 let multisig =
133 Multisigs::<T>::get(multi_account_id, call_hash).ok_or("multisig not created")?;
134 assert_eq!(multisig.approvals.len(), 2);
135
136 Ok(())
137 }
138
139 #[benchmark]
142 fn as_multi_complete(
143 s: Linear<2, { T::MaxSignatories::get() }>,
144 z: Linear<0, 10_000>,
145 ) -> Result<(), BenchmarkError> {
146 let (mut signatories, call) = setup_multi::<T>(s, z)?;
147 let call_hash = call.using_encoded(blake2_256);
148 let multi_account_id = Multisig::<T>::multi_account_id(&signatories, s.try_into().unwrap());
149 let mut signatories2 = signatories.clone();
150 let caller = signatories.pop().ok_or("signatories should have len 2 or more")?;
151 let timepoint = Multisig::<T>::timepoint();
153 Multisig::<T>::as_multi(
155 RawOrigin::Signed(caller).into(),
156 s as u16,
157 signatories,
158 None,
159 call.clone(),
160 Weight::zero(),
161 )?;
162 for i in 1..s - 1 {
164 let mut signatories_loop = signatories2.clone();
165 let caller_loop = signatories_loop.remove(i as usize);
166 let o = RawOrigin::Signed(caller_loop).into();
167 Multisig::<T>::as_multi(
168 o,
169 s as u16,
170 signatories_loop,
171 Some(timepoint),
172 call.clone(),
173 Weight::zero(),
174 )?;
175 }
176 let caller2 = signatories2.remove(0);
177 assert!(Multisigs::<T>::contains_key(&multi_account_id, call_hash));
178 let caller_key = frame_system::Account::<T>::hashed_key_for(&caller2);
180 add_to_whitelist(caller_key.into());
181
182 #[extrinsic_call]
183 as_multi(
184 RawOrigin::Signed(caller2),
185 s as u16,
186 signatories2,
187 Some(timepoint),
188 call,
189 Weight::MAX,
190 );
191
192 assert!(!Multisigs::<T>::contains_key(&multi_account_id, call_hash));
193
194 Ok(())
195 }
196
197 #[benchmark]
199 fn approve_as_multi_create(
200 s: Linear<2, { T::MaxSignatories::get() }>,
201 ) -> Result<(), BenchmarkError> {
202 let call_len = 10_000;
204 let (mut signatories, call) = setup_multi::<T>(s, call_len)?;
205 let multi_account_id = Multisig::<T>::multi_account_id(&signatories, s.try_into().unwrap());
206 let caller = signatories.pop().ok_or("signatories should have len 2 or more")?;
207 let call_hash = call.using_encoded(blake2_256);
208 let caller_key = frame_system::Account::<T>::hashed_key_for(&caller);
210 add_to_whitelist(caller_key.into());
211
212 #[extrinsic_call]
214 approve_as_multi(
215 RawOrigin::Signed(caller),
216 s as u16,
217 signatories,
218 None,
219 call_hash,
220 Weight::zero(),
221 );
222
223 assert!(Multisigs::<T>::contains_key(multi_account_id, call_hash));
224
225 Ok(())
226 }
227
228 #[benchmark]
230 fn approve_as_multi_approve(
231 s: Linear<2, { T::MaxSignatories::get() }>,
232 ) -> Result<(), BenchmarkError> {
233 let call_len = 10_000;
235 let (mut signatories, call) = setup_multi::<T>(s, call_len)?;
236 let mut signatories2 = signatories.clone();
237 let multi_account_id = Multisig::<T>::multi_account_id(&signatories, s.try_into().unwrap());
238 let caller = signatories.pop().ok_or("signatories should have len 2 or more")?;
239 let call_hash = call.using_encoded(blake2_256);
240 let timepoint = Multisig::<T>::timepoint();
242 Multisig::<T>::as_multi(
244 RawOrigin::Signed(caller).into(),
245 s as u16,
246 signatories,
247 None,
248 call,
249 Weight::zero(),
250 )?;
251 let caller2 = signatories2.remove(0);
252 let caller_key = frame_system::Account::<T>::hashed_key_for(&caller2);
254 add_to_whitelist(caller_key.into());
255
256 #[extrinsic_call]
257 approve_as_multi(
258 RawOrigin::Signed(caller2),
259 s as u16,
260 signatories2,
261 Some(timepoint),
262 call_hash,
263 Weight::zero(),
264 );
265
266 let multisig =
267 Multisigs::<T>::get(multi_account_id, call_hash).ok_or("multisig not created")?;
268 assert_eq!(multisig.approvals.len(), 2);
269
270 Ok(())
271 }
272
273 #[benchmark]
275 fn cancel_as_multi(s: Linear<2, { T::MaxSignatories::get() }>) -> Result<(), BenchmarkError> {
276 let call_len = 10_000;
278 let (mut signatories, call) = setup_multi::<T>(s, call_len)?;
279 let multi_account_id = Multisig::<T>::multi_account_id(&signatories, s.try_into().unwrap());
280 let caller = signatories.pop().ok_or("signatories should have len 2 or more")?;
281 let call_hash = call.using_encoded(blake2_256);
282 let timepoint = Multisig::<T>::timepoint();
283 let o = RawOrigin::Signed(caller.clone()).into();
285 Multisig::<T>::as_multi(o, s as u16, signatories.clone(), None, call, Weight::zero())?;
286 assert!(Multisigs::<T>::contains_key(&multi_account_id, call_hash));
287 let caller_key = frame_system::Account::<T>::hashed_key_for(&caller);
289 add_to_whitelist(caller_key.into());
290
291 #[extrinsic_call]
292 _(RawOrigin::Signed(caller), s as u16, signatories, timepoint, call_hash);
293
294 assert!(!Multisigs::<T>::contains_key(multi_account_id, call_hash));
295
296 Ok(())
297 }
298
299 #[benchmark]
301 fn poke_deposit(s: Linear<2, { T::MaxSignatories::get() }>) -> Result<(), BenchmarkError> {
302 let call_len = 10_000;
304 let (mut signatories, call) = setup_multi::<T>(s, call_len)?;
305 let multi_account_id = Multisig::<T>::multi_account_id(&signatories, s.try_into().unwrap());
306 let caller = signatories.pop().ok_or("signatories should have len 2 or more")?;
307 let call_hash = call.using_encoded(blake2_256);
308 Multisig::<T>::as_multi(
310 RawOrigin::Signed(caller.clone()).into(),
311 s as u16,
312 signatories.clone(),
313 None,
314 call,
315 Weight::zero(),
316 )?;
317
318 let multisig = Multisigs::<T>::get(multi_account_id.clone(), call_hash)
320 .ok_or("multisig not created")?;
321 let old_deposit = multisig.deposit;
323 assert_eq!(T::Currency::reserved_balance(&caller), old_deposit);
324
325 let additional_amount = 2u32.into();
326 let new_deposit = old_deposit.saturating_add(additional_amount);
327
328 T::Currency::reserve(&caller, additional_amount)?;
330 assert_eq!(T::Currency::reserved_balance(&caller), new_deposit);
331 Multisigs::<T>::try_mutate(
333 &multi_account_id,
334 call_hash,
335 |maybe_multisig| -> DispatchResult {
336 let mut multisig = maybe_multisig.take().ok_or(Error::<T>::NotFound)?;
337 multisig.deposit = new_deposit;
338 *maybe_multisig = Some(multisig);
339 Ok(())
340 },
341 )
342 .map_err(|_| BenchmarkError::Stop("Mutating storage to change deposits failed"))?;
343 let multisig = Multisigs::<T>::get(multi_account_id.clone(), call_hash)
345 .ok_or("Multisig not created")?;
346 assert_eq!(multisig.deposit, new_deposit);
347
348 let caller_key = frame_system::Account::<T>::hashed_key_for(&caller);
350 add_to_whitelist(caller_key.into());
351
352 #[extrinsic_call]
353 _(RawOrigin::Signed(caller.clone()), s as u16, signatories, call_hash);
354
355 let multisig = Multisigs::<T>::get(multi_account_id.clone(), call_hash)
356 .ok_or("Multisig not created")?;
357 assert_eq!(multisig.deposit, old_deposit);
358 assert_eq!(T::Currency::reserved_balance(&caller), old_deposit);
359 Ok(())
360 }
361
362 impl_benchmark_test_suite!(Multisig, crate::tests::new_test_ext(), crate::tests::Test);
363}