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			if status.deciding.is_some() {
598				Self::note_one_fewer_deciding(status.track);
599			}
600			Self::deposit_event(Event::<T, I>::Cancelled { index, tally: status.tally });
601			let info = ReferendumInfo::Cancelled(
602				T::BlockNumberProvider::current_block_number(),
603				Some(status.submission_deposit),
604				status.decision_deposit,
605			);
606			ReferendumInfoFor::<T, I>::insert(index, info);
607			Ok(())
608		}
609
610		/// Cancel an ongoing referendum and slash the deposits.
611		///
612		/// - `origin`: must be the `KillOrigin`.
613		/// - `index`: The index of the referendum to be cancelled.
614		///
615		/// Emits `Killed` and `DepositSlashed`.
616		#[pallet::call_index(4)]
617		#[pallet::weight(T::WeightInfo::kill())]
618		pub fn kill(origin: OriginFor<T>, index: ReferendumIndex) -> DispatchResult {
619			T::KillOrigin::ensure_origin(origin)?;
620			let status = Self::ensure_ongoing(index)?;
621			if let Some((_, last_alarm)) = status.alarm {
622				let _ = T::Scheduler::cancel(last_alarm);
623			}
624			if status.deciding.is_some() {
625				Self::note_one_fewer_deciding(status.track);
626			}
627			Self::deposit_event(Event::<T, I>::Killed { index, tally: status.tally });
628			Self::slash_deposit(Some(status.submission_deposit.clone()));
629			Self::slash_deposit(status.decision_deposit.clone());
630			Self::do_clear_metadata(index);
631			let info = ReferendumInfo::Killed(T::BlockNumberProvider::current_block_number());
632			ReferendumInfoFor::<T, I>::insert(index, info);
633			Ok(())
634		}
635
636		/// Advance a referendum onto its next logical state. Only used internally.
637		///
638		/// - `origin`: must be `Root`.
639		/// - `index`: the referendum to be advanced.
640		#[pallet::call_index(5)]
641		#[pallet::weight(ServiceBranch::max_weight_of_nudge::<T, I>())]
642		pub fn nudge_referendum(
643			origin: OriginFor<T>,
644			index: ReferendumIndex,
645		) -> DispatchResultWithPostInfo {
646			ensure_root(origin)?;
647			let now = T::BlockNumberProvider::current_block_number();
648			let mut status = Self::ensure_ongoing(index)?;
649			// This is our wake-up, so we can disregard the alarm.
650			status.alarm = None;
651			let (info, dirty, branch) = Self::service_referendum(now, index, status);
652			if dirty {
653				ReferendumInfoFor::<T, I>::insert(index, info);
654			}
655			Ok(Some(branch.weight_of_nudge::<T, I>()).into())
656		}
657
658		/// Advance a track onto its next logical state. Only used internally.
659		///
660		/// - `origin`: must be `Root`.
661		/// - `track`: the track to be advanced.
662		///
663		/// Action item for when there is now one fewer referendum in the deciding phase and the
664		/// `DecidingCount` is not yet updated. This means that we should either:
665		/// - begin deciding another referendum (and leave `DecidingCount` alone); or
666		/// - decrement `DecidingCount`.
667		#[pallet::call_index(6)]
668		#[pallet::weight(OneFewerDecidingBranch::max_weight::<T, I>())]
669		pub fn one_fewer_deciding(
670			origin: OriginFor<T>,
671			track: TrackIdOf<T, I>,
672		) -> DispatchResultWithPostInfo {
673			ensure_root(origin)?;
674			let track_info = T::Tracks::info(track).ok_or(Error::<T, I>::BadTrack)?;
675			let mut track_queue = TrackQueue::<T, I>::get(track);
676			let branch =
677				if let Some((index, mut status)) = Self::next_for_deciding(&mut track_queue) {
678					let now = T::BlockNumberProvider::current_block_number();
679					let (maybe_alarm, branch) =
680						Self::begin_deciding(&mut status, index, now, &track_info);
681					if let Some(set_alarm) = maybe_alarm {
682						Self::ensure_alarm_at(&mut status, index, set_alarm);
683					}
684					ReferendumInfoFor::<T, I>::insert(index, ReferendumInfo::Ongoing(status));
685					TrackQueue::<T, I>::insert(track, track_queue);
686					branch.into()
687				} else {
688					DecidingCount::<T, I>::mutate(track, |x| x.saturating_dec());
689					OneFewerDecidingBranch::QueueEmpty
690				};
691			Ok(Some(branch.weight::<T, I>()).into())
692		}
693
694		/// Refund the Submission Deposit for a closed referendum back to the depositor.
695		///
696		/// - `origin`: must be `Signed` or `Root`.
697		/// - `index`: The index of a closed referendum whose Submission Deposit has not yet been
698		///   refunded.
699		///
700		/// Emits `SubmissionDepositRefunded`.
701		#[pallet::call_index(7)]
702		#[pallet::weight(T::WeightInfo::refund_submission_deposit())]
703		pub fn refund_submission_deposit(
704			origin: OriginFor<T>,
705			index: ReferendumIndex,
706		) -> DispatchResult {
707			ensure_signed_or_root(origin)?;
708			let mut info =
709				ReferendumInfoFor::<T, I>::get(index).ok_or(Error::<T, I>::BadReferendum)?;
710			let deposit = info
711				.take_submission_deposit()
712				.map_err(|_| Error::<T, I>::BadStatus)?
713				.ok_or(Error::<T, I>::NoDeposit)?;
714			Self::refund_deposit(Some(deposit.clone()));
715			ReferendumInfoFor::<T, I>::insert(index, info);
716			let e = Event::<T, I>::SubmissionDepositRefunded {
717				index,
718				who: deposit.who,
719				amount: deposit.amount,
720			};
721			Self::deposit_event(e);
722			Ok(())
723		}
724
725		/// Set or clear metadata of a referendum.
726		///
727		/// Parameters:
728		/// - `origin`: Must be `Signed` by a creator of a referendum or by anyone to clear a
729		///   metadata of a finished referendum.
730		/// - `index`:  The index of a referendum to set or clear metadata for.
731		/// - `maybe_hash`: The hash of an on-chain stored preimage. `None` to clear a metadata.
732		#[pallet::call_index(8)]
733		#[pallet::weight(
734			maybe_hash.map_or(
735				T::WeightInfo::clear_metadata(), |_| T::WeightInfo::set_some_metadata())
736			)]
737		pub fn set_metadata(
738			origin: OriginFor<T>,
739			index: ReferendumIndex,
740			maybe_hash: Option<T::Hash>,
741		) -> DispatchResult {
742			let who = ensure_signed(origin)?;
743			if let Some(hash) = maybe_hash {
744				let status = Self::ensure_ongoing(index)?;
745				ensure!(status.submission_deposit.who == who, Error::<T, I>::NoPermission);
746				ensure!(T::Preimages::len(&hash).is_some(), Error::<T, I>::PreimageNotExist);
747				MetadataOf::<T, I>::insert(index, hash);
748				Self::deposit_event(Event::<T, I>::MetadataSet { index, hash });
749				Ok(())
750			} else {
751				if let Some(status) = Self::ensure_ongoing(index).ok() {
752					ensure!(status.submission_deposit.who == who, Error::<T, I>::NoPermission);
753				}
754				Self::do_clear_metadata(index);
755				Ok(())
756			}
757		}
758	}
759}
760
761impl<T: Config<I>, I: 'static> Polling<T::Tally> for Pallet<T, I> {
762	type Index = ReferendumIndex;
763	type Votes = VotesOf<T, I>;
764	type Moment = BlockNumberFor<T, I>;
765	type Class = TrackIdOf<T, I>;
766
767	fn classes() -> Vec<Self::Class> {
768		T::Tracks::track_ids().collect()
769	}
770
771	fn access_poll<R>(
772		index: Self::Index,
773		f: impl FnOnce(PollStatus<&mut T::Tally, BlockNumberFor<T, I>, TrackIdOf<T, I>>) -> R,
774	) -> R {
775		match ReferendumInfoFor::<T, I>::get(index) {
776			Some(ReferendumInfo::Ongoing(mut status)) => {
777				let result = f(PollStatus::Ongoing(&mut status.tally, status.track));
778				let now = T::BlockNumberProvider::current_block_number();
779				Self::ensure_alarm_at(&mut status, index, now + One::one());
780				ReferendumInfoFor::<T, I>::insert(index, ReferendumInfo::Ongoing(status));
781				result
782			},
783			Some(ReferendumInfo::Approved(end, ..)) => f(PollStatus::Completed(end, true)),
784			Some(ReferendumInfo::Rejected(end, ..)) => f(PollStatus::Completed(end, false)),
785			_ => f(PollStatus::None),
786		}
787	}
788
789	fn try_access_poll<R>(
790		index: Self::Index,
791		f: impl FnOnce(
792			PollStatus<&mut T::Tally, BlockNumberFor<T, I>, TrackIdOf<T, I>>,
793		) -> Result<R, DispatchError>,
794	) -> Result<R, DispatchError> {
795		match ReferendumInfoFor::<T, I>::get(index) {
796			Some(ReferendumInfo::Ongoing(mut status)) => {
797				let result = f(PollStatus::Ongoing(&mut status.tally, status.track))?;
798				let now = T::BlockNumberProvider::current_block_number();
799				Self::ensure_alarm_at(&mut status, index, now + One::one());
800				ReferendumInfoFor::<T, I>::insert(index, ReferendumInfo::Ongoing(status));
801				Ok(result)
802			},
803			Some(ReferendumInfo::Approved(end, ..)) => f(PollStatus::Completed(end, true)),
804			Some(ReferendumInfo::Rejected(end, ..)) => f(PollStatus::Completed(end, false)),
805			_ => f(PollStatus::None),
806		}
807	}
808
809	fn as_ongoing(index: Self::Index) -> Option<(T::Tally, TrackIdOf<T, I>)> {
810		Self::ensure_ongoing(index).ok().map(|x| (x.tally, x.track))
811	}
812
813	#[cfg(feature = "runtime-benchmarks")]
814	fn create_ongoing(class: Self::Class) -> Result<Self::Index, ()> {
815		let index = ReferendumCount::<T, I>::mutate(|x| {
816			let r = *x;
817			*x += 1;
818			r
819		});
820		let now = T::BlockNumberProvider::current_block_number();
821		let dummy_account_id =
822			codec::Decode::decode(&mut sp_runtime::traits::TrailingZeroInput::new(&b"dummy"[..]))
823				.expect("infinite length input; no invalid inputs for type; qed");
824		let mut status = ReferendumStatusOf::<T, I> {
825			track: class,
826			origin: frame_support::dispatch::RawOrigin::Root.into(),
827			proposal: T::Preimages::bound(CallOf::<T, I>::from(Call::nudge_referendum { index }))
828				.map_err(|_| ())?,
829			enactment: DispatchTime::After(Zero::zero()),
830			submitted: now,
831			submission_deposit: Deposit { who: dummy_account_id, amount: Zero::zero() },
832			decision_deposit: None,
833			deciding: None,
834			tally: TallyOf::<T, I>::new(class),
835			in_queue: false,
836			alarm: None,
837		};
838
839		Self::ensure_alarm_at(&mut status, index, sp_runtime::traits::Bounded::max_value());
840		ReferendumInfoFor::<T, I>::insert(index, ReferendumInfo::Ongoing(status));
841		Ok(index)
842	}
843
844	#[cfg(feature = "runtime-benchmarks")]
845	fn end_ongoing(index: Self::Index, approved: bool) -> Result<(), ()> {
846		let mut status = Self::ensure_ongoing(index).map_err(|_| ())?;
847		Self::ensure_no_alarm(&mut status);
848		Self::note_one_fewer_deciding(status.track);
849		let now = T::BlockNumberProvider::current_block_number();
850		let info = if approved {
851			ReferendumInfo::Approved(now, Some(status.submission_deposit), status.decision_deposit)
852		} else {
853			ReferendumInfo::Rejected(now, Some(status.submission_deposit), status.decision_deposit)
854		};
855		ReferendumInfoFor::<T, I>::insert(index, info);
856		Ok(())
857	}
858
859	#[cfg(feature = "runtime-benchmarks")]
860	fn max_ongoing() -> (Self::Class, u32) {
861		let r = T::Tracks::tracks()
862			.max_by_key(|t| t.info.max_deciding)
863			.expect("Always one class");
864		(r.id, r.info.max_deciding)
865	}
866}
867
868impl<T: Config<I>, I: 'static> Pallet<T, I> {
869	/// Check that referendum `index` is in the `Ongoing` state and return the `ReferendumStatus`
870	/// value, or `Err` otherwise.
871	pub fn ensure_ongoing(
872		index: ReferendumIndex,
873	) -> Result<ReferendumStatusOf<T, I>, DispatchError> {
874		match ReferendumInfoFor::<T, I>::get(index) {
875			Some(ReferendumInfo::Ongoing(status)) => Ok(status),
876			_ => Err(Error::<T, I>::NotOngoing.into()),
877		}
878	}
879
880	/// Returns whether the referendum is passing.
881	/// Referendum must be ongoing and its track must exist.
882	pub fn is_referendum_passing(ref_index: ReferendumIndex) -> Result<bool, DispatchError> {
883		let info = ReferendumInfoFor::<T, I>::get(ref_index).ok_or(Error::<T, I>::BadReferendum)?;
884		match info {
885			ReferendumInfo::Ongoing(status) => {
886				let track = T::Tracks::info(status.track).ok_or(Error::<T, I>::NoTrack)?;
887				let elapsed = if let Some(deciding) = status.deciding {
888					T::BlockNumberProvider::current_block_number().saturating_sub(deciding.since)
889				} else {
890					Zero::zero()
891				};
892				Ok(Self::is_passing(
893					&status.tally,
894					elapsed,
895					track.decision_period,
896					&track.min_support,
897					&track.min_approval,
898					status.track,
899				))
900			},
901			_ => Err(Error::<T, I>::NotOngoing.into()),
902		}
903	}
904
905	// Enqueue a proposal from a referendum which has presumably passed.
906	fn schedule_enactment(
907		index: ReferendumIndex,
908		track: &TrackInfoOf<T, I>,
909		desired: DispatchTime<BlockNumberFor<T, I>>,
910		origin: PalletsOriginOf<T>,
911		call: BoundedCallOf<T, I>,
912	) {
913		let now = T::BlockNumberProvider::current_block_number();
914		// Earliest allowed block is always at minimum the next block.
915		let earliest_allowed = now.saturating_add(track.min_enactment_period.max(One::one()));
916		let desired = desired.evaluate(now);
917		let ok = T::Scheduler::schedule_named(
918			(ASSEMBLY_ID, "enactment", index).using_encoded(sp_io::hashing::blake2_256),
919			DispatchTime::At(desired.max(earliest_allowed)),
920			None,
921			63,
922			origin,
923			call,
924		)
925		.is_ok();
926		debug_assert!(ok, "LOGIC ERROR: bake_referendum/schedule_named failed");
927	}
928
929	/// Set an alarm to dispatch `call` at block number `when`.
930	fn set_alarm(
931		call: BoundedCallOf<T, I>,
932		when: BlockNumberFor<T, I>,
933	) -> Option<(BlockNumberFor<T, I>, ScheduleAddressOf<T, I>)> {
934		let alarm_interval = T::AlarmInterval::get().max(One::one());
935		// Alarm must go off no earlier than `when`.
936		// This rounds `when` upwards to the next multiple of `alarm_interval`.
937		let when = (when.saturating_add(alarm_interval.saturating_sub(One::one())) /
938			alarm_interval)
939			.saturating_mul(alarm_interval);
940		let result = T::Scheduler::schedule(
941			DispatchTime::At(when),
942			None,
943			128u8,
944			frame_system::RawOrigin::Root.into(),
945			call,
946		);
947		debug_assert!(
948			result.is_ok(),
949			"Unable to schedule a new alarm at #{:?} (now: #{:?}), scheduler error: `{:?}`",
950			when,
951			T::BlockNumberProvider::current_block_number(),
952			result.unwrap_err(),
953		);
954		result.ok().map(|x| (when, x))
955	}
956
957	/// Mutate a referendum's `status` into the correct deciding state.
958	///
959	/// - `now` is the current block number.
960	/// - `track` is the track info for the referendum.
961	///
962	/// This will properly set up the `confirming` item.
963	fn begin_deciding(
964		status: &mut ReferendumStatusOf<T, I>,
965		index: ReferendumIndex,
966		now: BlockNumberFor<T, I>,
967		track: &TrackInfoOf<T, I>,
968	) -> (Option<BlockNumberFor<T, I>>, BeginDecidingBranch) {
969		let is_passing = Self::is_passing(
970			&status.tally,
971			Zero::zero(),
972			track.decision_period,
973			&track.min_support,
974			&track.min_approval,
975			status.track,
976		);
977		status.in_queue = false;
978		Self::deposit_event(Event::<T, I>::DecisionStarted {
979			index,
980			tally: status.tally.clone(),
981			proposal: status.proposal.clone(),
982			track: status.track,
983		});
984		let confirming = if is_passing {
985			Self::deposit_event(Event::<T, I>::ConfirmStarted { index });
986			Some(now.saturating_add(track.confirm_period))
987		} else {
988			None
989		};
990		let deciding_status = DecidingStatus { since: now, confirming };
991		let alarm = Self::decision_time(&deciding_status, &status.tally, status.track, track)
992			.max(now.saturating_add(One::one()));
993		status.deciding = Some(deciding_status);
994		let branch =
995			if is_passing { BeginDecidingBranch::Passing } else { BeginDecidingBranch::Failing };
996		(Some(alarm), branch)
997	}
998
999	/// If it returns `Some`, deciding has begun and it needs waking at the given block number. The
1000	/// second item is the flag for whether it is confirming or not.
1001	///
1002	/// If `None`, then it is queued and should be nudged automatically as the queue gets drained.
1003	fn ready_for_deciding(
1004		now: BlockNumberFor<T, I>,
1005		track: &TrackInfoOf<T, I>,
1006		index: ReferendumIndex,
1007		status: &mut ReferendumStatusOf<T, I>,
1008	) -> (Option<BlockNumberFor<T, I>>, ServiceBranch) {
1009		let deciding_count = DecidingCount::<T, I>::get(status.track);
1010		if deciding_count < track.max_deciding {
1011			// Begin deciding.
1012			DecidingCount::<T, I>::insert(status.track, deciding_count.saturating_add(1));
1013			let r = Self::begin_deciding(status, index, now, track);
1014			(r.0, r.1.into())
1015		} else {
1016			// Add to queue.
1017			let item = (index, status.tally.ayes(status.track));
1018			status.in_queue = true;
1019			TrackQueue::<T, I>::mutate(status.track, |q| q.insert_sorted_by_key(item, |x| x.1));
1020			(None, ServiceBranch::Queued)
1021		}
1022	}
1023
1024	/// Grab the index and status for the referendum which is the highest priority of those for the
1025	/// given track which are ready for being decided.
1026	fn next_for_deciding(
1027		track_queue: &mut BoundedVec<(u32, VotesOf<T, I>), T::MaxQueued>,
1028	) -> Option<(ReferendumIndex, ReferendumStatusOf<T, I>)> {
1029		loop {
1030			let (index, _) = track_queue.pop()?;
1031			match Self::ensure_ongoing(index) {
1032				Ok(s) => return Some((index, s)),
1033				Err(_) => {}, // referendum already timedout or was cancelled.
1034			}
1035		}
1036	}
1037
1038	/// Schedule a call to `one_fewer_deciding` function via the dispatchable
1039	/// `defer_one_fewer_deciding`. We could theoretically call it immediately (and it would be
1040	/// overall more efficient), however the weights become rather less easy to measure.
1041	fn note_one_fewer_deciding(track: TrackIdOf<T, I>) {
1042		// Set an alarm call for the next block to nudge the track along.
1043		let now = T::BlockNumberProvider::current_block_number();
1044		let next_block = now + One::one();
1045		let call = match T::Preimages::bound(CallOf::<T, I>::from(Call::one_fewer_deciding {
1046			track,
1047		})) {
1048			Ok(c) => c,
1049			Err(_) => {
1050				debug_assert!(false, "Unable to create a bounded call from `one_fewer_deciding`??",);
1051				return;
1052			},
1053		};
1054		Self::set_alarm(call, next_block);
1055	}
1056
1057	/// Ensure that a `service_referendum` alarm happens for the referendum `index` at `alarm`.
1058	///
1059	/// This will do nothing if the alarm is already set.
1060	///
1061	/// Returns `false` if nothing changed.
1062	fn ensure_alarm_at(
1063		status: &mut ReferendumStatusOf<T, I>,
1064		index: ReferendumIndex,
1065		alarm: BlockNumberFor<T, I>,
1066	) -> bool {
1067		if status.alarm.as_ref().map_or(true, |&(when, _)| when != alarm) {
1068			// Either no alarm or one that was different
1069			Self::ensure_no_alarm(status);
1070			let call =
1071				match T::Preimages::bound(CallOf::<T, I>::from(Call::nudge_referendum { index })) {
1072					Ok(c) => c,
1073					Err(_) => {
1074						debug_assert!(
1075							false,
1076							"Unable to create a bounded call from `nudge_referendum`??",
1077						);
1078						return false;
1079					},
1080				};
1081			status.alarm = Self::set_alarm(call, alarm);
1082			true
1083		} else {
1084			false
1085		}
1086	}
1087
1088	/// Advance the state of a referendum, which comes down to:
1089	/// - If it's ready to be decided, start deciding;
1090	/// - If it's not ready to be decided and non-deciding timeout has passed, fail;
1091	/// - If it's ongoing and passing, ensure confirming; if at end of confirmation period, pass.
1092	/// - If it's ongoing and not passing, stop confirming; if it has reached end time, fail.
1093	///
1094	/// Weight will be a bit different depending on what it does, but it's designed so as not to
1095	/// differ dramatically, especially if `MaxQueue` is kept small. In particular _there are no
1096	/// balance operations in here_.
1097	///
1098	/// In terms of storage, every call to it is expected to access:
1099	/// - The scheduler, either to insert, remove or alter an entry;
1100	/// - `TrackQueue`, which should be a `BoundedVec` with a low limit (8-16);
1101	/// - `DecidingCount`.
1102	///
1103	/// Both of the two storage items will only have as many items as there are different tracks,
1104	/// perhaps around 10 and should be whitelisted.
1105	///
1106	/// The heaviest branch is likely to be when a proposal is placed into, or moved within, the
1107	/// `TrackQueue`. Basically this happens when a referendum is in the deciding queue and receives
1108	/// a vote, or when it moves into the deciding queue.
1109	fn service_referendum(
1110		now: BlockNumberFor<T, I>,
1111		index: ReferendumIndex,
1112		mut status: ReferendumStatusOf<T, I>,
1113	) -> (ReferendumInfoOf<T, I>, bool, ServiceBranch) {
1114		let mut dirty = false;
1115		// Should it begin being decided?
1116		let track = match T::Tracks::info(status.track) {
1117			Some(x) => x,
1118			None => return (ReferendumInfo::Ongoing(status), false, ServiceBranch::Fail),
1119		};
1120		// Default the alarm to the end of the world.
1121		let timeout = status.submitted + T::UndecidingTimeout::get();
1122		let mut alarm = BlockNumberFor::<T, I>::max_value();
1123		let branch;
1124		match &mut status.deciding {
1125			None => {
1126				// Are we already queued for deciding?
1127				if status.in_queue {
1128					// Does our position in the queue need updating?
1129					let ayes = status.tally.ayes(status.track);
1130					let mut queue = TrackQueue::<T, I>::get(status.track);
1131					let maybe_old_pos = queue.iter().position(|(x, _)| *x == index);
1132					let new_pos = queue.binary_search_by_key(&ayes, |x| x.1).unwrap_or_else(|x| x);
1133					branch = if maybe_old_pos.is_none() && new_pos > 0 {
1134						// Just insert.
1135						let _ = queue.force_insert_keep_right(new_pos, (index, ayes));
1136						ServiceBranch::RequeuedInsertion
1137					} else if let Some(old_pos) = maybe_old_pos {
1138						// We were in the queue - slide into the correct position.
1139						queue[old_pos].1 = ayes;
1140						queue.slide(old_pos, new_pos);
1141						ServiceBranch::RequeuedSlide
1142					} else {
1143						ServiceBranch::NotQueued
1144					};
1145					TrackQueue::<T, I>::insert(status.track, queue);
1146				} else {
1147					// Are we ready for deciding?
1148					branch = if status.decision_deposit.is_some() {
1149						let prepare_end = status.submitted.saturating_add(track.prepare_period);
1150						if now >= prepare_end {
1151							let (maybe_alarm, branch) =
1152								Self::ready_for_deciding(now, &track, index, &mut status);
1153							if let Some(set_alarm) = maybe_alarm {
1154								alarm = alarm.min(set_alarm);
1155							}
1156							dirty = true;
1157							branch
1158						} else {
1159							alarm = alarm.min(prepare_end);
1160							ServiceBranch::Preparing
1161						}
1162					} else {
1163						alarm = timeout;
1164						ServiceBranch::NoDeposit
1165					}
1166				}
1167				// If we didn't move into being decided, then check the timeout.
1168				if status.deciding.is_none() && now >= timeout && !status.in_queue {
1169					// Too long without being decided - end it.
1170					Self::ensure_no_alarm(&mut status);
1171					Self::deposit_event(Event::<T, I>::TimedOut { index, tally: status.tally });
1172					return (
1173						ReferendumInfo::TimedOut(
1174							now,
1175							Some(status.submission_deposit),
1176							status.decision_deposit,
1177						),
1178						true,
1179						ServiceBranch::TimedOut,
1180					);
1181				}
1182			},
1183			Some(deciding) => {
1184				let is_passing = Self::is_passing(
1185					&status.tally,
1186					now.saturating_sub(deciding.since),
1187					track.decision_period,
1188					&track.min_support,
1189					&track.min_approval,
1190					status.track,
1191				);
1192				branch = if is_passing {
1193					match deciding.confirming {
1194						Some(t) if now >= t => {
1195							// Passed!
1196							Self::ensure_no_alarm(&mut status);
1197							Self::note_one_fewer_deciding(status.track);
1198							let (desired, call) = (status.enactment, status.proposal);
1199							Self::schedule_enactment(index, &track, desired, status.origin, call);
1200							Self::deposit_event(Event::<T, I>::Confirmed {
1201								index,
1202								tally: status.tally,
1203							});
1204							return (
1205								ReferendumInfo::Approved(
1206									now,
1207									Some(status.submission_deposit),
1208									status.decision_deposit,
1209								),
1210								true,
1211								ServiceBranch::Approved,
1212							);
1213						},
1214						Some(_) => ServiceBranch::ContinueConfirming,
1215						None => {
1216							// Start confirming
1217							dirty = true;
1218							deciding.confirming = Some(now.saturating_add(track.confirm_period));
1219							Self::deposit_event(Event::<T, I>::ConfirmStarted { index });
1220							ServiceBranch::BeginConfirming
1221						},
1222					}
1223				} else {
1224					if now >= deciding.since.saturating_add(track.decision_period) {
1225						// Failed!
1226						Self::ensure_no_alarm(&mut status);
1227						Self::note_one_fewer_deciding(status.track);
1228						Self::deposit_event(Event::<T, I>::Rejected { index, tally: status.tally });
1229						return (
1230							ReferendumInfo::Rejected(
1231								now,
1232								Some(status.submission_deposit),
1233								status.decision_deposit,
1234							),
1235							true,
1236							ServiceBranch::Rejected,
1237						);
1238					}
1239					if deciding.confirming.is_some() {
1240						// Stop confirming
1241						dirty = true;
1242						deciding.confirming = None;
1243						Self::deposit_event(Event::<T, I>::ConfirmAborted { index });
1244						ServiceBranch::EndConfirming
1245					} else {
1246						ServiceBranch::ContinueNotConfirming
1247					}
1248				};
1249				alarm = Self::decision_time(deciding, &status.tally, status.track, &track);
1250			},
1251		}
1252
1253		let dirty_alarm = if alarm < BlockNumberFor::<T, I>::max_value() {
1254			Self::ensure_alarm_at(&mut status, index, alarm)
1255		} else {
1256			Self::ensure_no_alarm(&mut status)
1257		};
1258		(ReferendumInfo::Ongoing(status), dirty_alarm || dirty, branch)
1259	}
1260
1261	/// Determine the point at which a referendum will be accepted, move into confirmation with the
1262	/// given `tally` or end with rejection (whichever happens sooner).
1263	fn decision_time(
1264		deciding: &DecidingStatusOf<T, I>,
1265		tally: &T::Tally,
1266		track_id: TrackIdOf<T, I>,
1267		track: &TrackInfoOf<T, I>,
1268	) -> BlockNumberFor<T, I> {
1269		deciding.confirming.unwrap_or_else(|| {
1270			// Set alarm to the point where the current voting would make it pass.
1271			let approval = tally.approval(track_id);
1272			let support = tally.support(track_id);
1273			let until_approval = track.min_approval.delay(approval);
1274			let until_support = track.min_support.delay(support);
1275			let offset = until_support.max(until_approval);
1276			deciding.since.saturating_add(offset.mul_ceil(track.decision_period))
1277		})
1278	}
1279
1280	/// Cancel the alarm in `status`, if one exists.
1281	fn ensure_no_alarm(status: &mut ReferendumStatusOf<T, I>) -> bool {
1282		if let Some((_, last_alarm)) = status.alarm.take() {
1283			// Incorrect alarm - cancel it.
1284			let _ = T::Scheduler::cancel(last_alarm);
1285			true
1286		} else {
1287			false
1288		}
1289	}
1290
1291	/// Reserve a deposit and return the `Deposit` instance.
1292	fn take_deposit(
1293		who: T::AccountId,
1294		amount: BalanceOf<T, I>,
1295	) -> Result<Deposit<T::AccountId, BalanceOf<T, I>>, DispatchError> {
1296		T::Currency::reserve(&who, amount)?;
1297		Ok(Deposit { who, amount })
1298	}
1299
1300	/// Return a deposit, if `Some`.
1301	fn refund_deposit(deposit: Option<Deposit<T::AccountId, BalanceOf<T, I>>>) {
1302		if let Some(Deposit { who, amount }) = deposit {
1303			T::Currency::unreserve(&who, amount);
1304		}
1305	}
1306
1307	/// Slash a deposit, if `Some`.
1308	fn slash_deposit(deposit: Option<Deposit<T::AccountId, BalanceOf<T, I>>>) {
1309		if let Some(Deposit { who, amount }) = deposit {
1310			T::Slash::on_unbalanced(T::Currency::slash_reserved(&who, amount).0);
1311			Self::deposit_event(Event::<T, I>::DepositSlashed { who, amount });
1312		}
1313	}
1314
1315	/// Determine whether the given `tally` would result in a referendum passing at `elapsed` blocks
1316	/// into a total decision `period`, given the two curves for `support_needed` and
1317	/// `approval_needed`.
1318	fn is_passing(
1319		tally: &T::Tally,
1320		elapsed: BlockNumberFor<T, I>,
1321		period: BlockNumberFor<T, I>,
1322		support_needed: &Curve,
1323		approval_needed: &Curve,
1324		id: TrackIdOf<T, I>,
1325	) -> bool {
1326		let x = Perbill::from_rational(elapsed.min(period), period);
1327		support_needed.passing(x, tally.support(id)) &&
1328			approval_needed.passing(x, tally.approval(id))
1329	}
1330
1331	/// Clear metadata if exist for a given referendum index.
1332	fn do_clear_metadata(index: ReferendumIndex) {
1333		if let Some(hash) = MetadataOf::<T, I>::take(index) {
1334			Self::deposit_event(Event::<T, I>::MetadataCleared { index, hash });
1335		}
1336	}
1337
1338	/// Ensure the correctness of the state of this pallet.
1339	///
1340	/// The following assertions must always apply.
1341	///
1342	/// General assertions:
1343	///
1344	/// * [`ReferendumCount`] must always be equal to the number of referenda in
1345	///   [`ReferendumInfoFor`].
1346	/// * Referendum indices in [`MetadataOf`] must also be stored in [`ReferendumInfoFor`].
1347	#[cfg(any(feature = "try-runtime", test))]
1348	fn do_try_state() -> Result<(), sp_runtime::TryRuntimeError> {
1349		ensure!(
1350			ReferendumCount::<T, I>::get() as usize ==
1351				ReferendumInfoFor::<T, I>::iter_keys().count(),
1352			"Number of referenda in `ReferendumInfoFor` is different than `ReferendumCount`"
1353		);
1354
1355		MetadataOf::<T, I>::iter_keys().try_for_each(|referendum_index| -> DispatchResult {
1356			ensure!(
1357				ReferendumInfoFor::<T, I>::contains_key(referendum_index),
1358				"Referendum indices in `MetadataOf` must also be stored in `ReferendumInfoOf`"
1359			);
1360			Ok(())
1361		})?;
1362
1363		Self::try_state_referenda_info()?;
1364		Self::try_state_tracks()?;
1365
1366		Ok(())
1367	}
1368
1369	/// Looking at referenda info:
1370	///
1371	/// - Data regarding ongoing phase:
1372	///
1373	/// * There must exist track info for the track of the referendum.
1374	/// * The deciding stage has to begin before confirmation period.
1375	/// * If alarm is set the nudge call has to be at most [`UndecidingTimeout`] blocks away
1376	///  from the submission block.
1377	#[cfg(any(feature = "try-runtime", test))]
1378	fn try_state_referenda_info() -> Result<(), sp_runtime::TryRuntimeError> {
1379		ReferendumInfoFor::<T, I>::iter().try_for_each(|(_, referendum)| {
1380			match referendum {
1381				ReferendumInfo::Ongoing(status) => {
1382					ensure!(
1383						T::Tracks::info(status.track).is_some(),
1384						"No track info for the track of the referendum."
1385					);
1386
1387					if let Some(deciding) = status.deciding {
1388						ensure!(
1389							deciding.since <
1390								deciding
1391									.confirming
1392									.unwrap_or(BlockNumberFor::<T, I>::max_value()),
1393							"Deciding status cannot begin before confirming stage."
1394						)
1395					}
1396				},
1397				_ => {},
1398			}
1399			Ok(())
1400		})
1401	}
1402
1403	/// Looking at tracks:
1404	///
1405	/// * The referendum indices stored in [`TrackQueue`] must exist as keys in the
1406	///  [`ReferendumInfoFor`] storage map.
1407	#[cfg(any(feature = "try-runtime", test))]
1408	fn try_state_tracks() -> Result<(), sp_runtime::TryRuntimeError> {
1409		T::Tracks::tracks().try_for_each(|track| {
1410			TrackQueue::<T, I>::get(track.id).iter().try_for_each(
1411				|(referendum_index, _)| -> Result<(), sp_runtime::TryRuntimeError> {
1412					ensure!(
1413					ReferendumInfoFor::<T, I>::contains_key(referendum_index),
1414					"`ReferendumIndex` inside the `TrackQueue` should be a key in `ReferendumInfoFor`"
1415				);
1416					Ok(())
1417				},
1418			)?;
1419			Ok(())
1420		})
1421	}
1422}