referrerpolicy=no-referrer-when-downgrade

pallet_referenda/
lib.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//! # Referenda Pallet
19//!
20//! ## Overview
21//!
22//! A pallet for executing referenda. No voting logic is present here, and the `Polling` and
23//! `PollStatus` traits are used to allow the voting logic (likely in a pallet) to be utilized.
24//!
25//! A referendum is a vote on whether a proposal should be dispatched from a particular origin. The
26//! origin is used to determine which one of several _tracks_ that a referendum happens under.
27//! Tracks each have their own configuration which governs the voting process and parameters.
28//!
29//! A referendum's lifecycle has three main stages: Preparation, deciding and conclusion.
30//! Referenda are considered "ongoing" immediately after submission until their eventual
31//! conclusion, and votes may be cast throughout.
32//!
33//! In order to progress from preparating to being decided, three things must be in place:
34//! - There must have been a *Decision Deposit* placed, an amount determined by the track. Anyone
35//! may place this deposit.
36//! - A period must have elapsed since submission of the referendum. This period is known as the
37//! *Preparation Period* and is determined by the track.
38//! - The track must not already be at capacity with referendum being decided. The maximum number of
39//! referenda which may be being decided simultaneously is determined by the track.
40//!
41//! In order to become concluded, one of three things must happen:
42//! - The referendum should remain in an unbroken _Passing_ state for a period of time. This
43//! is known as the _Confirmation Period_ and is determined by the track. A referendum is considered
44//! _Passing_ when there is a sufficiently high support and approval, given the amount of time it
45//! has been being decided. Generally the threshold for what counts as being "sufficiently high"
46//! will reduce over time. The curves setting these thresholds are determined by the track. In this
47//! case, the referendum is considered _Approved_ and the proposal is scheduled for dispatch.
48//! - The referendum reaches the end of its deciding phase outside not _Passing_. It ends in
49//! rejection and the proposal is not dispatched.
50//! - The referendum is cancelled.
51//!
52//! A general time-out is also in place and referenda which exist in preparation for too long may
53//! conclude without ever entering into a deciding stage.
54//!
55//! Once a referendum is concluded, the decision deposit may be refunded.
56//!
57//! ## Terms
58//! - *Support*: The number of aye-votes, pre-conviction, as a proportion of the total number of
59//!   pre-conviction votes able to be cast in the population.
60//!
61//! - [`Config`]
62//! - [`Call`]
63
64#![recursion_limit = "256"]
65#![cfg_attr(not(feature = "std"), no_std)]
66
67extern crate alloc;
68
69use alloc::boxed::Box;
70use codec::{Codec, Encode};
71use core::fmt::Debug;
72use frame_support::{
73	dispatch::DispatchResult,
74	ensure,
75	traits::{
76		schedule::{
77			v3::{Anon as ScheduleAnon, Named as ScheduleNamed},
78			DispatchTime,
79		},
80		Currency, LockIdentifier, OnUnbalanced, OriginTrait, PollStatus, Polling, QueryPreimage,
81		ReservableCurrency, StorePreimage, VoteTally,
82	},
83	BoundedVec,
84};
85use scale_info::TypeInfo;
86use sp_runtime::{
87	traits::{AtLeast32BitUnsigned, Bounded, Dispatchable, One, Saturating, Zero},
88	DispatchError, Perbill,
89};
90
91mod branch;
92pub mod migration;
93mod types;
94pub mod weights;
95
96use self::branch::{BeginDecidingBranch, OneFewerDecidingBranch, ServiceBranch};
97pub use self::{
98	pallet::*,
99	types::{
100		BalanceOf, BlockNumberFor, BoundedCallOf, CallOf, ConstTrackInfo, Curve, DecidingStatus,
101		DecidingStatusOf, Deposit, InsertSorted, NegativeImbalanceOf, PalletsOriginOf,
102		ReferendumIndex, ReferendumInfo, ReferendumInfoOf, ReferendumStatus, ReferendumStatusOf,
103		ScheduleAddressOf, StringLike, TallyOf, Track, TrackIdOf, TrackInfo, TrackInfoOf,
104		TracksInfo, VotesOf,
105	},
106	weights::WeightInfo,
107};
108pub use alloc::vec::Vec;
109use sp_runtime::traits::BlockNumberProvider;
110
111#[cfg(test)]
112mod mock;
113#[cfg(test)]
114mod tests;
115
116#[cfg(feature = "runtime-benchmarks")]
117pub mod benchmarking;
118
119pub use frame_support::traits::Get;
120
121const ASSEMBLY_ID: LockIdentifier = *b"assembly";
122
123#[frame_support::pallet]
124pub mod pallet {
125	use super::*;
126	use frame_support::{pallet_prelude::*, traits::EnsureOriginWithArg};
127	use frame_system::pallet_prelude::{
128		ensure_root, ensure_signed, ensure_signed_or_root, BlockNumberFor as SystemBlockNumberFor,
129		OriginFor,
130	};
131
132	/// The in-code storage version.
133	const STORAGE_VERSION: StorageVersion = StorageVersion::new(1);
134
135	#[pallet::pallet]
136	#[pallet::storage_version(STORAGE_VERSION)]
137	pub struct Pallet<T, I = ()>(_);
138
139	#[pallet::config]
140	pub trait Config<I: 'static = ()>: frame_system::Config + Sized {
141		// System level stuff.
142		type RuntimeCall: Parameter
143			+ Dispatchable<RuntimeOrigin = Self::RuntimeOrigin>
144			+ From<Call<Self, I>>
145			+ IsType<<Self as frame_system::Config>::RuntimeCall>
146			+ From<frame_system::Call<Self>>;
147		#[allow(deprecated)]
148		type RuntimeEvent: From<Event<Self, I>>
149			+ IsType<<Self as frame_system::Config>::RuntimeEvent>;
150		/// Weight information for extrinsics in this pallet.
151		type WeightInfo: WeightInfo;
152		/// The Scheduler.
153		type Scheduler: ScheduleAnon<
154				BlockNumberFor<Self, I>,
155				CallOf<Self, I>,
156				PalletsOriginOf<Self>,
157				Hasher = Self::Hashing,
158			> + ScheduleNamed<
159				BlockNumberFor<Self, I>,
160				CallOf<Self, I>,
161				PalletsOriginOf<Self>,
162				Hasher = Self::Hashing,
163			>;
164		/// Currency type for this pallet.
165		type Currency: ReservableCurrency<Self::AccountId>;
166		// Origins and unbalances.
167		/// Origin from which proposals may be submitted.
168		type SubmitOrigin: EnsureOriginWithArg<
169			Self::RuntimeOrigin,
170			PalletsOriginOf<Self>,
171			Success = Self::AccountId,
172		>;
173		/// Origin from which any vote may be cancelled.
174		type CancelOrigin: EnsureOrigin<Self::RuntimeOrigin>;
175		/// Origin from which any vote may be killed.
176		type KillOrigin: EnsureOrigin<Self::RuntimeOrigin>;
177		/// Handler for the unbalanced reduction when slashing a preimage deposit.
178		type Slash: OnUnbalanced<NegativeImbalanceOf<Self, I>>;
179		/// The counting type for votes. Usually just balance.
180		type Votes: AtLeast32BitUnsigned + Copy + Parameter + Member + MaxEncodedLen;
181		/// The tallying type.
182		type Tally: VoteTally<Self::Votes, TrackIdOf<Self, I>>
183			+ Clone
184			+ Codec
185			+ Eq
186			+ Debug
187			+ TypeInfo
188			+ MaxEncodedLen;
189
190		// Constants
191		/// The minimum amount to be used as a deposit for a public referendum proposal.
192		#[pallet::constant]
193		type SubmissionDeposit: Get<BalanceOf<Self, I>>;
194
195		/// Maximum size of the referendum queue for a single track.
196		#[pallet::constant]
197		type MaxQueued: Get<u32>;
198
199		/// The number of blocks after submission that a referendum must begin being decided by.
200		/// Once this passes, then anyone may cancel the referendum.
201		#[pallet::constant]
202		type UndecidingTimeout: Get<BlockNumberFor<Self, I>>;
203
204		/// Quantization level for the referendum wakeup scheduler. A higher number will result in
205		/// fewer storage reads/writes needed for smaller voters, but also result in delays to the
206		/// automatic referendum status changes. Explicit servicing instructions are unaffected.
207		#[pallet::constant]
208		type AlarmInterval: Get<BlockNumberFor<Self, I>>;
209
210		// The other stuff.
211		/// Information concerning the different referendum tracks.
212		type Tracks: TracksInfo<
213			BalanceOf<Self, I>,
214			BlockNumberFor<Self, I>,
215			RuntimeOrigin = <Self::RuntimeOrigin as OriginTrait>::PalletsOrigin,
216		>;
217
218		/// The preimage provider.
219		type Preimages: QueryPreimage<H = Self::Hashing> + StorePreimage;
220
221		/// Provider for the block number.
222		///
223		/// Normally this is the `frame_system` pallet.
224		type BlockNumberProvider: BlockNumberProvider;
225	}
226
227	#[pallet::extra_constants]
228	impl<T: Config<I>, I: 'static> Pallet<T, I> {
229		/// A list of tracks.
230		///
231		/// Note: if the tracks are dynamic, the value in the static metadata might be inaccurate.
232		#[pallet::constant_name(Tracks)]
233		fn tracks() -> Vec<(TrackIdOf<T, I>, ConstTrackInfo<BalanceOf<T, I>, BlockNumberFor<T, I>>)>
234		{
235			T::Tracks::tracks()
236				.map(|t| t.into_owned())
237				.map(|Track { id, info }| {
238					(
239						id,
240						ConstTrackInfo {
241							name: StringLike(info.name),
242							max_deciding: info.max_deciding,
243							decision_deposit: info.decision_deposit,
244							prepare_period: info.prepare_period,
245							decision_period: info.decision_period,
246							confirm_period: info.confirm_period,
247							min_enactment_period: info.min_enactment_period,
248							min_approval: info.min_approval,
249							min_support: info.min_support,
250						},
251					)
252				})
253				.collect()
254		}
255	}
256
257	/// The next free referendum index, aka the number of referenda started so far.
258	#[pallet::storage]
259	pub type ReferendumCount<T, I = ()> = StorageValue<_, ReferendumIndex, ValueQuery>;
260
261	/// Information concerning any given referendum.
262	#[pallet::storage]
263	pub type ReferendumInfoFor<T: Config<I>, I: 'static = ()> =
264		StorageMap<_, Blake2_128Concat, ReferendumIndex, ReferendumInfoOf<T, I>>;
265
266	/// The sorted list of referenda ready to be decided but not yet being decided, ordered by
267	/// conviction-weighted approvals.
268	///
269	/// This should be empty if `DecidingCount` is less than `TrackInfo::max_deciding`.
270	#[pallet::storage]
271	pub type TrackQueue<T: Config<I>, I: 'static = ()> = StorageMap<
272		_,
273		Twox64Concat,
274		TrackIdOf<T, I>,
275		BoundedVec<(ReferendumIndex, T::Votes), T::MaxQueued>,
276		ValueQuery,
277	>;
278
279	/// The number of referenda being decided currently.
280	#[pallet::storage]
281	pub type DecidingCount<T: Config<I>, I: 'static = ()> =
282		StorageMap<_, Twox64Concat, TrackIdOf<T, I>, u32, ValueQuery>;
283
284	/// The metadata is a general information concerning the referendum.
285	/// The `Hash` refers to the preimage of the `Preimages` provider which can be a JSON
286	/// dump or IPFS hash of a JSON file.
287	///
288	/// Consider a garbage collection for a metadata of finished referendums to `unrequest` (remove)
289	/// large preimages.
290	#[pallet::storage]
291	pub type MetadataOf<T: Config<I>, I: 'static = ()> =
292		StorageMap<_, Blake2_128Concat, ReferendumIndex, T::Hash>;
293
294	#[pallet::event]
295	#[pallet::generate_deposit(pub(super) fn deposit_event)]
296	pub enum Event<T: Config<I>, I: 'static = ()> {
297		/// A referendum has been submitted.
298		Submitted {
299			/// Index of the referendum.
300			index: ReferendumIndex,
301			/// The track (and by extension proposal dispatch origin) of this referendum.
302			track: TrackIdOf<T, I>,
303			/// The proposal for the referendum.
304			proposal: BoundedCallOf<T, I>,
305		},
306		/// The decision deposit has been placed.
307		DecisionDepositPlaced {
308			/// Index of the referendum.
309			index: ReferendumIndex,
310			/// The account who placed the deposit.
311			who: T::AccountId,
312			/// The amount placed by the account.
313			amount: BalanceOf<T, I>,
314		},
315		/// The decision deposit has been refunded.
316		DecisionDepositRefunded {
317			/// Index of the referendum.
318			index: ReferendumIndex,
319			/// The account who placed the deposit.
320			who: T::AccountId,
321			/// The amount placed by the account.
322			amount: BalanceOf<T, I>,
323		},
324		/// A deposit has been slashed.
325		DepositSlashed {
326			/// The account who placed the deposit.
327			who: T::AccountId,
328			/// The amount placed by the account.
329			amount: BalanceOf<T, I>,
330		},
331		/// A referendum has moved into the deciding phase.
332		DecisionStarted {
333			/// Index of the referendum.
334			index: ReferendumIndex,
335			/// The track (and by extension proposal dispatch origin) of this referendum.
336			track: TrackIdOf<T, I>,
337			/// The proposal for the referendum.
338			proposal: BoundedCallOf<T, I>,
339			/// The current tally of votes in this referendum.
340			tally: T::Tally,
341		},
342		ConfirmStarted {
343			/// Index of the referendum.
344			index: ReferendumIndex,
345		},
346		ConfirmAborted {
347			/// Index of the referendum.
348			index: ReferendumIndex,
349		},
350		/// A referendum has ended its confirmation phase and is ready for approval.
351		Confirmed {
352			/// Index of the referendum.
353			index: ReferendumIndex,
354			/// The final tally of votes in this referendum.
355			tally: T::Tally,
356		},
357		/// A referendum has been approved and its proposal has been scheduled.
358		Approved {
359			/// Index of the referendum.
360			index: ReferendumIndex,
361		},
362		/// A proposal has been rejected by referendum.
363		Rejected {
364			/// Index of the referendum.
365			index: ReferendumIndex,
366			/// The final tally of votes in this referendum.
367			tally: T::Tally,
368		},
369		/// A referendum has been timed out without being decided.
370		TimedOut {
371			/// Index of the referendum.
372			index: ReferendumIndex,
373			/// The final tally of votes in this referendum.
374			tally: T::Tally,
375		},
376		/// A referendum has been cancelled.
377		Cancelled {
378			/// Index of the referendum.
379			index: ReferendumIndex,
380			/// The final tally of votes in this referendum.
381			tally: T::Tally,
382		},
383		/// A referendum has been killed.
384		Killed {
385			/// Index of the referendum.
386			index: ReferendumIndex,
387			/// The final tally of votes in this referendum.
388			tally: T::Tally,
389		},
390		/// The submission deposit has been refunded.
391		SubmissionDepositRefunded {
392			/// Index of the referendum.
393			index: ReferendumIndex,
394			/// The account who placed the deposit.
395			who: T::AccountId,
396			/// The amount placed by the account.
397			amount: BalanceOf<T, I>,
398		},
399		/// Metadata for a referendum has been set.
400		MetadataSet {
401			/// Index of the referendum.
402			index: ReferendumIndex,
403			/// Preimage hash.
404			hash: T::Hash,
405		},
406		/// Metadata for a referendum has been cleared.
407		MetadataCleared {
408			/// Index of the referendum.
409			index: ReferendumIndex,
410			/// Preimage hash.
411			hash: T::Hash,
412		},
413	}
414
415	#[pallet::error]
416	pub enum Error<T, I = ()> {
417		/// Referendum is not ongoing.
418		NotOngoing,
419		/// Referendum's decision deposit is already paid.
420		HasDeposit,
421		/// The track identifier given was invalid.
422		BadTrack,
423		/// There are already a full complement of referenda in progress for this track.
424		Full,
425		/// The queue of the track is empty.
426		QueueEmpty,
427		/// The referendum index provided is invalid in this context.
428		BadReferendum,
429		/// There was nothing to do in the advancement.
430		NothingToDo,
431		/// No track exists for the proposal origin.
432		NoTrack,
433		/// Any deposit cannot be refunded until after the decision is over.
434		Unfinished,
435		/// The deposit refunder is not the depositor.
436		NoPermission,
437		/// The deposit cannot be refunded since none was made.
438		NoDeposit,
439		/// The referendum status is invalid for this operation.
440		BadStatus,
441		/// The preimage does not exist.
442		PreimageNotExist,
443		/// The preimage is stored with a different length than the one provided.
444		PreimageStoredWithDifferentLength,
445	}
446
447	#[pallet::hooks]
448	impl<T: Config<I>, I: 'static> Hooks<SystemBlockNumberFor<T>> for Pallet<T, I> {
449		#[cfg(feature = "try-runtime")]
450		fn try_state(_n: SystemBlockNumberFor<T>) -> Result<(), sp_runtime::TryRuntimeError> {
451			Self::do_try_state()?;
452			Ok(())
453		}
454
455		#[cfg(any(feature = "std", test))]
456		fn integrity_test() {
457			T::Tracks::check_integrity().expect("Static tracks configuration is valid.");
458		}
459	}
460
461	#[pallet::call]
462	impl<T: Config<I>, I: 'static> Pallet<T, I> {
463		/// Propose a referendum on a privileged action.
464		///
465		/// - `origin`: must be `SubmitOrigin` and the account must have `SubmissionDeposit` funds
466		///   available.
467		/// - `proposal_origin`: The origin from which the proposal should be executed.
468		/// - `proposal`: The proposal.
469		/// - `enactment_moment`: The moment that the proposal should be enacted.
470		///
471		/// Emits `Submitted`.
472		#[pallet::call_index(0)]
473		#[pallet::weight(T::WeightInfo::submit())]
474		pub fn submit(
475			origin: OriginFor<T>,
476			proposal_origin: Box<PalletsOriginOf<T>>,
477			proposal: BoundedCallOf<T, I>,
478			enactment_moment: DispatchTime<BlockNumberFor<T, I>>,
479		) -> DispatchResult {
480			let proposal_origin = *proposal_origin;
481			let who = T::SubmitOrigin::ensure_origin(origin, &proposal_origin)?;
482
483			// If the pre-image is already stored, ensure that it has the same length as given in
484			// `proposal`.
485			if let (Some(preimage_len), Some(proposal_len)) =
486				(proposal.lookup_hash().and_then(|h| T::Preimages::len(&h)), proposal.lookup_len())
487			{
488				if preimage_len != proposal_len {
489					return Err(Error::<T, I>::PreimageStoredWithDifferentLength.into())
490				}
491			}
492
493			let track =
494				T::Tracks::track_for(&proposal_origin).map_err(|_| Error::<T, I>::NoTrack)?;
495			let submission_deposit = Self::take_deposit(who, T::SubmissionDeposit::get())?;
496			let index = ReferendumCount::<T, I>::mutate(|x| {
497				let r = *x;
498				*x += 1;
499				r
500			});
501			let now = T::BlockNumberProvider::current_block_number();
502			let nudge_call =
503				T::Preimages::bound(CallOf::<T, I>::from(Call::nudge_referendum { index }))?;
504			let status = ReferendumStatus {
505				track,
506				origin: proposal_origin,
507				proposal: proposal.clone(),
508				enactment: enactment_moment,
509				submitted: now,
510				submission_deposit,
511				decision_deposit: None,
512				deciding: None,
513				tally: TallyOf::<T, I>::new(track),
514				in_queue: false,
515				alarm: Self::set_alarm(nudge_call, now.saturating_add(T::UndecidingTimeout::get())),
516			};
517			ReferendumInfoFor::<T, I>::insert(index, ReferendumInfo::Ongoing(status));
518
519			Self::deposit_event(Event::<T, I>::Submitted { index, track, proposal });
520			Ok(())
521		}
522
523		/// Post the Decision Deposit for a referendum.
524		///
525		/// - `origin`: must be `Signed` and the account must have funds available for the
526		///   referendum's track's Decision Deposit.
527		/// - `index`: The index of the submitted referendum whose Decision Deposit is yet to be
528		///   posted.
529		///
530		/// Emits `DecisionDepositPlaced`.
531		#[pallet::call_index(1)]
532		#[pallet::weight(ServiceBranch::max_weight_of_deposit::<T, I>())]
533		pub fn place_decision_deposit(
534			origin: OriginFor<T>,
535			index: ReferendumIndex,
536		) -> DispatchResultWithPostInfo {
537			let who = ensure_signed(origin)?;
538			let mut status = Self::ensure_ongoing(index)?;
539			ensure!(status.decision_deposit.is_none(), Error::<T, I>::HasDeposit);
540			let track = T::Tracks::info(status.track).ok_or(Error::<T, I>::NoTrack)?;
541			status.decision_deposit =
542				Some(Self::take_deposit(who.clone(), track.decision_deposit)?);
543			let now = T::BlockNumberProvider::current_block_number();
544			let (info, _, branch) = Self::service_referendum(now, index, status);
545			ReferendumInfoFor::<T, I>::insert(index, info);
546			let e =
547				Event::<T, I>::DecisionDepositPlaced { index, who, amount: track.decision_deposit };
548			Self::deposit_event(e);
549			Ok(branch.weight_of_deposit::<T, I>().into())
550		}
551
552		/// Refund the Decision Deposit for a closed referendum back to the depositor.
553		///
554		/// - `origin`: must be `Signed` or `Root`.
555		/// - `index`: The index of a closed referendum whose Decision Deposit has not yet been
556		///   refunded.
557		///
558		/// Emits `DecisionDepositRefunded`.
559		#[pallet::call_index(2)]
560		#[pallet::weight(T::WeightInfo::refund_decision_deposit())]
561		pub fn refund_decision_deposit(
562			origin: OriginFor<T>,
563			index: ReferendumIndex,
564		) -> DispatchResult {
565			ensure_signed_or_root(origin)?;
566			let mut info =
567				ReferendumInfoFor::<T, I>::get(index).ok_or(Error::<T, I>::BadReferendum)?;
568			let deposit = info
569				.take_decision_deposit()
570				.map_err(|_| Error::<T, I>::Unfinished)?
571				.ok_or(Error::<T, I>::NoDeposit)?;
572			Self::refund_deposit(Some(deposit.clone()));
573			ReferendumInfoFor::<T, I>::insert(index, info);
574			let e = Event::<T, I>::DecisionDepositRefunded {
575				index,
576				who: deposit.who,
577				amount: deposit.amount,
578			};
579			Self::deposit_event(e);
580			Ok(())
581		}
582
583		/// Cancel an ongoing referendum.
584		///
585		/// - `origin`: must be the `CancelOrigin`.
586		/// - `index`: The index of the referendum to be cancelled.
587		///
588		/// Emits `Cancelled`.
589		#[pallet::call_index(3)]
590		#[pallet::weight(T::WeightInfo::cancel())]
591		pub fn cancel(origin: OriginFor<T>, index: ReferendumIndex) -> DispatchResult {
592			T::CancelOrigin::ensure_origin(origin)?;
593			let status = Self::ensure_ongoing(index)?;
594			if let Some((_, last_alarm)) = status.alarm {
595				let _ = T::Scheduler::cancel(last_alarm);
596			}
597			Self::note_one_fewer_deciding(status.track);
598			Self::deposit_event(Event::<T, I>::Cancelled { index, tally: status.tally });
599			let info = ReferendumInfo::Cancelled(
600				T::BlockNumberProvider::current_block_number(),
601				Some(status.submission_deposit),
602				status.decision_deposit,
603			);
604			ReferendumInfoFor::<T, I>::insert(index, info);
605			Ok(())
606		}
607
608		/// Cancel an ongoing referendum and slash the deposits.
609		///
610		/// - `origin`: must be the `KillOrigin`.
611		/// - `index`: The index of the referendum to be cancelled.
612		///
613		/// Emits `Killed` and `DepositSlashed`.
614		#[pallet::call_index(4)]
615		#[pallet::weight(T::WeightInfo::kill())]
616		pub fn kill(origin: OriginFor<T>, index: ReferendumIndex) -> DispatchResult {
617			T::KillOrigin::ensure_origin(origin)?;
618			let status = Self::ensure_ongoing(index)?;
619			if let Some((_, last_alarm)) = status.alarm {
620				let _ = T::Scheduler::cancel(last_alarm);
621			}
622			Self::note_one_fewer_deciding(status.track);
623			Self::deposit_event(Event::<T, I>::Killed { index, tally: status.tally });
624			Self::slash_deposit(Some(status.submission_deposit.clone()));
625			Self::slash_deposit(status.decision_deposit.clone());
626			Self::do_clear_metadata(index);
627			let info = ReferendumInfo::Killed(T::BlockNumberProvider::current_block_number());
628			ReferendumInfoFor::<T, I>::insert(index, info);
629			Ok(())
630		}
631
632		/// Advance a referendum onto its next logical state. Only used internally.
633		///
634		/// - `origin`: must be `Root`.
635		/// - `index`: the referendum to be advanced.
636		#[pallet::call_index(5)]
637		#[pallet::weight(ServiceBranch::max_weight_of_nudge::<T, I>())]
638		pub fn nudge_referendum(
639			origin: OriginFor<T>,
640			index: ReferendumIndex,
641		) -> DispatchResultWithPostInfo {
642			ensure_root(origin)?;
643			let now = T::BlockNumberProvider::current_block_number();
644			let mut status = Self::ensure_ongoing(index)?;
645			// This is our wake-up, so we can disregard the alarm.
646			status.alarm = None;
647			let (info, dirty, branch) = Self::service_referendum(now, index, status);
648			if dirty {
649				ReferendumInfoFor::<T, I>::insert(index, info);
650			}
651			Ok(Some(branch.weight_of_nudge::<T, I>()).into())
652		}
653
654		/// Advance a track onto its next logical state. Only used internally.
655		///
656		/// - `origin`: must be `Root`.
657		/// - `track`: the track to be advanced.
658		///
659		/// Action item for when there is now one fewer referendum in the deciding phase and the
660		/// `DecidingCount` is not yet updated. This means that we should either:
661		/// - begin deciding another referendum (and leave `DecidingCount` alone); or
662		/// - decrement `DecidingCount`.
663		#[pallet::call_index(6)]
664		#[pallet::weight(OneFewerDecidingBranch::max_weight::<T, I>())]
665		pub fn one_fewer_deciding(
666			origin: OriginFor<T>,
667			track: TrackIdOf<T, I>,
668		) -> DispatchResultWithPostInfo {
669			ensure_root(origin)?;
670			let track_info = T::Tracks::info(track).ok_or(Error::<T, I>::BadTrack)?;
671			let mut track_queue = TrackQueue::<T, I>::get(track);
672			let branch =
673				if let Some((index, mut status)) = Self::next_for_deciding(&mut track_queue) {
674					let now = T::BlockNumberProvider::current_block_number();
675					let (maybe_alarm, branch) =
676						Self::begin_deciding(&mut status, index, now, &track_info);
677					if let Some(set_alarm) = maybe_alarm {
678						Self::ensure_alarm_at(&mut status, index, set_alarm);
679					}
680					ReferendumInfoFor::<T, I>::insert(index, ReferendumInfo::Ongoing(status));
681					TrackQueue::<T, I>::insert(track, track_queue);
682					branch.into()
683				} else {
684					DecidingCount::<T, I>::mutate(track, |x| x.saturating_dec());
685					OneFewerDecidingBranch::QueueEmpty
686				};
687			Ok(Some(branch.weight::<T, I>()).into())
688		}
689
690		/// Refund the Submission Deposit for a closed referendum back to the depositor.
691		///
692		/// - `origin`: must be `Signed` or `Root`.
693		/// - `index`: The index of a closed referendum whose Submission Deposit has not yet been
694		///   refunded.
695		///
696		/// Emits `SubmissionDepositRefunded`.
697		#[pallet::call_index(7)]
698		#[pallet::weight(T::WeightInfo::refund_submission_deposit())]
699		pub fn refund_submission_deposit(
700			origin: OriginFor<T>,
701			index: ReferendumIndex,
702		) -> DispatchResult {
703			ensure_signed_or_root(origin)?;
704			let mut info =
705				ReferendumInfoFor::<T, I>::get(index).ok_or(Error::<T, I>::BadReferendum)?;
706			let deposit = info
707				.take_submission_deposit()
708				.map_err(|_| Error::<T, I>::BadStatus)?
709				.ok_or(Error::<T, I>::NoDeposit)?;
710			Self::refund_deposit(Some(deposit.clone()));
711			ReferendumInfoFor::<T, I>::insert(index, info);
712			let e = Event::<T, I>::SubmissionDepositRefunded {
713				index,
714				who: deposit.who,
715				amount: deposit.amount,
716			};
717			Self::deposit_event(e);
718			Ok(())
719		}
720
721		/// Set or clear metadata of a referendum.
722		///
723		/// Parameters:
724		/// - `origin`: Must be `Signed` by a creator of a referendum or by anyone to clear a
725		///   metadata of a finished referendum.
726		/// - `index`:  The index of a referendum to set or clear metadata for.
727		/// - `maybe_hash`: The hash of an on-chain stored preimage. `None` to clear a metadata.
728		#[pallet::call_index(8)]
729		#[pallet::weight(
730			maybe_hash.map_or(
731				T::WeightInfo::clear_metadata(), |_| T::WeightInfo::set_some_metadata())
732			)]
733		pub fn set_metadata(
734			origin: OriginFor<T>,
735			index: ReferendumIndex,
736			maybe_hash: Option<T::Hash>,
737		) -> DispatchResult {
738			let who = ensure_signed(origin)?;
739			if let Some(hash) = maybe_hash {
740				let status = Self::ensure_ongoing(index)?;
741				ensure!(status.submission_deposit.who == who, Error::<T, I>::NoPermission);
742				ensure!(T::Preimages::len(&hash).is_some(), Error::<T, I>::PreimageNotExist);
743				MetadataOf::<T, I>::insert(index, hash);
744				Self::deposit_event(Event::<T, I>::MetadataSet { index, hash });
745				Ok(())
746			} else {
747				if let Some(status) = Self::ensure_ongoing(index).ok() {
748					ensure!(status.submission_deposit.who == who, Error::<T, I>::NoPermission);
749				}
750				Self::do_clear_metadata(index);
751				Ok(())
752			}
753		}
754	}
755}
756
757impl<T: Config<I>, I: 'static> Polling<T::Tally> for Pallet<T, I> {
758	type Index = ReferendumIndex;
759	type Votes = VotesOf<T, I>;
760	type Moment = BlockNumberFor<T, I>;
761	type Class = TrackIdOf<T, I>;
762
763	fn classes() -> Vec<Self::Class> {
764		T::Tracks::track_ids().collect()
765	}
766
767	fn access_poll<R>(
768		index: Self::Index,
769		f: impl FnOnce(PollStatus<&mut T::Tally, BlockNumberFor<T, I>, TrackIdOf<T, I>>) -> R,
770	) -> R {
771		match ReferendumInfoFor::<T, I>::get(index) {
772			Some(ReferendumInfo::Ongoing(mut status)) => {
773				let result = f(PollStatus::Ongoing(&mut status.tally, status.track));
774				let now = T::BlockNumberProvider::current_block_number();
775				Self::ensure_alarm_at(&mut status, index, now + One::one());
776				ReferendumInfoFor::<T, I>::insert(index, ReferendumInfo::Ongoing(status));
777				result
778			},
779			Some(ReferendumInfo::Approved(end, ..)) => f(PollStatus::Completed(end, true)),
780			Some(ReferendumInfo::Rejected(end, ..)) => f(PollStatus::Completed(end, false)),
781			_ => f(PollStatus::None),
782		}
783	}
784
785	fn try_access_poll<R>(
786		index: Self::Index,
787		f: impl FnOnce(
788			PollStatus<&mut T::Tally, BlockNumberFor<T, I>, TrackIdOf<T, I>>,
789		) -> Result<R, DispatchError>,
790	) -> Result<R, DispatchError> {
791		match ReferendumInfoFor::<T, I>::get(index) {
792			Some(ReferendumInfo::Ongoing(mut status)) => {
793				let result = f(PollStatus::Ongoing(&mut status.tally, status.track))?;
794				let now = T::BlockNumberProvider::current_block_number();
795				Self::ensure_alarm_at(&mut status, index, now + One::one());
796				ReferendumInfoFor::<T, I>::insert(index, ReferendumInfo::Ongoing(status));
797				Ok(result)
798			},
799			Some(ReferendumInfo::Approved(end, ..)) => f(PollStatus::Completed(end, true)),
800			Some(ReferendumInfo::Rejected(end, ..)) => f(PollStatus::Completed(end, false)),
801			_ => f(PollStatus::None),
802		}
803	}
804
805	fn as_ongoing(index: Self::Index) -> Option<(T::Tally, TrackIdOf<T, I>)> {
806		Self::ensure_ongoing(index).ok().map(|x| (x.tally, x.track))
807	}
808
809	#[cfg(feature = "runtime-benchmarks")]
810	fn create_ongoing(class: Self::Class) -> Result<Self::Index, ()> {
811		let index = ReferendumCount::<T, I>::mutate(|x| {
812			let r = *x;
813			*x += 1;
814			r
815		});
816		let now = T::BlockNumberProvider::current_block_number();
817		let dummy_account_id =
818			codec::Decode::decode(&mut sp_runtime::traits::TrailingZeroInput::new(&b"dummy"[..]))
819				.expect("infinite length input; no invalid inputs for type; qed");
820		let mut status = ReferendumStatusOf::<T, I> {
821			track: class,
822			origin: frame_support::dispatch::RawOrigin::Root.into(),
823			proposal: T::Preimages::bound(CallOf::<T, I>::from(Call::nudge_referendum { index }))
824				.map_err(|_| ())?,
825			enactment: DispatchTime::After(Zero::zero()),
826			submitted: now,
827			submission_deposit: Deposit { who: dummy_account_id, amount: Zero::zero() },
828			decision_deposit: None,
829			deciding: None,
830			tally: TallyOf::<T, I>::new(class),
831			in_queue: false,
832			alarm: None,
833		};
834
835		Self::ensure_alarm_at(&mut status, index, sp_runtime::traits::Bounded::max_value());
836		ReferendumInfoFor::<T, I>::insert(index, ReferendumInfo::Ongoing(status));
837		Ok(index)
838	}
839
840	#[cfg(feature = "runtime-benchmarks")]
841	fn end_ongoing(index: Self::Index, approved: bool) -> Result<(), ()> {
842		let mut status = Self::ensure_ongoing(index).map_err(|_| ())?;
843		Self::ensure_no_alarm(&mut status);
844		Self::note_one_fewer_deciding(status.track);
845		let now = T::BlockNumberProvider::current_block_number();
846		let info = if approved {
847			ReferendumInfo::Approved(now, Some(status.submission_deposit), status.decision_deposit)
848		} else {
849			ReferendumInfo::Rejected(now, Some(status.submission_deposit), status.decision_deposit)
850		};
851		ReferendumInfoFor::<T, I>::insert(index, info);
852		Ok(())
853	}
854
855	#[cfg(feature = "runtime-benchmarks")]
856	fn max_ongoing() -> (Self::Class, u32) {
857		let r = T::Tracks::tracks()
858			.max_by_key(|t| t.info.max_deciding)
859			.expect("Always one class");
860		(r.id, r.info.max_deciding)
861	}
862}
863
864impl<T: Config<I>, I: 'static> Pallet<T, I> {
865	/// Check that referendum `index` is in the `Ongoing` state and return the `ReferendumStatus`
866	/// value, or `Err` otherwise.
867	pub fn ensure_ongoing(
868		index: ReferendumIndex,
869	) -> Result<ReferendumStatusOf<T, I>, DispatchError> {
870		match ReferendumInfoFor::<T, I>::get(index) {
871			Some(ReferendumInfo::Ongoing(status)) => Ok(status),
872			_ => Err(Error::<T, I>::NotOngoing.into()),
873		}
874	}
875
876	/// Returns whether the referendum is passing.
877	/// Referendum must be ongoing and its track must exist.
878	pub fn is_referendum_passing(ref_index: ReferendumIndex) -> Result<bool, DispatchError> {
879		let info = ReferendumInfoFor::<T, I>::get(ref_index).ok_or(Error::<T, I>::BadReferendum)?;
880		match info {
881			ReferendumInfo::Ongoing(status) => {
882				let track = T::Tracks::info(status.track).ok_or(Error::<T, I>::NoTrack)?;
883				let elapsed = if let Some(deciding) = status.deciding {
884					T::BlockNumberProvider::current_block_number().saturating_sub(deciding.since)
885				} else {
886					Zero::zero()
887				};
888				Ok(Self::is_passing(
889					&status.tally,
890					elapsed,
891					track.decision_period,
892					&track.min_support,
893					&track.min_approval,
894					status.track,
895				))
896			},
897			_ => Err(Error::<T, I>::NotOngoing.into()),
898		}
899	}
900
901	// Enqueue a proposal from a referendum which has presumably passed.
902	fn schedule_enactment(
903		index: ReferendumIndex,
904		track: &TrackInfoOf<T, I>,
905		desired: DispatchTime<BlockNumberFor<T, I>>,
906		origin: PalletsOriginOf<T>,
907		call: BoundedCallOf<T, I>,
908	) {
909		let now = T::BlockNumberProvider::current_block_number();
910		// Earliest allowed block is always at minimum the next block.
911		let earliest_allowed = now.saturating_add(track.min_enactment_period.max(One::one()));
912		let desired = desired.evaluate(now);
913		let ok = T::Scheduler::schedule_named(
914			(ASSEMBLY_ID, "enactment", index).using_encoded(sp_io::hashing::blake2_256),
915			DispatchTime::At(desired.max(earliest_allowed)),
916			None,
917			63,
918			origin,
919			call,
920		)
921		.is_ok();
922		debug_assert!(ok, "LOGIC ERROR: bake_referendum/schedule_named failed");
923	}
924
925	/// Set an alarm to dispatch `call` at block number `when`.
926	fn set_alarm(
927		call: BoundedCallOf<T, I>,
928		when: BlockNumberFor<T, I>,
929	) -> Option<(BlockNumberFor<T, I>, ScheduleAddressOf<T, I>)> {
930		let alarm_interval = T::AlarmInterval::get().max(One::one());
931		// Alarm must go off no earlier than `when`.
932		// This rounds `when` upwards to the next multiple of `alarm_interval`.
933		let when = (when.saturating_add(alarm_interval.saturating_sub(One::one())) /
934			alarm_interval)
935			.saturating_mul(alarm_interval);
936		let result = T::Scheduler::schedule(
937			DispatchTime::At(when),
938			None,
939			128u8,
940			frame_system::RawOrigin::Root.into(),
941			call,
942		);
943		debug_assert!(
944			result.is_ok(),
945			"Unable to schedule a new alarm at #{:?} (now: #{:?}), scheduler error: `{:?}`",
946			when,
947			T::BlockNumberProvider::current_block_number(),
948			result.unwrap_err(),
949		);
950		result.ok().map(|x| (when, x))
951	}
952
953	/// Mutate a referendum's `status` into the correct deciding state.
954	///
955	/// - `now` is the current block number.
956	/// - `track` is the track info for the referendum.
957	///
958	/// This will properly set up the `confirming` item.
959	fn begin_deciding(
960		status: &mut ReferendumStatusOf<T, I>,
961		index: ReferendumIndex,
962		now: BlockNumberFor<T, I>,
963		track: &TrackInfoOf<T, I>,
964	) -> (Option<BlockNumberFor<T, I>>, BeginDecidingBranch) {
965		let is_passing = Self::is_passing(
966			&status.tally,
967			Zero::zero(),
968			track.decision_period,
969			&track.min_support,
970			&track.min_approval,
971			status.track,
972		);
973		status.in_queue = false;
974		Self::deposit_event(Event::<T, I>::DecisionStarted {
975			index,
976			tally: status.tally.clone(),
977			proposal: status.proposal.clone(),
978			track: status.track,
979		});
980		let confirming = if is_passing {
981			Self::deposit_event(Event::<T, I>::ConfirmStarted { index });
982			Some(now.saturating_add(track.confirm_period))
983		} else {
984			None
985		};
986		let deciding_status = DecidingStatus { since: now, confirming };
987		let alarm = Self::decision_time(&deciding_status, &status.tally, status.track, track)
988			.max(now.saturating_add(One::one()));
989		status.deciding = Some(deciding_status);
990		let branch =
991			if is_passing { BeginDecidingBranch::Passing } else { BeginDecidingBranch::Failing };
992		(Some(alarm), branch)
993	}
994
995	/// If it returns `Some`, deciding has begun and it needs waking at the given block number. The
996	/// second item is the flag for whether it is confirming or not.
997	///
998	/// If `None`, then it is queued and should be nudged automatically as the queue gets drained.
999	fn ready_for_deciding(
1000		now: BlockNumberFor<T, I>,
1001		track: &TrackInfoOf<T, I>,
1002		index: ReferendumIndex,
1003		status: &mut ReferendumStatusOf<T, I>,
1004	) -> (Option<BlockNumberFor<T, I>>, ServiceBranch) {
1005		let deciding_count = DecidingCount::<T, I>::get(status.track);
1006		if deciding_count < track.max_deciding {
1007			// Begin deciding.
1008			DecidingCount::<T, I>::insert(status.track, deciding_count.saturating_add(1));
1009			let r = Self::begin_deciding(status, index, now, track);
1010			(r.0, r.1.into())
1011		} else {
1012			// Add to queue.
1013			let item = (index, status.tally.ayes(status.track));
1014			status.in_queue = true;
1015			TrackQueue::<T, I>::mutate(status.track, |q| q.insert_sorted_by_key(item, |x| x.1));
1016			(None, ServiceBranch::Queued)
1017		}
1018	}
1019
1020	/// Grab the index and status for the referendum which is the highest priority of those for the
1021	/// given track which are ready for being decided.
1022	fn next_for_deciding(
1023		track_queue: &mut BoundedVec<(u32, VotesOf<T, I>), T::MaxQueued>,
1024	) -> Option<(ReferendumIndex, ReferendumStatusOf<T, I>)> {
1025		loop {
1026			let (index, _) = track_queue.pop()?;
1027			match Self::ensure_ongoing(index) {
1028				Ok(s) => return Some((index, s)),
1029				Err(_) => {}, // referendum already timedout or was cancelled.
1030			}
1031		}
1032	}
1033
1034	/// Schedule a call to `one_fewer_deciding` function via the dispatchable
1035	/// `defer_one_fewer_deciding`. We could theoretically call it immediately (and it would be
1036	/// overall more efficient), however the weights become rather less easy to measure.
1037	fn note_one_fewer_deciding(track: TrackIdOf<T, I>) {
1038		// Set an alarm call for the next block to nudge the track along.
1039		let now = T::BlockNumberProvider::current_block_number();
1040		let next_block = now + One::one();
1041		let call = match T::Preimages::bound(CallOf::<T, I>::from(Call::one_fewer_deciding {
1042			track,
1043		})) {
1044			Ok(c) => c,
1045			Err(_) => {
1046				debug_assert!(false, "Unable to create a bounded call from `one_fewer_deciding`??",);
1047				return
1048			},
1049		};
1050		Self::set_alarm(call, next_block);
1051	}
1052
1053	/// Ensure that a `service_referendum` alarm happens for the referendum `index` at `alarm`.
1054	///
1055	/// This will do nothing if the alarm is already set.
1056	///
1057	/// Returns `false` if nothing changed.
1058	fn ensure_alarm_at(
1059		status: &mut ReferendumStatusOf<T, I>,
1060		index: ReferendumIndex,
1061		alarm: BlockNumberFor<T, I>,
1062	) -> bool {
1063		if status.alarm.as_ref().map_or(true, |&(when, _)| when != alarm) {
1064			// Either no alarm or one that was different
1065			Self::ensure_no_alarm(status);
1066			let call =
1067				match T::Preimages::bound(CallOf::<T, I>::from(Call::nudge_referendum { index })) {
1068					Ok(c) => c,
1069					Err(_) => {
1070						debug_assert!(
1071							false,
1072							"Unable to create a bounded call from `nudge_referendum`??",
1073						);
1074						return false
1075					},
1076				};
1077			status.alarm = Self::set_alarm(call, alarm);
1078			true
1079		} else {
1080			false
1081		}
1082	}
1083
1084	/// Advance the state of a referendum, which comes down to:
1085	/// - If it's ready to be decided, start deciding;
1086	/// - If it's not ready to be decided and non-deciding timeout has passed, fail;
1087	/// - If it's ongoing and passing, ensure confirming; if at end of confirmation period, pass.
1088	/// - If it's ongoing and not passing, stop confirming; if it has reached end time, fail.
1089	///
1090	/// Weight will be a bit different depending on what it does, but it's designed so as not to
1091	/// differ dramatically, especially if `MaxQueue` is kept small. In particular _there are no
1092	/// balance operations in here_.
1093	///
1094	/// In terms of storage, every call to it is expected to access:
1095	/// - The scheduler, either to insert, remove or alter an entry;
1096	/// - `TrackQueue`, which should be a `BoundedVec` with a low limit (8-16);
1097	/// - `DecidingCount`.
1098	///
1099	/// Both of the two storage items will only have as many items as there are different tracks,
1100	/// perhaps around 10 and should be whitelisted.
1101	///
1102	/// The heaviest branch is likely to be when a proposal is placed into, or moved within, the
1103	/// `TrackQueue`. Basically this happens when a referendum is in the deciding queue and receives
1104	/// a vote, or when it moves into the deciding queue.
1105	fn service_referendum(
1106		now: BlockNumberFor<T, I>,
1107		index: ReferendumIndex,
1108		mut status: ReferendumStatusOf<T, I>,
1109	) -> (ReferendumInfoOf<T, I>, bool, ServiceBranch) {
1110		let mut dirty = false;
1111		// Should it begin being decided?
1112		let track = match T::Tracks::info(status.track) {
1113			Some(x) => x,
1114			None => return (ReferendumInfo::Ongoing(status), false, ServiceBranch::Fail),
1115		};
1116		// Default the alarm to the end of the world.
1117		let timeout = status.submitted + T::UndecidingTimeout::get();
1118		let mut alarm = BlockNumberFor::<T, I>::max_value();
1119		let branch;
1120		match &mut status.deciding {
1121			None => {
1122				// Are we already queued for deciding?
1123				if status.in_queue {
1124					// Does our position in the queue need updating?
1125					let ayes = status.tally.ayes(status.track);
1126					let mut queue = TrackQueue::<T, I>::get(status.track);
1127					let maybe_old_pos = queue.iter().position(|(x, _)| *x == index);
1128					let new_pos = queue.binary_search_by_key(&ayes, |x| x.1).unwrap_or_else(|x| x);
1129					branch = if maybe_old_pos.is_none() && new_pos > 0 {
1130						// Just insert.
1131						let _ = queue.force_insert_keep_right(new_pos, (index, ayes));
1132						ServiceBranch::RequeuedInsertion
1133					} else if let Some(old_pos) = maybe_old_pos {
1134						// We were in the queue - slide into the correct position.
1135						queue[old_pos].1 = ayes;
1136						queue.slide(old_pos, new_pos);
1137						ServiceBranch::RequeuedSlide
1138					} else {
1139						ServiceBranch::NotQueued
1140					};
1141					TrackQueue::<T, I>::insert(status.track, queue);
1142				} else {
1143					// Are we ready for deciding?
1144					branch = if status.decision_deposit.is_some() {
1145						let prepare_end = status.submitted.saturating_add(track.prepare_period);
1146						if now >= prepare_end {
1147							let (maybe_alarm, branch) =
1148								Self::ready_for_deciding(now, &track, index, &mut status);
1149							if let Some(set_alarm) = maybe_alarm {
1150								alarm = alarm.min(set_alarm);
1151							}
1152							dirty = true;
1153							branch
1154						} else {
1155							alarm = alarm.min(prepare_end);
1156							ServiceBranch::Preparing
1157						}
1158					} else {
1159						alarm = timeout;
1160						ServiceBranch::NoDeposit
1161					}
1162				}
1163				// If we didn't move into being decided, then check the timeout.
1164				if status.deciding.is_none() && now >= timeout && !status.in_queue {
1165					// Too long without being decided - end it.
1166					Self::ensure_no_alarm(&mut status);
1167					Self::deposit_event(Event::<T, I>::TimedOut { index, tally: status.tally });
1168					return (
1169						ReferendumInfo::TimedOut(
1170							now,
1171							Some(status.submission_deposit),
1172							status.decision_deposit,
1173						),
1174						true,
1175						ServiceBranch::TimedOut,
1176					)
1177				}
1178			},
1179			Some(deciding) => {
1180				let is_passing = Self::is_passing(
1181					&status.tally,
1182					now.saturating_sub(deciding.since),
1183					track.decision_period,
1184					&track.min_support,
1185					&track.min_approval,
1186					status.track,
1187				);
1188				branch = if is_passing {
1189					match deciding.confirming {
1190						Some(t) if now >= t => {
1191							// Passed!
1192							Self::ensure_no_alarm(&mut status);
1193							Self::note_one_fewer_deciding(status.track);
1194							let (desired, call) = (status.enactment, status.proposal);
1195							Self::schedule_enactment(index, &track, desired, status.origin, call);
1196							Self::deposit_event(Event::<T, I>::Confirmed {
1197								index,
1198								tally: status.tally,
1199							});
1200							return (
1201								ReferendumInfo::Approved(
1202									now,
1203									Some(status.submission_deposit),
1204									status.decision_deposit,
1205								),
1206								true,
1207								ServiceBranch::Approved,
1208							)
1209						},
1210						Some(_) => ServiceBranch::ContinueConfirming,
1211						None => {
1212							// Start confirming
1213							dirty = true;
1214							deciding.confirming = Some(now.saturating_add(track.confirm_period));
1215							Self::deposit_event(Event::<T, I>::ConfirmStarted { index });
1216							ServiceBranch::BeginConfirming
1217						},
1218					}
1219				} else {
1220					if now >= deciding.since.saturating_add(track.decision_period) {
1221						// Failed!
1222						Self::ensure_no_alarm(&mut status);
1223						Self::note_one_fewer_deciding(status.track);
1224						Self::deposit_event(Event::<T, I>::Rejected { index, tally: status.tally });
1225						return (
1226							ReferendumInfo::Rejected(
1227								now,
1228								Some(status.submission_deposit),
1229								status.decision_deposit,
1230							),
1231							true,
1232							ServiceBranch::Rejected,
1233						)
1234					}
1235					if deciding.confirming.is_some() {
1236						// Stop confirming
1237						dirty = true;
1238						deciding.confirming = None;
1239						Self::deposit_event(Event::<T, I>::ConfirmAborted { index });
1240						ServiceBranch::EndConfirming
1241					} else {
1242						ServiceBranch::ContinueNotConfirming
1243					}
1244				};
1245				alarm = Self::decision_time(deciding, &status.tally, status.track, &track);
1246			},
1247		}
1248
1249		let dirty_alarm = if alarm < BlockNumberFor::<T, I>::max_value() {
1250			Self::ensure_alarm_at(&mut status, index, alarm)
1251		} else {
1252			Self::ensure_no_alarm(&mut status)
1253		};
1254		(ReferendumInfo::Ongoing(status), dirty_alarm || dirty, branch)
1255	}
1256
1257	/// Determine the point at which a referendum will be accepted, move into confirmation with the
1258	/// given `tally` or end with rejection (whichever happens sooner).
1259	fn decision_time(
1260		deciding: &DecidingStatusOf<T, I>,
1261		tally: &T::Tally,
1262		track_id: TrackIdOf<T, I>,
1263		track: &TrackInfoOf<T, I>,
1264	) -> BlockNumberFor<T, I> {
1265		deciding.confirming.unwrap_or_else(|| {
1266			// Set alarm to the point where the current voting would make it pass.
1267			let approval = tally.approval(track_id);
1268			let support = tally.support(track_id);
1269			let until_approval = track.min_approval.delay(approval);
1270			let until_support = track.min_support.delay(support);
1271			let offset = until_support.max(until_approval);
1272			deciding.since.saturating_add(offset.mul_ceil(track.decision_period))
1273		})
1274	}
1275
1276	/// Cancel the alarm in `status`, if one exists.
1277	fn ensure_no_alarm(status: &mut ReferendumStatusOf<T, I>) -> bool {
1278		if let Some((_, last_alarm)) = status.alarm.take() {
1279			// Incorrect alarm - cancel it.
1280			let _ = T::Scheduler::cancel(last_alarm);
1281			true
1282		} else {
1283			false
1284		}
1285	}
1286
1287	/// Reserve a deposit and return the `Deposit` instance.
1288	fn take_deposit(
1289		who: T::AccountId,
1290		amount: BalanceOf<T, I>,
1291	) -> Result<Deposit<T::AccountId, BalanceOf<T, I>>, DispatchError> {
1292		T::Currency::reserve(&who, amount)?;
1293		Ok(Deposit { who, amount })
1294	}
1295
1296	/// Return a deposit, if `Some`.
1297	fn refund_deposit(deposit: Option<Deposit<T::AccountId, BalanceOf<T, I>>>) {
1298		if let Some(Deposit { who, amount }) = deposit {
1299			T::Currency::unreserve(&who, amount);
1300		}
1301	}
1302
1303	/// Slash a deposit, if `Some`.
1304	fn slash_deposit(deposit: Option<Deposit<T::AccountId, BalanceOf<T, I>>>) {
1305		if let Some(Deposit { who, amount }) = deposit {
1306			T::Slash::on_unbalanced(T::Currency::slash_reserved(&who, amount).0);
1307			Self::deposit_event(Event::<T, I>::DepositSlashed { who, amount });
1308		}
1309	}
1310
1311	/// Determine whether the given `tally` would result in a referendum passing at `elapsed` blocks
1312	/// into a total decision `period`, given the two curves for `support_needed` and
1313	/// `approval_needed`.
1314	fn is_passing(
1315		tally: &T::Tally,
1316		elapsed: BlockNumberFor<T, I>,
1317		period: BlockNumberFor<T, I>,
1318		support_needed: &Curve,
1319		approval_needed: &Curve,
1320		id: TrackIdOf<T, I>,
1321	) -> bool {
1322		let x = Perbill::from_rational(elapsed.min(period), period);
1323		support_needed.passing(x, tally.support(id)) &&
1324			approval_needed.passing(x, tally.approval(id))
1325	}
1326
1327	/// Clear metadata if exist for a given referendum index.
1328	fn do_clear_metadata(index: ReferendumIndex) {
1329		if let Some(hash) = MetadataOf::<T, I>::take(index) {
1330			Self::deposit_event(Event::<T, I>::MetadataCleared { index, hash });
1331		}
1332	}
1333
1334	/// Ensure the correctness of the state of this pallet.
1335	///
1336	/// The following assertions must always apply.
1337	///
1338	/// General assertions:
1339	///
1340	/// * [`ReferendumCount`] must always be equal to the number of referenda in
1341	///   [`ReferendumInfoFor`].
1342	/// * Referendum indices in [`MetadataOf`] must also be stored in [`ReferendumInfoFor`].
1343	#[cfg(any(feature = "try-runtime", test))]
1344	fn do_try_state() -> Result<(), sp_runtime::TryRuntimeError> {
1345		ensure!(
1346			ReferendumCount::<T, I>::get() as usize ==
1347				ReferendumInfoFor::<T, I>::iter_keys().count(),
1348			"Number of referenda in `ReferendumInfoFor` is different than `ReferendumCount`"
1349		);
1350
1351		MetadataOf::<T, I>::iter_keys().try_for_each(|referendum_index| -> DispatchResult {
1352			ensure!(
1353				ReferendumInfoFor::<T, I>::contains_key(referendum_index),
1354				"Referendum indices in `MetadataOf` must also be stored in `ReferendumInfoOf`"
1355			);
1356			Ok(())
1357		})?;
1358
1359		Self::try_state_referenda_info()?;
1360		Self::try_state_tracks()?;
1361
1362		Ok(())
1363	}
1364
1365	/// Looking at referenda info:
1366	///
1367	/// - Data regarding ongoing phase:
1368	///
1369	/// * There must exist track info for the track of the referendum.
1370	/// * The deciding stage has to begin before confirmation period.
1371	/// * If alarm is set the nudge call has to be at most [`UndecidingTimeout`] blocks away
1372	///  from the submission block.
1373	#[cfg(any(feature = "try-runtime", test))]
1374	fn try_state_referenda_info() -> Result<(), sp_runtime::TryRuntimeError> {
1375		ReferendumInfoFor::<T, I>::iter().try_for_each(|(_, referendum)| {
1376			match referendum {
1377				ReferendumInfo::Ongoing(status) => {
1378					ensure!(
1379						T::Tracks::info(status.track).is_some(),
1380						"No track info for the track of the referendum."
1381					);
1382
1383					if let Some(deciding) = status.deciding {
1384						ensure!(
1385							deciding.since <
1386								deciding
1387									.confirming
1388									.unwrap_or(BlockNumberFor::<T, I>::max_value()),
1389							"Deciding status cannot begin before confirming stage."
1390						)
1391					}
1392				},
1393				_ => {},
1394			}
1395			Ok(())
1396		})
1397	}
1398
1399	/// Looking at tracks:
1400	///
1401	/// * The referendum indices stored in [`TrackQueue`] must exist as keys in the
1402	///  [`ReferendumInfoFor`] storage map.
1403	#[cfg(any(feature = "try-runtime", test))]
1404	fn try_state_tracks() -> Result<(), sp_runtime::TryRuntimeError> {
1405		T::Tracks::tracks().try_for_each(|track| {
1406			TrackQueue::<T, I>::get(track.id).iter().try_for_each(
1407				|(referendum_index, _)| -> Result<(), sp_runtime::TryRuntimeError> {
1408					ensure!(
1409					ReferendumInfoFor::<T, I>::contains_key(referendum_index),
1410					"`ReferendumIndex` inside the `TrackQueue` should be a key in `ReferendumInfoFor`"
1411				);
1412					Ok(())
1413				},
1414			)?;
1415			Ok(())
1416		})
1417	}
1418}