referrerpolicy=no-referrer-when-downgrade

pallet_referenda/
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//! Democracy pallet benchmarking.
19
20use super::*;
21use crate::Pallet as Referenda;
22use alloc::{borrow::Cow, vec, vec::Vec};
23use assert_matches::assert_matches;
24use frame_benchmarking::v1::{
25	account, benchmarks_instance_pallet, whitelist_account, BenchmarkError,
26};
27use frame_support::{
28	assert_ok,
29	traits::{Currency, EnsureOrigin, EnsureOriginWithArg, UnfilteredDispatchable},
30};
31use frame_system::RawOrigin;
32use sp_runtime::traits::Bounded as ArithBounded;
33
34const SEED: u32 = 0;
35
36fn set_block_number<T: Config<I>, I: 'static>(n: BlockNumberFor<T, I>) {
37	<T as Config<I>>::BlockNumberProvider::set_block_number(n);
38}
39
40fn assert_last_event<T: Config<I>, I: 'static>(generic_event: <T as Config<I>>::RuntimeEvent) {
41	frame_system::Pallet::<T>::assert_last_event(generic_event.into());
42}
43
44fn funded_account<T: Config<I>, I: 'static>(name: &'static str, index: u32) -> T::AccountId {
45	let caller: T::AccountId = account(name, index, SEED);
46	T::Currency::make_free_balance_be(&caller, BalanceOf::<T, I>::max_value());
47	caller
48}
49
50fn dummy_call<T: Config<I>, I: 'static>() -> BoundedCallOf<T, I> {
51	let inner = frame_system::Call::remark { remark: vec![] };
52	let call = <T as Config<I>>::RuntimeCall::from(inner);
53	T::Preimages::bound(call).unwrap()
54}
55
56fn create_referendum<T: Config<I>, I: 'static>(origin: T::RuntimeOrigin) -> ReferendumIndex {
57	if let Ok(caller) = frame_system::ensure_signed(origin.clone()) {
58		T::Currency::make_free_balance_be(&caller, BalanceOf::<T, I>::max_value());
59		whitelist_account!(caller);
60	}
61
62	let proposal_origin = Box::new(RawOrigin::Root.into());
63	let proposal = dummy_call::<T, I>();
64	let enactment_moment = DispatchTime::After(0u32.into());
65	let call = crate::Call::<T, I>::submit { proposal_origin, proposal, enactment_moment };
66	assert_ok!(call.dispatch_bypass_filter(origin.clone()));
67	let index = ReferendumCount::<T, I>::get() - 1;
68	index
69}
70
71fn place_deposit<T: Config<I>, I: 'static>(index: ReferendumIndex) {
72	let caller = funded_account::<T, I>("caller", 0);
73	whitelist_account!(caller);
74	assert_ok!(Referenda::<T, I>::place_decision_deposit(RawOrigin::Signed(caller).into(), index));
75}
76
77fn nudge<T: Config<I>, I: 'static>(index: ReferendumIndex) {
78	assert_ok!(Referenda::<T, I>::nudge_referendum(RawOrigin::Root.into(), index));
79}
80
81fn fill_queue<T: Config<I>, I: 'static>(
82	origin: T::RuntimeOrigin,
83	index: ReferendumIndex,
84	spaces: u32,
85	pass_after: u32,
86) -> Vec<ReferendumIndex> {
87	// First, create enough other referendums to fill the track.
88	let mut others = vec![];
89	for _ in 0..info::<T, I>(index).max_deciding {
90		let index = create_referendum::<T, I>(origin.clone());
91		place_deposit::<T, I>(index);
92		others.push(index);
93	}
94
95	// We will also need enough referenda which are queued and passing, we want `MaxQueued - 1`
96	// in order to force the maximum amount of work to insert ours into the queue.
97	for _ in spaces..T::MaxQueued::get() {
98		let index = create_referendum::<T, I>(origin.clone());
99		place_deposit::<T, I>(index);
100		make_passing_after::<T, I>(index, Perbill::from_percent(pass_after));
101		others.push(index);
102	}
103
104	// Skip to when they can start being decided.
105	skip_prepare_period::<T, I>(index);
106
107	// Manually nudge the other referenda first to ensure that they begin.
108	others.iter().for_each(|&i| nudge::<T, I>(i));
109
110	others
111}
112
113fn info<T: Config<I>, I: 'static>(index: ReferendumIndex) -> Cow<'static, TrackInfoOf<T, I>> {
114	let status = Referenda::<T, I>::ensure_ongoing(index).unwrap();
115	T::Tracks::info(status.track).expect("Id value returned from T::Tracks")
116}
117
118fn make_passing_after<T: Config<I>, I: 'static>(index: ReferendumIndex, period_portion: Perbill) {
119	// We add an extra 1 percent to handle any perbill rounding errors which may cause
120	// a proposal to not actually pass.
121	let support = info::<T, I>(index)
122		.min_support
123		.threshold(period_portion)
124		.saturating_add(Perbill::from_percent(1));
125	let approval = info::<T, I>(index)
126		.min_approval
127		.threshold(period_portion)
128		.saturating_add(Perbill::from_percent(1));
129	Referenda::<T, I>::access_poll(index, |status| {
130		if let PollStatus::Ongoing(tally, class) = status {
131			T::Tally::setup(class, Perbill::from_rational(1u32, 1000u32));
132			*tally = T::Tally::from_requirements(support, approval, class);
133		}
134	});
135}
136
137fn make_passing<T: Config<I>, I: 'static>(index: ReferendumIndex) {
138	Referenda::<T, I>::access_poll(index, |status| {
139		if let PollStatus::Ongoing(tally, class) = status {
140			T::Tally::setup(class, Perbill::from_rational(1u32, 1000u32));
141			*tally = T::Tally::unanimity(class);
142		}
143	});
144}
145
146fn make_failing<T: Config<I>, I: 'static>(index: ReferendumIndex) {
147	Referenda::<T, I>::access_poll(index, |status| {
148		if let PollStatus::Ongoing(tally, class) = status {
149			T::Tally::setup(class, Perbill::from_rational(1u32, 1000u32));
150			*tally = T::Tally::rejection(class);
151		}
152	});
153}
154
155fn skip_prepare_period<T: Config<I>, I: 'static>(index: ReferendumIndex) {
156	let status = Referenda::<T, I>::ensure_ongoing(index).unwrap();
157	let prepare_period_over = status.submitted + info::<T, I>(index).prepare_period;
158	set_block_number::<T, I>(prepare_period_over);
159}
160
161fn skip_decision_period<T: Config<I>, I: 'static>(index: ReferendumIndex) {
162	let status = Referenda::<T, I>::ensure_ongoing(index).unwrap();
163	let decision_period_over = status.deciding.unwrap().since + info::<T, I>(index).decision_period;
164	set_block_number::<T, I>(decision_period_over);
165}
166
167fn skip_confirm_period<T: Config<I>, I: 'static>(index: ReferendumIndex) {
168	let status = Referenda::<T, I>::ensure_ongoing(index).unwrap();
169	let confirm_period_over = status.deciding.unwrap().confirming.unwrap();
170	set_block_number::<T, I>(confirm_period_over);
171}
172
173fn skip_timeout_period<T: Config<I>, I: 'static>(index: ReferendumIndex) {
174	let status = Referenda::<T, I>::ensure_ongoing(index).unwrap();
175	let timeout_period_over = status.submitted + T::UndecidingTimeout::get();
176	set_block_number::<T, I>(timeout_period_over);
177}
178
179fn alarm_time<T: Config<I>, I: 'static>(index: ReferendumIndex) -> BlockNumberFor<T, I> {
180	let status = Referenda::<T, I>::ensure_ongoing(index).unwrap();
181	status.alarm.unwrap().0
182}
183
184fn is_confirming<T: Config<I>, I: 'static>(index: ReferendumIndex) -> bool {
185	let status = Referenda::<T, I>::ensure_ongoing(index).unwrap();
186	matches!(
187		status,
188		ReferendumStatus { deciding: Some(DecidingStatus { confirming: Some(_), .. }), .. }
189	)
190}
191
192fn is_not_confirming<T: Config<I>, I: 'static>(index: ReferendumIndex) -> bool {
193	let status = Referenda::<T, I>::ensure_ongoing(index).unwrap();
194	matches!(
195		status,
196		ReferendumStatus { deciding: Some(DecidingStatus { confirming: None, .. }), .. }
197	)
198}
199
200benchmarks_instance_pallet! {
201	submit {
202		let origin =
203			T::SubmitOrigin::try_successful_origin(&RawOrigin::Root.into()).map_err(|_| BenchmarkError::Weightless)?;
204		if let Ok(caller) = frame_system::ensure_signed(origin.clone()) {
205			T::Currency::make_free_balance_be(&caller, BalanceOf::<T, I>::max_value());
206			whitelist_account!(caller);
207		}
208	}: _<T::RuntimeOrigin>(
209		origin,
210		Box::new(RawOrigin::Root.into()),
211		dummy_call::<T, I>(),
212		DispatchTime::After(0u32.into())
213	) verify {
214		let index = ReferendumCount::<T, I>::get().checked_sub(1).unwrap();
215		assert_matches!(ReferendumInfoFor::<T, I>::get(index), Some(ReferendumInfo::Ongoing(_)));
216	}
217
218	place_decision_deposit_preparing {
219		let origin =
220			T::SubmitOrigin::try_successful_origin(&RawOrigin::Root.into()).map_err(|_| BenchmarkError::Weightless)?;
221		let index = create_referendum::<T, I>(origin.clone());
222	}: place_decision_deposit<T::RuntimeOrigin>(origin, index)
223	verify {
224		assert!(Referenda::<T, I>::ensure_ongoing(index).unwrap().decision_deposit.is_some());
225	}
226
227	place_decision_deposit_queued {
228		let origin =
229			T::SubmitOrigin::try_successful_origin(&RawOrigin::Root.into()).map_err(|_| BenchmarkError::Weightless)?;
230		let index = create_referendum::<T, I>(origin.clone());
231		fill_queue::<T, I>(origin.clone(), index, 1, 90);
232	}: place_decision_deposit<T::RuntimeOrigin>(origin, index)
233	verify {
234		let track = Referenda::<T, I>::ensure_ongoing(index).unwrap().track;
235		assert_eq!(TrackQueue::<T, I>::get(&track).len() as u32, T::MaxQueued::get());
236		assert!(TrackQueue::<T, I>::get(&track).contains(&(index, 0u32.into())));
237	}
238
239	place_decision_deposit_not_queued {
240		let origin =
241			T::SubmitOrigin::try_successful_origin(&RawOrigin::Root.into()).map_err(|_| BenchmarkError::Weightless)?;
242		let index = create_referendum::<T, I>(origin.clone());
243		fill_queue::<T, I>(origin.clone(), index, 0, 90);
244		let track = Referenda::<T, I>::ensure_ongoing(index).unwrap().track;
245		assert_eq!(TrackQueue::<T, I>::get(&track).len() as u32, T::MaxQueued::get());
246		assert!(TrackQueue::<T, I>::get(&track).into_iter().all(|(i, _)| i != index));
247	}: place_decision_deposit<T::RuntimeOrigin>(origin, index)
248	verify {
249		assert_eq!(TrackQueue::<T, I>::get(&track).len() as u32, T::MaxQueued::get());
250		assert!(TrackQueue::<T, I>::get(&track).into_iter().all(|(i, _)| i != index));
251	}
252
253	place_decision_deposit_passing {
254		let origin =
255			T::SubmitOrigin::try_successful_origin(&RawOrigin::Root.into()).map_err(|_| BenchmarkError::Weightless)?;
256		let index = create_referendum::<T, I>(origin.clone());
257		skip_prepare_period::<T, I>(index);
258		make_passing::<T, I>(index);
259	}: place_decision_deposit<T::RuntimeOrigin>(origin, index)
260	verify {
261		assert!(is_confirming::<T, I>(index));
262	}
263
264	place_decision_deposit_failing {
265		let origin =
266			T::SubmitOrigin::try_successful_origin(&RawOrigin::Root.into()).map_err(|_| BenchmarkError::Weightless)?;
267		let index = create_referendum::<T, I>(origin.clone());
268		skip_prepare_period::<T, I>(index);
269	}: place_decision_deposit<T::RuntimeOrigin>(origin, index)
270	verify {
271		assert!(is_not_confirming::<T, I>(index));
272	}
273
274	refund_decision_deposit {
275		let origin =
276			T::SubmitOrigin::try_successful_origin(&RawOrigin::Root.into()).map_err(|_| BenchmarkError::Weightless)?;
277		let index = create_referendum::<T, I>(origin.clone());
278		place_deposit::<T, I>(index);
279		assert_ok!(Referenda::<T, I>::cancel(
280			T::CancelOrigin::try_successful_origin()
281				.expect("CancelOrigin has no successful origin required for the benchmark"),
282			index,
283		));
284	}: _<T::RuntimeOrigin>(origin, index)
285	verify {
286		assert_matches!(ReferendumInfoFor::<T, I>::get(index), Some(ReferendumInfo::Cancelled(_, _, None)));
287	}
288
289	refund_submission_deposit {
290		let origin =
291			T::SubmitOrigin::try_successful_origin(&RawOrigin::Root.into()).map_err(|_| BenchmarkError::Weightless)?;
292		let index = create_referendum::<T, I>(origin.clone());
293		let caller = frame_system::ensure_signed(origin.clone()).unwrap();
294		let balance = T::Currency::free_balance(&caller);
295		assert_ok!(Referenda::<T, I>::cancel(
296			T::CancelOrigin::try_successful_origin()
297				.expect("CancelOrigin has no successful origin required for the benchmark"),
298			index,
299		));
300		assert_matches!(ReferendumInfoFor::<T, I>::get(index), Some(ReferendumInfo::Cancelled(_, Some(_), _)));
301	}: _<T::RuntimeOrigin>(origin, index)
302	verify {
303		assert_matches!(ReferendumInfoFor::<T, I>::get(index), Some(ReferendumInfo::Cancelled(_, None, _)));
304		let new_balance = T::Currency::free_balance(&caller);
305		// the deposit is zero or make sure it was unreserved.
306		assert!(T::SubmissionDeposit::get().is_zero() || new_balance > balance);
307	}
308
309	cancel {
310		let origin = T::SubmitOrigin::try_successful_origin(&RawOrigin::Root.into())
311			.expect("SubmitOrigin has no successful origin required for the benchmark");
312		let index = create_referendum::<T, I>(origin);
313		place_deposit::<T, I>(index);
314	}: _<T::RuntimeOrigin>(
315		T::CancelOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?,
316		index
317	) verify {
318		assert_matches!(ReferendumInfoFor::<T, I>::get(index), Some(ReferendumInfo::Cancelled(..)));
319	}
320
321	kill {
322		let origin = T::SubmitOrigin::try_successful_origin(&RawOrigin::Root.into())
323			.expect("SubmitOrigin has no successful origin required for the benchmark");
324		let index = create_referendum::<T, I>(origin);
325		place_deposit::<T, I>(index);
326	}: _<T::RuntimeOrigin>(
327		T::KillOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?,
328		index
329	) verify {
330		assert_matches!(ReferendumInfoFor::<T, I>::get(index), Some(ReferendumInfo::Killed(..)));
331	}
332
333	one_fewer_deciding_queue_empty {
334		let origin = T::SubmitOrigin::try_successful_origin(&RawOrigin::Root.into())
335			.expect("SubmitOrigin has no successful origin required for the benchmark");
336		let index = create_referendum::<T, I>(origin);
337		place_deposit::<T, I>(index);
338		skip_prepare_period::<T, I>(index);
339		nudge::<T, I>(index);
340		let track = Referenda::<T, I>::ensure_ongoing(index).unwrap().track;
341		assert_ok!(Referenda::<T, I>::cancel(
342			T::CancelOrigin::try_successful_origin()
343				.expect("CancelOrigin has no successful origin required for the benchmark"),
344			index,
345		));
346		assert_eq!(DecidingCount::<T, I>::get(&track), 1);
347	}: one_fewer_deciding(RawOrigin::Root, track)
348	verify {
349		assert_eq!(DecidingCount::<T, I>::get(&track), 0);
350	}
351
352	one_fewer_deciding_failing {
353		let origin = T::SubmitOrigin::try_successful_origin(&RawOrigin::Root.into())
354			.expect("SubmitOrigin has no successful origin required for the benchmark");
355		let index = create_referendum::<T, I>(origin.clone());
356		// No spaces free in the queue.
357		let queued = fill_queue::<T, I>(origin, index, 0, 90);
358		let track = Referenda::<T, I>::ensure_ongoing(index).unwrap().track;
359		assert_ok!(Referenda::<T, I>::cancel(
360			T::CancelOrigin::try_successful_origin()
361				.expect("CancelOrigin has no successful origin required for the benchmark"),
362			queued[0],
363		));
364		assert_eq!(TrackQueue::<T, I>::get(&track).len() as u32, T::MaxQueued::get());
365		let deciding_count = DecidingCount::<T, I>::get(&track);
366	}: one_fewer_deciding(RawOrigin::Root, track)
367	verify {
368		assert_eq!(DecidingCount::<T, I>::get(&track), deciding_count);
369		assert_eq!(TrackQueue::<T, I>::get(&track).len() as u32, T::MaxQueued::get() - 1);
370		assert!(queued.into_iter().skip(1).all(|i| Referenda::<T, I>::ensure_ongoing(i)
371			.unwrap()
372			.deciding
373			.map_or(true, |d| d.confirming.is_none())
374		));
375	}
376
377	one_fewer_deciding_passing {
378		let origin = T::SubmitOrigin::try_successful_origin(&RawOrigin::Root.into())
379			.expect("SubmitOrigin has no successful origin required for the benchmark");
380		let index = create_referendum::<T, I>(origin.clone());
381		// No spaces free in the queue.
382		let queued = fill_queue::<T, I>(origin, index, 0, 0);
383		let track = Referenda::<T, I>::ensure_ongoing(index).unwrap().track;
384		assert_ok!(Referenda::<T, I>::cancel(
385			T::CancelOrigin::try_successful_origin()
386				.expect("CancelOrigin has no successful origin required for the benchmark"),
387			queued[0],
388		));
389		assert_eq!(TrackQueue::<T, I>::get(&track).len() as u32, T::MaxQueued::get());
390		let deciding_count = DecidingCount::<T, I>::get(&track);
391	}: one_fewer_deciding(RawOrigin::Root, track)
392	verify {
393		assert_eq!(DecidingCount::<T, I>::get(&track), deciding_count);
394		assert_eq!(TrackQueue::<T, I>::get(&track).len() as u32, T::MaxQueued::get() - 1);
395		assert!(queued.into_iter().skip(1).filter(|i| Referenda::<T, I>::ensure_ongoing(*i)
396			.unwrap()
397			.deciding
398			.map_or(false, |d| d.confirming.is_some())
399		).count() == 1);
400	}
401
402	nudge_referendum_requeued_insertion {
403		let origin = T::SubmitOrigin::try_successful_origin(&RawOrigin::Root.into())
404			.expect("SubmitOrigin has no successful origin required for the benchmark");
405		// First create our referendum and place the deposit. It will be failing.
406		let index = create_referendum::<T, I>(origin.clone());
407		place_deposit::<T, I>(index);
408		fill_queue::<T, I>(origin, index, 0, 90);
409
410		// Now nudge ours, with the track now full and the queue full of referenda with votes,
411		// ours will not be in the queue.
412		nudge::<T, I>(index);
413		let track = Referenda::<T, I>::ensure_ongoing(index).unwrap().track;
414		assert!(TrackQueue::<T, I>::get(&track).into_iter().all(|(i, _)| i != index));
415
416		// Now alter the voting, so that ours goes into pole-position and shifts others down.
417		make_passing::<T, I>(index);
418	}: nudge_referendum(RawOrigin::Root, index)
419	verify {
420		let t = TrackQueue::<T, I>::get(&track);
421		assert_eq!(t.len() as u32, T::MaxQueued::get());
422		assert_eq!(t[t.len() - 1].0, index);
423	}
424
425	nudge_referendum_requeued_slide {
426		let origin = T::SubmitOrigin::try_successful_origin(&RawOrigin::Root.into())
427			.expect("SubmitOrigin has no successful origin required for the benchmark");
428		// First create our referendum and place the deposit. It will be failing.
429		let index = create_referendum::<T, I>(origin.clone());
430		place_deposit::<T, I>(index);
431		fill_queue::<T, I>(origin, index, 1, 90);
432
433		// Now nudge ours, with the track now full, ours will be queued, but with no votes, it
434		// will have the worst position.
435		nudge::<T, I>(index);
436		let track = Referenda::<T, I>::ensure_ongoing(index).unwrap().track;
437		assert_eq!(TrackQueue::<T, I>::get(&track).len() as u32, T::MaxQueued::get());
438		assert_eq!(TrackQueue::<T, I>::get(&track)[0], (index, 0u32.into()));
439
440		// Now alter the voting, so that ours leap-frogs all into the best position.
441		make_passing::<T, I>(index);
442	}: nudge_referendum(RawOrigin::Root, index)
443	verify {
444		let t = TrackQueue::<T, I>::get(&track);
445		assert_eq!(t.len() as u32, T::MaxQueued::get());
446		assert_eq!(t[t.len() - 1].0, index);
447	}
448
449	nudge_referendum_queued {
450		// NOTE: worst possible queue situation is with a queue full of passing refs with one slot
451		// free and this failing. It would result in `QUEUE_SIZE - 1` items being shifted for the
452		// insertion at the beginning.
453
454		let origin = T::SubmitOrigin::try_successful_origin(&RawOrigin::Root.into())
455			.expect("SubmitOrigin has no successful origin required for the benchmark");
456		// First create our referendum and place the deposit. It will be failing.
457		let index = create_referendum::<T, I>(origin.clone());
458		place_deposit::<T, I>(index);
459		fill_queue::<T, I>(origin, index, 1, 0);
460
461		let track = Referenda::<T, I>::ensure_ongoing(index).unwrap().track;
462		assert_eq!(TrackQueue::<T, I>::get(&track).len() as u32, T::MaxQueued::get() - 1);
463		assert!(TrackQueue::<T, I>::get(&track).into_iter().all(|(_, v)| v > 0u32.into()));
464
465		// Then nudge ours, with the track now full, ours will be queued.
466	}: nudge_referendum(RawOrigin::Root, index)
467	verify {
468		assert_eq!(TrackQueue::<T, I>::get(&track).len() as u32, T::MaxQueued::get());
469		assert_eq!(TrackQueue::<T, I>::get(&track)[0], (index, 0u32.into()));
470	}
471
472	nudge_referendum_not_queued {
473		let origin = T::SubmitOrigin::try_successful_origin(&RawOrigin::Root.into())
474			.expect("SubmitOrigin has no successful origin required for the benchmark");
475		// First create our referendum and place the deposit. It will be failing.
476		let index = create_referendum::<T, I>(origin.clone());
477		place_deposit::<T, I>(index);
478		fill_queue::<T, I>(origin, index, 0, 0);
479
480		let track = Referenda::<T, I>::ensure_ongoing(index).unwrap().track;
481		assert_eq!(TrackQueue::<T, I>::get(&track).len() as u32, T::MaxQueued::get());
482		assert!(TrackQueue::<T, I>::get(&track).into_iter().all(|(_, v)| v > 0u32.into()));
483
484		// Then nudge ours, with the track now full, ours will be queued.
485	}: nudge_referendum(RawOrigin::Root, index)
486	verify {
487		assert_eq!(TrackQueue::<T, I>::get(&track).len() as u32, T::MaxQueued::get());
488		assert!(TrackQueue::<T, I>::get(&track).into_iter().all(|(i, _)| i != index));
489	}
490
491	nudge_referendum_no_deposit {
492		let origin = T::SubmitOrigin::try_successful_origin(&RawOrigin::Root.into())
493			.expect("SubmitOrigin has no successful origin required for the benchmark");
494		let index = create_referendum::<T, I>(origin);
495		skip_prepare_period::<T, I>(index);
496	}: nudge_referendum(RawOrigin::Root, index)
497	verify {
498		let status = Referenda::<T, I>::ensure_ongoing(index).unwrap();
499		assert_matches!(status, ReferendumStatus { deciding: None, .. });
500	}
501
502	nudge_referendum_preparing {
503		let origin = T::SubmitOrigin::try_successful_origin(&RawOrigin::Root.into())
504			.expect("SubmitOrigin has no successful origin required for the benchmark");
505		let index = create_referendum::<T, I>(origin);
506		place_deposit::<T, I>(index);
507	}: nudge_referendum(RawOrigin::Root, index)
508	verify {
509		let status = Referenda::<T, I>::ensure_ongoing(index).unwrap();
510		assert_matches!(status, ReferendumStatus { deciding: None, .. });
511	}
512
513	nudge_referendum_timed_out {
514		let origin = T::SubmitOrigin::try_successful_origin(&RawOrigin::Root.into())
515			.expect("SubmitOrigin has no successful origin required for the benchmark");
516		let index = create_referendum::<T, I>(origin);
517		skip_timeout_period::<T, I>(index);
518	}: nudge_referendum(RawOrigin::Root, index)
519	verify {
520		let info = ReferendumInfoFor::<T, I>::get(index).unwrap();
521		assert_matches!(info, ReferendumInfo::TimedOut(..));
522	}
523
524	nudge_referendum_begin_deciding_failing {
525		let origin = T::SubmitOrigin::try_successful_origin(&RawOrigin::Root.into())
526			.expect("SubmitOrigin has no successful origin required for the benchmark");
527		let index = create_referendum::<T, I>(origin);
528		place_deposit::<T, I>(index);
529		skip_prepare_period::<T, I>(index);
530	}: nudge_referendum(RawOrigin::Root, index)
531	verify {
532		assert!(is_not_confirming::<T, I>(index));
533	}
534
535	nudge_referendum_begin_deciding_passing {
536		let origin = T::SubmitOrigin::try_successful_origin(&RawOrigin::Root.into())
537			.expect("SubmitOrigin has no successful origin required for the benchmark");
538		let index = create_referendum::<T, I>(origin);
539		place_deposit::<T, I>(index);
540		make_passing::<T, I>(index);
541		skip_prepare_period::<T, I>(index);
542	}: nudge_referendum(RawOrigin::Root, index)
543	verify {
544		assert!(is_confirming::<T, I>(index));
545	}
546
547	nudge_referendum_begin_confirming {
548		let origin = T::SubmitOrigin::try_successful_origin(&RawOrigin::Root.into())
549			.expect("SubmitOrigin has no successful origin required for the benchmark");
550		let index = create_referendum::<T, I>(origin);
551		place_deposit::<T, I>(index);
552		skip_prepare_period::<T, I>(index);
553		nudge::<T, I>(index);
554		assert!(!is_confirming::<T, I>(index));
555		make_passing::<T, I>(index);
556	}: nudge_referendum(RawOrigin::Root, index)
557	verify {
558		assert!(is_confirming::<T, I>(index));
559	}
560
561	nudge_referendum_end_confirming {
562		let origin = T::SubmitOrigin::try_successful_origin(&RawOrigin::Root.into())
563			.expect("SubmitOrigin has no successful origin required for the benchmark");
564		let index = create_referendum::<T, I>(origin);
565		place_deposit::<T, I>(index);
566		skip_prepare_period::<T, I>(index);
567		make_passing::<T, I>(index);
568		nudge::<T, I>(index);
569		assert!(is_confirming::<T, I>(index));
570		make_failing::<T, I>(index);
571	}: nudge_referendum(RawOrigin::Root, index)
572	verify {
573		assert!(!is_confirming::<T, I>(index));
574	}
575
576	nudge_referendum_continue_not_confirming {
577		let origin = T::SubmitOrigin::try_successful_origin(&RawOrigin::Root.into())
578			.expect("SubmitOrigin has no successful origin required for the benchmark");
579		let index = create_referendum::<T, I>(origin);
580		place_deposit::<T, I>(index);
581		skip_prepare_period::<T, I>(index);
582		nudge::<T, I>(index);
583		assert!(!is_confirming::<T, I>(index));
584		let old_alarm = alarm_time::<T, I>(index);
585		make_passing_after::<T, I>(index, Perbill::from_percent(50));
586	}: nudge_referendum(RawOrigin::Root, index)
587	verify {
588		assert_ne!(old_alarm, alarm_time::<T, I>(index));
589		assert!(!is_confirming::<T, I>(index));
590	}
591
592	nudge_referendum_continue_confirming {
593		let origin = T::SubmitOrigin::try_successful_origin(&RawOrigin::Root.into())
594			.expect("SubmitOrigin has no successful origin required for the benchmark");
595		let index = create_referendum::<T, I>(origin);
596		place_deposit::<T, I>(index);
597		make_passing::<T, I>(index);
598		skip_prepare_period::<T, I>(index);
599		nudge::<T, I>(index);
600		assert!(is_confirming::<T, I>(index));
601		let old_alarm = alarm_time::<T, I>(index);
602	}: nudge_referendum(RawOrigin::Root, index)
603	verify {
604		assert!(is_confirming::<T, I>(index));
605	}
606
607	nudge_referendum_approved {
608		let origin = T::SubmitOrigin::try_successful_origin(&RawOrigin::Root.into())
609			.expect("SubmitOrigin has no successful origin required for the benchmark");
610		let index = create_referendum::<T, I>(origin);
611		place_deposit::<T, I>(index);
612		skip_prepare_period::<T, I>(index);
613		make_passing::<T, I>(index);
614		nudge::<T, I>(index);
615		skip_confirm_period::<T, I>(index);
616	}: nudge_referendum(RawOrigin::Root, index)
617	verify {
618		let info = ReferendumInfoFor::<T, I>::get(index).unwrap();
619		assert_matches!(info, ReferendumInfo::Approved(..));
620	}
621
622	nudge_referendum_rejected {
623		let origin = T::SubmitOrigin::try_successful_origin(&RawOrigin::Root.into())
624			.expect("SubmitOrigin has no successful origin required for the benchmark");
625		let index = create_referendum::<T, I>(origin);
626		place_deposit::<T, I>(index);
627		skip_prepare_period::<T, I>(index);
628		make_failing::<T, I>(index);
629		nudge::<T, I>(index);
630		skip_decision_period::<T, I>(index);
631	}: nudge_referendum(RawOrigin::Root, index)
632	verify {
633		let info = ReferendumInfoFor::<T, I>::get(index).unwrap();
634		assert_matches!(info, ReferendumInfo::Rejected(..));
635	}
636
637	set_some_metadata {
638		use alloc::borrow::Cow;
639		let origin = T::SubmitOrigin::try_successful_origin(&RawOrigin::Root.into())
640			.expect("SubmitOrigin has no successful origin required for the benchmark");
641		let index = create_referendum::<T, I>(origin.clone());
642		let hash = T::Preimages::note(Cow::from(vec![5, 6])).unwrap();
643	}: set_metadata<T::RuntimeOrigin>(origin, index, Some(hash))
644	verify {
645		assert_last_event::<T, I>(Event::MetadataSet { index, hash }.into());
646	}
647
648	clear_metadata {
649		use alloc::borrow::Cow;
650		let origin = T::SubmitOrigin::try_successful_origin(&RawOrigin::Root.into())
651			.expect("SubmitOrigin has no successful origin required for the benchmark");
652		let index = create_referendum::<T, I>(origin.clone());
653		let hash = T::Preimages::note(Cow::from(vec![6, 7, 8])).unwrap();
654		assert_ok!(
655			Referenda::<T, I>::set_metadata(origin.clone(), index, Some(hash))
656		);
657	}: set_metadata<T::RuntimeOrigin>(origin, index, None)
658	verify {
659		assert_last_event::<T, I>(Event::MetadataCleared { index, hash }.into());
660	}
661
662	impl_benchmark_test_suite!(
663		Referenda,
664		crate::mock::ExtBuilder::default().build(),
665		crate::mock::Test
666	);
667}