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

            
67
extern crate alloc;
68

            
69
use alloc::boxed::Box;
70
use codec::{Codec, Encode};
71
use core::fmt::Debug;
72
use 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
};
85
use frame_system::pallet_prelude::BlockNumberFor;
86
use scale_info::TypeInfo;
87
use sp_runtime::{
88
	traits::{AtLeast32BitUnsigned, Bounded, Dispatchable, One, Saturating, Zero},
89
	DispatchError, Perbill,
90
};
91

            
92
mod branch;
93
pub mod migration;
94
mod types;
95
pub mod weights;
96

            
97
use self::branch::{BeginDecidingBranch, OneFewerDecidingBranch, ServiceBranch};
98
pub use self::{
99
	pallet::*,
100
	types::{
101
		BalanceOf, BoundedCallOf, CallOf, Curve, DecidingStatus, DecidingStatusOf, Deposit,
102
		InsertSorted, NegativeImbalanceOf, PalletsOriginOf, ReferendumIndex, ReferendumInfo,
103
		ReferendumInfoOf, ReferendumStatus, ReferendumStatusOf, ScheduleAddressOf, TallyOf,
104
		TrackIdOf, TrackInfo, TrackInfoOf, TracksInfo, VotesOf,
105
	},
106
	weights::WeightInfo,
107
};
108
pub use alloc::vec::Vec;
109

            
110
#[cfg(test)]
111
mod mock;
112
#[cfg(test)]
113
mod tests;
114

            
115
#[cfg(feature = "runtime-benchmarks")]
116
pub mod benchmarking;
117

            
118
pub use frame_support::traits::Get;
119

            
120
#[macro_export]
121
macro_rules! impl_tracksinfo_get {
122
	($tracksinfo:ty, $balance:ty, $blocknumber:ty) => {
123
		impl
124
			$crate::Get<
125
				$crate::Vec<(
126
					<$tracksinfo as $crate::TracksInfo<$balance, $blocknumber>>::Id,
127
					$crate::TrackInfo<$balance, $blocknumber>,
128
				)>,
129
			> for $tracksinfo
130
		{
131
			fn get() -> $crate::Vec<(
132
				<$tracksinfo as $crate::TracksInfo<$balance, $blocknumber>>::Id,
133
				$crate::TrackInfo<$balance, $blocknumber>,
134
			)> {
135
				<$tracksinfo as $crate::TracksInfo<$balance, $blocknumber>>::tracks().to_vec()
136
			}
137
		}
138
	};
139
}
140

            
141
const ASSEMBLY_ID: LockIdentifier = *b"assembly";
142

            
143
3766
#[frame_support::pallet]
144
pub mod pallet {
145
	use super::*;
146
	use frame_support::{pallet_prelude::*, traits::EnsureOriginWithArg};
147
	use frame_system::pallet_prelude::*;
148

            
149
	/// The in-code storage version.
150
	const STORAGE_VERSION: StorageVersion = StorageVersion::new(1);
151

            
152
3396
	#[pallet::pallet]
153
	#[pallet::storage_version(STORAGE_VERSION)]
154
	pub struct Pallet<T, I = ()>(_);
155

            
156
	#[pallet::config]
157
	pub trait Config<I: 'static = ()>: frame_system::Config + Sized {
158
		// System level stuff.
159
		type RuntimeCall: Parameter
160
			+ Dispatchable<RuntimeOrigin = Self::RuntimeOrigin>
161
			+ From<Call<Self, I>>
162
			+ IsType<<Self as frame_system::Config>::RuntimeCall>
163
			+ From<frame_system::Call<Self>>;
164
		type RuntimeEvent: From<Event<Self, I>>
165
			+ IsType<<Self as frame_system::Config>::RuntimeEvent>;
166
		/// Weight information for extrinsics in this pallet.
167
		type WeightInfo: WeightInfo;
168
		/// The Scheduler.
169
		type Scheduler: ScheduleAnon<
170
				BlockNumberFor<Self>,
171
				CallOf<Self, I>,
172
				PalletsOriginOf<Self>,
173
				Hasher = Self::Hashing,
174
			> + ScheduleNamed<
175
				BlockNumberFor<Self>,
176
				CallOf<Self, I>,
177
				PalletsOriginOf<Self>,
178
				Hasher = Self::Hashing,
179
			>;
180
		/// Currency type for this pallet.
181
		type Currency: ReservableCurrency<Self::AccountId>;
182
		// Origins and unbalances.
183
		/// Origin from which proposals may be submitted.
184
		type SubmitOrigin: EnsureOriginWithArg<
185
			Self::RuntimeOrigin,
186
			PalletsOriginOf<Self>,
187
			Success = Self::AccountId,
188
		>;
189
		/// Origin from which any vote may be cancelled.
190
		type CancelOrigin: EnsureOrigin<Self::RuntimeOrigin>;
191
		/// Origin from which any vote may be killed.
192
		type KillOrigin: EnsureOrigin<Self::RuntimeOrigin>;
193
		/// Handler for the unbalanced reduction when slashing a preimage deposit.
194
		type Slash: OnUnbalanced<NegativeImbalanceOf<Self, I>>;
195
		/// The counting type for votes. Usually just balance.
196
		type Votes: AtLeast32BitUnsigned + Copy + Parameter + Member + MaxEncodedLen;
197
		/// The tallying type.
198
		type Tally: VoteTally<Self::Votes, TrackIdOf<Self, I>>
199
			+ Clone
200
			+ Codec
201
			+ Eq
202
			+ Debug
203
			+ TypeInfo
204
			+ MaxEncodedLen;
205

            
206
		// Constants
207
		/// The minimum amount to be used as a deposit for a public referendum proposal.
208
		#[pallet::constant]
209
		type SubmissionDeposit: Get<BalanceOf<Self, I>>;
210

            
211
		/// Maximum size of the referendum queue for a single track.
212
		#[pallet::constant]
213
		type MaxQueued: Get<u32>;
214

            
215
		/// The number of blocks after submission that a referendum must begin being decided by.
216
		/// Once this passes, then anyone may cancel the referendum.
217
		#[pallet::constant]
218
		type UndecidingTimeout: Get<BlockNumberFor<Self>>;
219

            
220
		/// Quantization level for the referendum wakeup scheduler. A higher number will result in
221
		/// fewer storage reads/writes needed for smaller voters, but also result in delays to the
222
		/// automatic referendum status changes. Explicit servicing instructions are unaffected.
223
		#[pallet::constant]
224
		type AlarmInterval: Get<BlockNumberFor<Self>>;
225

            
226
		// The other stuff.
227
		/// Information concerning the different referendum tracks.
228
		#[pallet::constant]
229
		type Tracks: Get<
230
				Vec<(
231
					<Self::Tracks as TracksInfo<BalanceOf<Self, I>, BlockNumberFor<Self>>>::Id,
232
					TrackInfo<BalanceOf<Self, I>, BlockNumberFor<Self>>,
233
				)>,
234
			> + TracksInfo<
235
				BalanceOf<Self, I>,
236
				BlockNumberFor<Self>,
237
				RuntimeOrigin = <Self::RuntimeOrigin as OriginTrait>::PalletsOrigin,
238
			>;
239

            
240
		/// The preimage provider.
241
		type Preimages: QueryPreimage<H = Self::Hashing> + StorePreimage;
242
	}
243

            
244
	/// The next free referendum index, aka the number of referenda started so far.
245
218292
	#[pallet::storage]
246
	pub type ReferendumCount<T, I = ()> = StorageValue<_, ReferendumIndex, ValueQuery>;
247

            
248
	/// Information concerning any given referendum.
249
431784
	#[pallet::storage]
250
	pub type ReferendumInfoFor<T: Config<I>, I: 'static = ()> =
251
		StorageMap<_, Blake2_128Concat, ReferendumIndex, ReferendumInfoOf<T, I>>;
252

            
253
	/// The sorted list of referenda ready to be decided but not yet being decided, ordered by
254
	/// conviction-weighted approvals.
255
	///
256
	/// This should be empty if `DecidingCount` is less than `TrackInfo::max_deciding`.
257
1340925
	#[pallet::storage]
258
	pub type TrackQueue<T: Config<I>, I: 'static = ()> = StorageMap<
259
		_,
260
		Twox64Concat,
261
		TrackIdOf<T, I>,
262
		BoundedVec<(ReferendumIndex, T::Votes), T::MaxQueued>,
263
		ValueQuery,
264
	>;
265

            
266
	/// The number of referenda being decided currently.
267
12
	#[pallet::storage]
268
	pub type DecidingCount<T: Config<I>, I: 'static = ()> =
269
		StorageMap<_, Twox64Concat, TrackIdOf<T, I>, u32, ValueQuery>;
270

            
271
	/// The metadata is a general information concerning the referendum.
272
	/// The `Hash` refers to the preimage of the `Preimages` provider which can be a JSON
273
	/// dump or IPFS hash of a JSON file.
274
	///
275
	/// Consider a garbage collection for a metadata of finished referendums to `unrequest` (remove)
276
	/// large preimages.
277
214860
	#[pallet::storage]
278
	pub type MetadataOf<T: Config<I>, I: 'static = ()> =
279
		StorageMap<_, Blake2_128Concat, ReferendumIndex, T::Hash>;
280

            
281
	#[pallet::event]
282
948
	#[pallet::generate_deposit(pub(super) fn deposit_event)]
283
	pub enum Event<T: Config<I>, I: 'static = ()> {
284
		/// A referendum has been submitted.
285
		Submitted {
286
			/// Index of the referendum.
287
			index: ReferendumIndex,
288
			/// The track (and by extension proposal dispatch origin) of this referendum.
289
			track: TrackIdOf<T, I>,
290
			/// The proposal for the referendum.
291
			proposal: BoundedCallOf<T, I>,
292
		},
293
		/// The decision deposit has been placed.
294
		DecisionDepositPlaced {
295
			/// Index of the referendum.
296
			index: ReferendumIndex,
297
			/// The account who placed the deposit.
298
			who: T::AccountId,
299
			/// The amount placed by the account.
300
			amount: BalanceOf<T, I>,
301
		},
302
		/// The decision deposit has been refunded.
303
		DecisionDepositRefunded {
304
			/// Index of the referendum.
305
			index: ReferendumIndex,
306
			/// The account who placed the deposit.
307
			who: T::AccountId,
308
			/// The amount placed by the account.
309
			amount: BalanceOf<T, I>,
310
		},
311
		/// A deposit has been slashed.
312
		DepositSlashed {
313
			/// The account who placed the deposit.
314
			who: T::AccountId,
315
			/// The amount placed by the account.
316
			amount: BalanceOf<T, I>,
317
		},
318
		/// A referendum has moved into the deciding phase.
319
		DecisionStarted {
320
			/// Index of the referendum.
321
			index: ReferendumIndex,
322
			/// The track (and by extension proposal dispatch origin) of this referendum.
323
			track: TrackIdOf<T, I>,
324
			/// The proposal for the referendum.
325
			proposal: BoundedCallOf<T, I>,
326
			/// The current tally of votes in this referendum.
327
			tally: T::Tally,
328
		},
329
		ConfirmStarted {
330
			/// Index of the referendum.
331
			index: ReferendumIndex,
332
		},
333
		ConfirmAborted {
334
			/// Index of the referendum.
335
			index: ReferendumIndex,
336
		},
337
		/// A referendum has ended its confirmation phase and is ready for approval.
338
		Confirmed {
339
			/// Index of the referendum.
340
			index: ReferendumIndex,
341
			/// The final tally of votes in this referendum.
342
			tally: T::Tally,
343
		},
344
		/// A referendum has been approved and its proposal has been scheduled.
345
		Approved {
346
			/// Index of the referendum.
347
			index: ReferendumIndex,
348
		},
349
		/// A proposal has been rejected by referendum.
350
		Rejected {
351
			/// Index of the referendum.
352
			index: ReferendumIndex,
353
			/// The final tally of votes in this referendum.
354
			tally: T::Tally,
355
		},
356
		/// A referendum has been timed out without being decided.
357
		TimedOut {
358
			/// Index of the referendum.
359
			index: ReferendumIndex,
360
			/// The final tally of votes in this referendum.
361
			tally: T::Tally,
362
		},
363
		/// A referendum has been cancelled.
364
		Cancelled {
365
			/// Index of the referendum.
366
			index: ReferendumIndex,
367
			/// The final tally of votes in this referendum.
368
			tally: T::Tally,
369
		},
370
		/// A referendum has been killed.
371
		Killed {
372
			/// Index of the referendum.
373
			index: ReferendumIndex,
374
			/// The final tally of votes in this referendum.
375
			tally: T::Tally,
376
		},
377
		/// The submission deposit has been refunded.
378
		SubmissionDepositRefunded {
379
			/// Index of the referendum.
380
			index: ReferendumIndex,
381
			/// The account who placed the deposit.
382
			who: T::AccountId,
383
			/// The amount placed by the account.
384
			amount: BalanceOf<T, I>,
385
		},
386
		/// Metadata for a referendum has been set.
387
		MetadataSet {
388
			/// Index of the referendum.
389
			index: ReferendumIndex,
390
			/// Preimage hash.
391
			hash: T::Hash,
392
		},
393
		/// Metadata for a referendum has been cleared.
394
		MetadataCleared {
395
			/// Index of the referendum.
396
			index: ReferendumIndex,
397
			/// Preimage hash.
398
			hash: T::Hash,
399
		},
400
	}
401

            
402
3210
	#[pallet::error]
403
	pub enum Error<T, I = ()> {
404
		/// Referendum is not ongoing.
405
		NotOngoing,
406
		/// Referendum's decision deposit is already paid.
407
		HasDeposit,
408
		/// The track identifier given was invalid.
409
		BadTrack,
410
		/// There are already a full complement of referenda in progress for this track.
411
		Full,
412
		/// The queue of the track is empty.
413
		QueueEmpty,
414
		/// The referendum index provided is invalid in this context.
415
		BadReferendum,
416
		/// There was nothing to do in the advancement.
417
		NothingToDo,
418
		/// No track exists for the proposal origin.
419
		NoTrack,
420
		/// Any deposit cannot be refunded until after the decision is over.
421
		Unfinished,
422
		/// The deposit refunder is not the depositor.
423
		NoPermission,
424
		/// The deposit cannot be refunded since none was made.
425
		NoDeposit,
426
		/// The referendum status is invalid for this operation.
427
		BadStatus,
428
		/// The preimage does not exist.
429
		PreimageNotExist,
430
		/// The preimage is stored with a different length than the one provided.
431
		PreimageStoredWithDifferentLength,
432
	}
433

            
434
1108734
	#[pallet::hooks]
435
	impl<T: Config<I>, I: 'static> Hooks<BlockNumberFor<T>> for Pallet<T, I> {
436
		#[cfg(feature = "try-runtime")]
437
107274
		fn try_state(_n: BlockNumberFor<T>) -> Result<(), sp_runtime::TryRuntimeError> {
438
107274
			Self::do_try_state()?;
439
107274
			Ok(())
440
107274
		}
441

            
442
		#[cfg(any(feature = "std", test))]
443
107274
		fn integrity_test() {
444
107274
			T::Tracks::check_integrity().expect("Static tracks configuration is valid.");
445
107274
		}
446
	}
447

            
448
20787
	#[pallet::call]
449
	impl<T: Config<I>, I: 'static> Pallet<T, I> {
450
		/// Propose a referendum on a privileged action.
451
		///
452
		/// - `origin`: must be `SubmitOrigin` and the account must have `SubmissionDeposit` funds
453
		///   available.
454
		/// - `proposal_origin`: The origin from which the proposal should be executed.
455
		/// - `proposal`: The proposal.
456
		/// - `enactment_moment`: The moment that the proposal should be enacted.
457
		///
458
		/// Emits `Submitted`.
459
		#[pallet::call_index(0)]
460
		#[pallet::weight(T::WeightInfo::submit())]
461
		pub fn submit(
462
			origin: OriginFor<T>,
463
			proposal_origin: Box<PalletsOriginOf<T>>,
464
			proposal: BoundedCallOf<T, I>,
465
			enactment_moment: DispatchTime<BlockNumberFor<T>>,
466
1617
		) -> DispatchResult {
467
1617
			let proposal_origin = *proposal_origin;
468
1617
			let who = T::SubmitOrigin::ensure_origin(origin, &proposal_origin)?;
469

            
470
			// If the pre-image is already stored, ensure that it has the same length as given in
471
			// `proposal`.
472
			if let (Some(preimage_len), Some(proposal_len)) =
473
1194
				(proposal.lookup_hash().and_then(|h| T::Preimages::len(&h)), proposal.lookup_len())
474
			{
475
				if preimage_len != proposal_len {
476
					return Err(Error::<T, I>::PreimageStoredWithDifferentLength.into())
477
				}
478
1194
			}
479

            
480
966
			let track =
481
1194
				T::Tracks::track_for(&proposal_origin).map_err(|_| Error::<T, I>::NoTrack)?;
482
966
			let submission_deposit = Self::take_deposit(who, T::SubmissionDeposit::get())?;
483
1248
			let index = ReferendumCount::<T, I>::mutate(|x| {
484
936
				let r = *x;
485
936
				*x += 1;
486
936
				r
487
1248
			});
488
936
			let now = frame_system::Pallet::<T>::block_number();
489
936
			let nudge_call =
490
936
				T::Preimages::bound(CallOf::<T, I>::from(Call::nudge_referendum { index }))?;
491
936
			let status = ReferendumStatus {
492
936
				track,
493
936
				origin: proposal_origin,
494
936
				proposal: proposal.clone(),
495
936
				enactment: enactment_moment,
496
936
				submitted: now,
497
936
				submission_deposit,
498
936
				decision_deposit: None,
499
936
				deciding: None,
500
936
				tally: TallyOf::<T, I>::new(track),
501
936
				in_queue: false,
502
936
				alarm: Self::set_alarm(nudge_call, now.saturating_add(T::UndecidingTimeout::get())),
503
936
			};
504
936
			ReferendumInfoFor::<T, I>::insert(index, ReferendumInfo::Ongoing(status));
505
936

            
506
936
			Self::deposit_event(Event::<T, I>::Submitted { index, track, proposal });
507
936
			Ok(())
508
		}
509

            
510
		/// Post the Decision Deposit for a referendum.
511
		///
512
		/// - `origin`: must be `Signed` and the account must have funds available for the
513
		///   referendum's track's Decision Deposit.
514
		/// - `index`: The index of the submitted referendum whose Decision Deposit is yet to be
515
		///   posted.
516
		///
517
		/// Emits `DecisionDepositPlaced`.
518
		#[pallet::call_index(1)]
519
		#[pallet::weight(ServiceBranch::max_weight_of_deposit::<T, I>())]
520
		pub fn place_decision_deposit(
521
			origin: OriginFor<T>,
522
			index: ReferendumIndex,
523
477
		) -> DispatchResultWithPostInfo {
524
477
			let who = ensure_signed(origin)?;
525
477
			let mut status = Self::ensure_ongoing(index)?;
526
9
			ensure!(status.decision_deposit.is_none(), Error::<T, I>::HasDeposit);
527
6
			let track = Self::track(status.track).ok_or(Error::<T, I>::NoTrack)?;
528
6
			status.decision_deposit =
529
6
				Some(Self::take_deposit(who.clone(), track.decision_deposit)?);
530
6
			let now = frame_system::Pallet::<T>::block_number();
531
6
			let (info, _, branch) = Self::service_referendum(now, index, status);
532
6
			ReferendumInfoFor::<T, I>::insert(index, info);
533
6
			let e =
534
6
				Event::<T, I>::DecisionDepositPlaced { index, who, amount: track.decision_deposit };
535
6
			Self::deposit_event(e);
536
6
			Ok(branch.weight_of_deposit::<T, I>().into())
537
		}
538

            
539
		/// Refund the Decision Deposit for a closed referendum back to the depositor.
540
		///
541
		/// - `origin`: must be `Signed` or `Root`.
542
		/// - `index`: The index of a closed referendum whose Decision Deposit has not yet been
543
		///   refunded.
544
		///
545
		/// Emits `DecisionDepositRefunded`.
546
		#[pallet::call_index(2)]
547
		#[pallet::weight(T::WeightInfo::refund_decision_deposit())]
548
		pub fn refund_decision_deposit(
549
			origin: OriginFor<T>,
550
			index: ReferendumIndex,
551
228
		) -> DispatchResult {
552
228
			ensure_signed_or_root(origin)?;
553
			let mut info =
554
228
				ReferendumInfoFor::<T, I>::get(index).ok_or(Error::<T, I>::BadReferendum)?;
555
			let deposit = info
556
				.take_decision_deposit()
557
				.map_err(|_| Error::<T, I>::Unfinished)?
558
				.ok_or(Error::<T, I>::NoDeposit)?;
559
			Self::refund_deposit(Some(deposit.clone()));
560
			ReferendumInfoFor::<T, I>::insert(index, info);
561
			let e = Event::<T, I>::DecisionDepositRefunded {
562
				index,
563
				who: deposit.who,
564
				amount: deposit.amount,
565
			};
566
			Self::deposit_event(e);
567
			Ok(())
568
		}
569

            
570
		/// Cancel an ongoing referendum.
571
		///
572
		/// - `origin`: must be the `CancelOrigin`.
573
		/// - `index`: The index of the referendum to be cancelled.
574
		///
575
		/// Emits `Cancelled`.
576
		#[pallet::call_index(3)]
577
		#[pallet::weight(T::WeightInfo::cancel())]
578
315
		pub fn cancel(origin: OriginFor<T>, index: ReferendumIndex) -> DispatchResult {
579
315
			T::CancelOrigin::ensure_origin(origin)?;
580
			let status = Self::ensure_ongoing(index)?;
581
			if let Some((_, last_alarm)) = status.alarm {
582
				let _ = T::Scheduler::cancel(last_alarm);
583
			}
584
			Self::note_one_fewer_deciding(status.track);
585
			Self::deposit_event(Event::<T, I>::Cancelled { index, tally: status.tally });
586
			let info = ReferendumInfo::Cancelled(
587
				frame_system::Pallet::<T>::block_number(),
588
				Some(status.submission_deposit),
589
				status.decision_deposit,
590
			);
591
			ReferendumInfoFor::<T, I>::insert(index, info);
592
			Ok(())
593
		}
594

            
595
		/// Cancel an ongoing referendum and slash the deposits.
596
		///
597
		/// - `origin`: must be the `KillOrigin`.
598
		/// - `index`: The index of the referendum to be cancelled.
599
		///
600
		/// Emits `Killed` and `DepositSlashed`.
601
		#[pallet::call_index(4)]
602
		#[pallet::weight(T::WeightInfo::kill())]
603
360
		pub fn kill(origin: OriginFor<T>, index: ReferendumIndex) -> DispatchResult {
604
360
			T::KillOrigin::ensure_origin(origin)?;
605
			let status = Self::ensure_ongoing(index)?;
606
			if let Some((_, last_alarm)) = status.alarm {
607
				let _ = T::Scheduler::cancel(last_alarm);
608
			}
609
			Self::note_one_fewer_deciding(status.track);
610
			Self::deposit_event(Event::<T, I>::Killed { index, tally: status.tally });
611
			Self::slash_deposit(Some(status.submission_deposit.clone()));
612
			Self::slash_deposit(status.decision_deposit.clone());
613
			Self::do_clear_metadata(index);
614
			let info = ReferendumInfo::Killed(frame_system::Pallet::<T>::block_number());
615
			ReferendumInfoFor::<T, I>::insert(index, info);
616
			Ok(())
617
		}
618

            
619
		/// Advance a referendum onto its next logical state. Only used internally.
620
		///
621
		/// - `origin`: must be `Root`.
622
		/// - `index`: the referendum to be advanced.
623
		#[pallet::call_index(5)]
624
		#[pallet::weight(ServiceBranch::max_weight_of_nudge::<T, I>())]
625
		pub fn nudge_referendum(
626
			origin: OriginFor<T>,
627
			index: ReferendumIndex,
628
111
		) -> DispatchResultWithPostInfo {
629
111
			ensure_root(origin)?;
630
			let now = frame_system::Pallet::<T>::block_number();
631
			let mut status = Self::ensure_ongoing(index)?;
632
			// This is our wake-up, so we can disregard the alarm.
633
			status.alarm = None;
634
			let (info, dirty, branch) = Self::service_referendum(now, index, status);
635
			if dirty {
636
				ReferendumInfoFor::<T, I>::insert(index, info);
637
			}
638
			Ok(Some(branch.weight_of_nudge::<T, I>()).into())
639
		}
640

            
641
		/// Advance a track onto its next logical state. Only used internally.
642
		///
643
		/// - `origin`: must be `Root`.
644
		/// - `track`: the track to be advanced.
645
		///
646
		/// Action item for when there is now one fewer referendum in the deciding phase and the
647
		/// `DecidingCount` is not yet updated. This means that we should either:
648
		/// - begin deciding another referendum (and leave `DecidingCount` alone); or
649
		/// - decrement `DecidingCount`.
650
		#[pallet::call_index(6)]
651
		#[pallet::weight(OneFewerDecidingBranch::max_weight::<T, I>())]
652
		pub fn one_fewer_deciding(
653
			origin: OriginFor<T>,
654
			track: TrackIdOf<T, I>,
655
147
		) -> DispatchResultWithPostInfo {
656
147
			ensure_root(origin)?;
657
			let track_info = T::Tracks::info(track).ok_or(Error::<T, I>::BadTrack)?;
658
			let mut track_queue = TrackQueue::<T, I>::get(track);
659
			let branch =
660
				if let Some((index, mut status)) = Self::next_for_deciding(&mut track_queue) {
661
					let now = frame_system::Pallet::<T>::block_number();
662
					let (maybe_alarm, branch) =
663
						Self::begin_deciding(&mut status, index, now, track_info);
664
					if let Some(set_alarm) = maybe_alarm {
665
						Self::ensure_alarm_at(&mut status, index, set_alarm);
666
					}
667
					ReferendumInfoFor::<T, I>::insert(index, ReferendumInfo::Ongoing(status));
668
					TrackQueue::<T, I>::insert(track, track_queue);
669
					branch.into()
670
				} else {
671
					DecidingCount::<T, I>::mutate(track, |x| x.saturating_dec());
672
					OneFewerDecidingBranch::QueueEmpty
673
				};
674
			Ok(Some(branch.weight::<T, I>()).into())
675
		}
676

            
677
		/// Refund the Submission Deposit for a closed referendum back to the depositor.
678
		///
679
		/// - `origin`: must be `Signed` or `Root`.
680
		/// - `index`: The index of a closed referendum whose Submission Deposit has not yet been
681
		///   refunded.
682
		///
683
		/// Emits `SubmissionDepositRefunded`.
684
		#[pallet::call_index(7)]
685
		#[pallet::weight(T::WeightInfo::refund_submission_deposit())]
686
		pub fn refund_submission_deposit(
687
			origin: OriginFor<T>,
688
			index: ReferendumIndex,
689
66
		) -> DispatchResult {
690
66
			ensure_signed_or_root(origin)?;
691
			let mut info =
692
66
				ReferendumInfoFor::<T, I>::get(index).ok_or(Error::<T, I>::BadReferendum)?;
693
			let deposit = info
694
				.take_submission_deposit()
695
				.map_err(|_| Error::<T, I>::BadStatus)?
696
				.ok_or(Error::<T, I>::NoDeposit)?;
697
			Self::refund_deposit(Some(deposit.clone()));
698
			ReferendumInfoFor::<T, I>::insert(index, info);
699
			let e = Event::<T, I>::SubmissionDepositRefunded {
700
				index,
701
				who: deposit.who,
702
				amount: deposit.amount,
703
			};
704
			Self::deposit_event(e);
705
			Ok(())
706
		}
707

            
708
		/// Set or clear metadata of a referendum.
709
		///
710
		/// Parameters:
711
		/// - `origin`: Must be `Signed` by a creator of a referendum or by anyone to clear a
712
		///   metadata of a finished referendum.
713
		/// - `index`:  The index of a referendum to set or clear metadata for.
714
		/// - `maybe_hash`: The hash of an on-chain stored preimage. `None` to clear a metadata.
715
		#[pallet::call_index(8)]
716
		#[pallet::weight(
717
			maybe_hash.map_or(
718
132
				T::WeightInfo::clear_metadata(), |_| T::WeightInfo::set_some_metadata())
719
			)]
720
		pub fn set_metadata(
721
			origin: OriginFor<T>,
722
			index: ReferendumIndex,
723
			maybe_hash: Option<T::Hash>,
724
435
		) -> DispatchResult {
725
435
			let who = ensure_signed(origin)?;
726
435
			if let Some(hash) = maybe_hash {
727
123
				let status = Self::ensure_ongoing(index)?;
728
				ensure!(status.submission_deposit.who == who, Error::<T, I>::NoPermission);
729
				ensure!(T::Preimages::len(&hash).is_some(), Error::<T, I>::PreimageNotExist);
730
				MetadataOf::<T, I>::insert(index, hash);
731
				Self::deposit_event(Event::<T, I>::MetadataSet { index, hash });
732
				Ok(())
733
			} else {
734
312
				if let Some(status) = Self::ensure_ongoing(index).ok() {
735
					ensure!(status.submission_deposit.who == who, Error::<T, I>::NoPermission);
736
312
				}
737
312
				Self::do_clear_metadata(index);
738
312
				Ok(())
739
			}
740
		}
741
	}
742
}
743

            
744
impl<T: Config<I>, I: 'static> Polling<T::Tally> for Pallet<T, I> {
745
	type Index = ReferendumIndex;
746
	type Votes = VotesOf<T, I>;
747
	type Moment = BlockNumberFor<T>;
748
	type Class = TrackIdOf<T, I>;
749

            
750
597
	fn classes() -> Vec<Self::Class> {
751
9154
		T::Tracks::tracks().iter().map(|x| x.0).collect()
752
597
	}
753

            
754
	fn access_poll<R>(
755
		index: Self::Index,
756
		f: impl FnOnce(PollStatus<&mut T::Tally, BlockNumberFor<T>, TrackIdOf<T, I>>) -> R,
757
	) -> R {
758
		match ReferendumInfoFor::<T, I>::get(index) {
759
			Some(ReferendumInfo::Ongoing(mut status)) => {
760
				let result = f(PollStatus::Ongoing(&mut status.tally, status.track));
761
				let now = frame_system::Pallet::<T>::block_number();
762
				Self::ensure_alarm_at(&mut status, index, now + One::one());
763
				ReferendumInfoFor::<T, I>::insert(index, ReferendumInfo::Ongoing(status));
764
				result
765
			},
766
			Some(ReferendumInfo::Approved(end, ..)) => f(PollStatus::Completed(end, true)),
767
			Some(ReferendumInfo::Rejected(end, ..)) => f(PollStatus::Completed(end, false)),
768
			_ => f(PollStatus::None),
769
		}
770
	}
771

            
772
315
	fn try_access_poll<R>(
773
315
		index: Self::Index,
774
315
		f: impl FnOnce(
775
315
			PollStatus<&mut T::Tally, BlockNumberFor<T>, TrackIdOf<T, I>>,
776
315
		) -> Result<R, DispatchError>,
777
315
	) -> Result<R, DispatchError> {
778
315
		match ReferendumInfoFor::<T, I>::get(index) {
779
48
			Some(ReferendumInfo::Ongoing(mut status)) => {
780
48
				let result = f(PollStatus::Ongoing(&mut status.tally, status.track))?;
781
48
				let now = frame_system::Pallet::<T>::block_number();
782
48
				Self::ensure_alarm_at(&mut status, index, now + One::one());
783
48
				ReferendumInfoFor::<T, I>::insert(index, ReferendumInfo::Ongoing(status));
784
48
				Ok(result)
785
			},
786
			Some(ReferendumInfo::Approved(end, ..)) => f(PollStatus::Completed(end, true)),
787
			Some(ReferendumInfo::Rejected(end, ..)) => f(PollStatus::Completed(end, false)),
788
267
			_ => f(PollStatus::None),
789
		}
790
315
	}
791

            
792
177
	fn as_ongoing(index: Self::Index) -> Option<(T::Tally, TrackIdOf<T, I>)> {
793
177
		Self::ensure_ongoing(index).ok().map(|x| (x.tally, x.track))
794
177
	}
795

            
796
	#[cfg(feature = "runtime-benchmarks")]
797
	fn create_ongoing(class: Self::Class) -> Result<Self::Index, ()> {
798
		let index = ReferendumCount::<T, I>::mutate(|x| {
799
			let r = *x;
800
			*x += 1;
801
			r
802
		});
803
		let now = frame_system::Pallet::<T>::block_number();
804
		let dummy_account_id =
805
			codec::Decode::decode(&mut sp_runtime::traits::TrailingZeroInput::new(&b"dummy"[..]))
806
				.expect("infinite length input; no invalid inputs for type; qed");
807
		let mut status = ReferendumStatusOf::<T, I> {
808
			track: class,
809
			origin: frame_support::dispatch::RawOrigin::Root.into(),
810
			proposal: T::Preimages::bound(CallOf::<T, I>::from(Call::nudge_referendum { index }))
811
				.map_err(|_| ())?,
812
			enactment: DispatchTime::After(Zero::zero()),
813
			submitted: now,
814
			submission_deposit: Deposit { who: dummy_account_id, amount: Zero::zero() },
815
			decision_deposit: None,
816
			deciding: None,
817
			tally: TallyOf::<T, I>::new(class),
818
			in_queue: false,
819
			alarm: None,
820
		};
821
		Self::ensure_alarm_at(&mut status, index, sp_runtime::traits::Bounded::max_value());
822
		ReferendumInfoFor::<T, I>::insert(index, ReferendumInfo::Ongoing(status));
823
		Ok(index)
824
	}
825

            
826
	#[cfg(feature = "runtime-benchmarks")]
827
	fn end_ongoing(index: Self::Index, approved: bool) -> Result<(), ()> {
828
		let mut status = Self::ensure_ongoing(index).map_err(|_| ())?;
829
		Self::ensure_no_alarm(&mut status);
830
		Self::note_one_fewer_deciding(status.track);
831
		let now = frame_system::Pallet::<T>::block_number();
832
		let info = if approved {
833
			ReferendumInfo::Approved(now, Some(status.submission_deposit), status.decision_deposit)
834
		} else {
835
			ReferendumInfo::Rejected(now, Some(status.submission_deposit), status.decision_deposit)
836
		};
837
		ReferendumInfoFor::<T, I>::insert(index, info);
838
		Ok(())
839
	}
840

            
841
	#[cfg(feature = "runtime-benchmarks")]
842
	fn max_ongoing() -> (Self::Class, u32) {
843
		let r = T::Tracks::tracks()
844
			.iter()
845
			.max_by_key(|(_, info)| info.max_deciding)
846
			.expect("Always one class");
847
		(r.0, r.1.max_deciding)
848
	}
849
}
850

            
851
impl<T: Config<I>, I: 'static> Pallet<T, I> {
852
	/// Check that referendum `index` is in the `Ongoing` state and return the `ReferendumStatus`
853
	/// value, or `Err` otherwise.
854
1089
	pub fn ensure_ongoing(
855
1089
		index: ReferendumIndex,
856
1089
	) -> Result<ReferendumStatusOf<T, I>, DispatchError> {
857
1089
		match ReferendumInfoFor::<T, I>::get(index) {
858
9
			Some(ReferendumInfo::Ongoing(status)) => Ok(status),
859
1080
			_ => Err(Error::<T, I>::NotOngoing.into()),
860
		}
861
1089
	}
862

            
863
	/// Returns whether the referendum is passing.
864
	/// Referendum must be ongoing and its track must exist.
865
	pub fn is_referendum_passing(ref_index: ReferendumIndex) -> Result<bool, DispatchError> {
866
		let info = ReferendumInfoFor::<T, I>::get(ref_index).ok_or(Error::<T, I>::BadReferendum)?;
867
		match info {
868
			ReferendumInfo::Ongoing(status) => {
869
				let track = Self::track(status.track).ok_or(Error::<T, I>::NoTrack)?;
870
				let elapsed = if let Some(deciding) = status.deciding {
871
					frame_system::Pallet::<T>::block_number().saturating_sub(deciding.since)
872
				} else {
873
					Zero::zero()
874
				};
875
				Ok(Self::is_passing(
876
					&status.tally,
877
					elapsed,
878
					track.decision_period,
879
					&track.min_support,
880
					&track.min_approval,
881
					status.track,
882
				))
883
			},
884
			_ => Err(Error::<T, I>::NotOngoing.into()),
885
		}
886
	}
887

            
888
	// Enqueue a proposal from a referendum which has presumably passed.
889
	fn schedule_enactment(
890
		index: ReferendumIndex,
891
		track: &TrackInfoOf<T, I>,
892
		desired: DispatchTime<BlockNumberFor<T>>,
893
		origin: PalletsOriginOf<T>,
894
		call: BoundedCallOf<T, I>,
895
	) {
896
		let now = frame_system::Pallet::<T>::block_number();
897
		// Earliest allowed block is always at minimum the next block.
898
		let earliest_allowed = now.saturating_add(track.min_enactment_period.max(One::one()));
899
		let desired = desired.evaluate(now);
900
		let ok = T::Scheduler::schedule_named(
901
			(ASSEMBLY_ID, "enactment", index).using_encoded(sp_io::hashing::blake2_256),
902
			DispatchTime::At(desired.max(earliest_allowed)),
903
			None,
904
			63,
905
			origin,
906
			call,
907
		)
908
		.is_ok();
909
		debug_assert!(ok, "LOGIC ERROR: bake_referendum/schedule_named failed");
910
	}
911

            
912
	/// Set an alarm to dispatch `call` at block number `when`.
913
990
	fn set_alarm(
914
990
		call: BoundedCallOf<T, I>,
915
990
		when: BlockNumberFor<T>,
916
990
	) -> Option<(BlockNumberFor<T>, ScheduleAddressOf<T, I>)> {
917
990
		let alarm_interval = T::AlarmInterval::get().max(One::one());
918
990
		// Alarm must go off no earlier than `when`.
919
990
		// This rounds `when` upwards to the next multiple of `alarm_interval`.
920
990
		let when = (when.saturating_add(alarm_interval.saturating_sub(One::one())) /
921
990
			alarm_interval)
922
990
			.saturating_mul(alarm_interval);
923
990
		let result = T::Scheduler::schedule(
924
990
			DispatchTime::At(when),
925
990
			None,
926
990
			128u8,
927
990
			frame_system::RawOrigin::Root.into(),
928
990
			call,
929
990
		);
930
990
		debug_assert!(
931
			result.is_ok(),
932
			"Unable to schedule a new alarm at #{:?} (now: #{:?}), scheduler error: `{:?}`",
933
			when,
934
			frame_system::Pallet::<T>::block_number(),
935
			result.unwrap_err(),
936
		);
937
990
		result.ok().map(|x| (when, x))
938
990
	}
939

            
940
	/// Mutate a referendum's `status` into the correct deciding state.
941
	///
942
	/// - `now` is the current block number.
943
	/// - `track` is the track info for the referendum.
944
	///
945
	/// This will properly set up the `confirming` item.
946
6
	fn begin_deciding(
947
6
		status: &mut ReferendumStatusOf<T, I>,
948
6
		index: ReferendumIndex,
949
6
		now: BlockNumberFor<T>,
950
6
		track: &TrackInfoOf<T, I>,
951
6
	) -> (Option<BlockNumberFor<T>>, BeginDecidingBranch) {
952
6
		let is_passing = Self::is_passing(
953
6
			&status.tally,
954
6
			Zero::zero(),
955
6
			track.decision_period,
956
6
			&track.min_support,
957
6
			&track.min_approval,
958
6
			status.track,
959
6
		);
960
6
		status.in_queue = false;
961
6
		Self::deposit_event(Event::<T, I>::DecisionStarted {
962
6
			index,
963
6
			tally: status.tally.clone(),
964
6
			proposal: status.proposal.clone(),
965
6
			track: status.track,
966
6
		});
967
6
		let confirming = if is_passing {
968
			Self::deposit_event(Event::<T, I>::ConfirmStarted { index });
969
			Some(now.saturating_add(track.confirm_period))
970
		} else {
971
6
			None
972
		};
973
6
		let deciding_status = DecidingStatus { since: now, confirming };
974
6
		let alarm = Self::decision_time(&deciding_status, &status.tally, status.track, track)
975
6
			.max(now.saturating_add(One::one()));
976
6
		status.deciding = Some(deciding_status);
977
6
		let branch =
978
6
			if is_passing { BeginDecidingBranch::Passing } else { BeginDecidingBranch::Failing };
979
6
		(Some(alarm), branch)
980
6
	}
981

            
982
	/// If it returns `Some`, deciding has begun and it needs waking at the given block number. The
983
	/// second item is the flag for whether it is confirming or not.
984
	///
985
	/// If `None`, then it is queued and should be nudged automatically as the queue gets drained.
986
6
	fn ready_for_deciding(
987
6
		now: BlockNumberFor<T>,
988
6
		track: &TrackInfoOf<T, I>,
989
6
		index: ReferendumIndex,
990
6
		status: &mut ReferendumStatusOf<T, I>,
991
6
	) -> (Option<BlockNumberFor<T>>, ServiceBranch) {
992
6
		let deciding_count = DecidingCount::<T, I>::get(status.track);
993
6
		if deciding_count < track.max_deciding {
994
			// Begin deciding.
995
6
			DecidingCount::<T, I>::insert(status.track, deciding_count.saturating_add(1));
996
6
			let r = Self::begin_deciding(status, index, now, track);
997
6
			(r.0, r.1.into())
998
		} else {
999
			// Add to queue.
			let item = (index, status.tally.ayes(status.track));
			status.in_queue = true;
			TrackQueue::<T, I>::mutate(status.track, |q| q.insert_sorted_by_key(item, |x| x.1));
			(None, ServiceBranch::Queued)
		}
6
	}
	/// Grab the index and status for the referendum which is the highest priority of those for the
	/// given track which are ready for being decided.
	fn next_for_deciding(
		track_queue: &mut BoundedVec<(u32, VotesOf<T, I>), T::MaxQueued>,
	) -> Option<(ReferendumIndex, ReferendumStatusOf<T, I>)> {
		loop {
			let (index, _) = track_queue.pop()?;
			match Self::ensure_ongoing(index) {
				Ok(s) => return Some((index, s)),
				Err(_) => {}, // referendum already timedout or was cancelled.
			}
		}
	}
	/// Schedule a call to `one_fewer_deciding` function via the dispatchable
	/// `defer_one_fewer_deciding`. We could theoretically call it immediately (and it would be
	/// overall more efficient), however the weights become rather less easy to measure.
	fn note_one_fewer_deciding(track: TrackIdOf<T, I>) {
		// Set an alarm call for the next block to nudge the track along.
		let now = frame_system::Pallet::<T>::block_number();
		let next_block = now + One::one();
		let call = match T::Preimages::bound(CallOf::<T, I>::from(Call::one_fewer_deciding {
			track,
		})) {
			Ok(c) => c,
			Err(_) => {
				debug_assert!(false, "Unable to create a bounded call from `one_fewer_deciding`??",);
				return
			},
		};
		Self::set_alarm(call, next_block);
	}
	/// Ensure that a `service_referendum` alarm happens for the referendum `index` at `alarm`.
	///
	/// This will do nothing if the alarm is already set.
	///
	/// Returns `false` if nothing changed.
54
	fn ensure_alarm_at(
54
		status: &mut ReferendumStatusOf<T, I>,
54
		index: ReferendumIndex,
54
		alarm: BlockNumberFor<T>,
54
	) -> bool {
54
		if status.alarm.as_ref().map_or(true, |&(when, _)| when != alarm) {
			// Either no alarm or one that was different
54
			Self::ensure_no_alarm(status);
54
			let call =
54
				match T::Preimages::bound(CallOf::<T, I>::from(Call::nudge_referendum { index })) {
54
					Ok(c) => c,
					Err(_) => {
						debug_assert!(
							false,
							"Unable to create a bounded call from `nudge_referendum`??",
						);
						return false
					},
				};
54
			status.alarm = Self::set_alarm(call, alarm);
54
			true
		} else {
			false
		}
54
	}
	/// Advance the state of a referendum, which comes down to:
	/// - If it's ready to be decided, start deciding;
	/// - If it's not ready to be decided and non-deciding timeout has passed, fail;
	/// - If it's ongoing and passing, ensure confirming; if at end of confirmation period, pass.
	/// - If it's ongoing and not passing, stop confirming; if it has reached end time, fail.
	///
	/// Weight will be a bit different depending on what it does, but it's designed so as not to
	/// differ dramatically, especially if `MaxQueue` is kept small. In particular _there are no
	/// balance operations in here_.
	///
	/// In terms of storage, every call to it is expected to access:
	/// - The scheduler, either to insert, remove or alter an entry;
	/// - `TrackQueue`, which should be a `BoundedVec` with a low limit (8-16);
	/// - `DecidingCount`.
	///
	/// Both of the two storage items will only have as many items as there are different tracks,
	/// perhaps around 10 and should be whitelisted.
	///
	/// The heaviest branch is likely to be when a proposal is placed into, or moved within, the
	/// `TrackQueue`. Basically this happens when a referendum is in the deciding queue and receives
	/// a vote, or when it moves into the deciding queue.
6
	fn service_referendum(
6
		now: BlockNumberFor<T>,
6
		index: ReferendumIndex,
6
		mut status: ReferendumStatusOf<T, I>,
6
	) -> (ReferendumInfoOf<T, I>, bool, ServiceBranch) {
6
		let mut dirty = false;
		// Should it begin being decided?
6
		let track = match Self::track(status.track) {
6
			Some(x) => x,
			None => return (ReferendumInfo::Ongoing(status), false, ServiceBranch::Fail),
		};
		// Default the alarm to the end of the world.
6
		let timeout = status.submitted + T::UndecidingTimeout::get();
6
		let mut alarm = BlockNumberFor::<T>::max_value();
6
		let branch;
6
		match &mut status.deciding {
			None => {
				// Are we already queued for deciding?
6
				if status.in_queue {
					// Does our position in the queue need updating?
					let ayes = status.tally.ayes(status.track);
					let mut queue = TrackQueue::<T, I>::get(status.track);
					let maybe_old_pos = queue.iter().position(|(x, _)| *x == index);
					let new_pos = queue.binary_search_by_key(&ayes, |x| x.1).unwrap_or_else(|x| x);
					branch = if maybe_old_pos.is_none() && new_pos > 0 {
						// Just insert.
						let _ = queue.force_insert_keep_right(new_pos, (index, ayes));
						ServiceBranch::RequeuedInsertion
					} else if let Some(old_pos) = maybe_old_pos {
						// We were in the queue - slide into the correct position.
						queue[old_pos].1 = ayes;
						queue.slide(old_pos, new_pos);
						ServiceBranch::RequeuedSlide
					} else {
						ServiceBranch::NotQueued
					};
					TrackQueue::<T, I>::insert(status.track, queue);
				} else {
					// Are we ready for deciding?
6
					branch = if status.decision_deposit.is_some() {
6
						let prepare_end = status.submitted.saturating_add(track.prepare_period);
6
						if now >= prepare_end {
6
							let (maybe_alarm, branch) =
6
								Self::ready_for_deciding(now, track, index, &mut status);
6
							if let Some(set_alarm) = maybe_alarm {
6
								alarm = alarm.min(set_alarm);
6
							}
6
							dirty = true;
6
							branch
						} else {
							alarm = alarm.min(prepare_end);
							ServiceBranch::Preparing
						}
					} else {
						alarm = timeout;
						ServiceBranch::NoDeposit
					}
				}
				// If we didn't move into being decided, then check the timeout.
6
				if status.deciding.is_none() && now >= timeout && !status.in_queue {
					// Too long without being decided - end it.
					Self::ensure_no_alarm(&mut status);
					Self::deposit_event(Event::<T, I>::TimedOut { index, tally: status.tally });
					return (
						ReferendumInfo::TimedOut(
							now,
							Some(status.submission_deposit),
							status.decision_deposit,
						),
						true,
						ServiceBranch::TimedOut,
					)
6
				}
			},
			Some(deciding) => {
				let is_passing = Self::is_passing(
					&status.tally,
					now.saturating_sub(deciding.since),
					track.decision_period,
					&track.min_support,
					&track.min_approval,
					status.track,
				);
				branch = if is_passing {
					match deciding.confirming {
						Some(t) if now >= t => {
							// Passed!
							Self::ensure_no_alarm(&mut status);
							Self::note_one_fewer_deciding(status.track);
							let (desired, call) = (status.enactment, status.proposal);
							Self::schedule_enactment(index, track, desired, status.origin, call);
							Self::deposit_event(Event::<T, I>::Confirmed {
								index,
								tally: status.tally,
							});
							return (
								ReferendumInfo::Approved(
									now,
									Some(status.submission_deposit),
									status.decision_deposit,
								),
								true,
								ServiceBranch::Approved,
							)
						},
						Some(_) => ServiceBranch::ContinueConfirming,
						None => {
							// Start confirming
							dirty = true;
							deciding.confirming = Some(now.saturating_add(track.confirm_period));
							Self::deposit_event(Event::<T, I>::ConfirmStarted { index });
							ServiceBranch::BeginConfirming
						},
					}
				} else {
					if now >= deciding.since.saturating_add(track.decision_period) {
						// Failed!
						Self::ensure_no_alarm(&mut status);
						Self::note_one_fewer_deciding(status.track);
						Self::deposit_event(Event::<T, I>::Rejected { index, tally: status.tally });
						return (
							ReferendumInfo::Rejected(
								now,
								Some(status.submission_deposit),
								status.decision_deposit,
							),
							true,
							ServiceBranch::Rejected,
						)
					}
					if deciding.confirming.is_some() {
						// Stop confirming
						dirty = true;
						deciding.confirming = None;
						Self::deposit_event(Event::<T, I>::ConfirmAborted { index });
						ServiceBranch::EndConfirming
					} else {
						ServiceBranch::ContinueNotConfirming
					}
				};
				alarm = Self::decision_time(deciding, &status.tally, status.track, track);
			},
		}
6
		let dirty_alarm = if alarm < BlockNumberFor::<T>::max_value() {
6
			Self::ensure_alarm_at(&mut status, index, alarm)
		} else {
			Self::ensure_no_alarm(&mut status)
		};
6
		(ReferendumInfo::Ongoing(status), dirty_alarm || dirty, branch)
6
	}
	/// Determine the point at which a referendum will be accepted, move into confirmation with the
	/// given `tally` or end with rejection (whichever happens sooner).
6
	fn decision_time(
6
		deciding: &DecidingStatusOf<T>,
6
		tally: &T::Tally,
6
		track_id: TrackIdOf<T, I>,
6
		track: &TrackInfoOf<T, I>,
6
	) -> BlockNumberFor<T> {
6
		deciding.confirming.unwrap_or_else(|| {
6
			// Set alarm to the point where the current voting would make it pass.
6
			let approval = tally.approval(track_id);
6
			let support = tally.support(track_id);
6
			let until_approval = track.min_approval.delay(approval);
6
			let until_support = track.min_support.delay(support);
6
			let offset = until_support.max(until_approval);
6
			deciding.since.saturating_add(offset.mul_ceil(track.decision_period))
6
		})
6
	}
	/// Cancel the alarm in `status`, if one exists.
54
	fn ensure_no_alarm(status: &mut ReferendumStatusOf<T, I>) -> bool {
54
		if let Some((_, last_alarm)) = status.alarm.take() {
			// Incorrect alarm - cancel it.
54
			let _ = T::Scheduler::cancel(last_alarm);
54
			true
		} else {
			false
		}
54
	}
	/// Reserve a deposit and return the `Deposit` instance.
972
	fn take_deposit(
972
		who: T::AccountId,
972
		amount: BalanceOf<T, I>,
972
	) -> Result<Deposit<T::AccountId, BalanceOf<T, I>>, DispatchError> {
972
		T::Currency::reserve(&who, amount)?;
942
		Ok(Deposit { who, amount })
972
	}
	/// Return a deposit, if `Some`.
	fn refund_deposit(deposit: Option<Deposit<T::AccountId, BalanceOf<T, I>>>) {
		if let Some(Deposit { who, amount }) = deposit {
			T::Currency::unreserve(&who, amount);
		}
	}
	/// Slash a deposit, if `Some`.
	fn slash_deposit(deposit: Option<Deposit<T::AccountId, BalanceOf<T, I>>>) {
		if let Some(Deposit { who, amount }) = deposit {
			T::Slash::on_unbalanced(T::Currency::slash_reserved(&who, amount).0);
			Self::deposit_event(Event::<T, I>::DepositSlashed { who, amount });
		}
	}
	/// Get the track info value for the track `id`.
948
	fn track(id: TrackIdOf<T, I>) -> Option<&'static TrackInfoOf<T, I>> {
948
		let tracks = T::Tracks::tracks();
3672
		let index = tracks.binary_search_by_key(&id, |x| x.0).unwrap_or_else(|x| x);
948
		Some(&tracks[index].1)
948
	}
	/// Determine whether the given `tally` would result in a referendum passing at `elapsed` blocks
	/// into a total decision `period`, given the two curves for `support_needed` and
	/// `approval_needed`.
6
	fn is_passing(
6
		tally: &T::Tally,
6
		elapsed: BlockNumberFor<T>,
6
		period: BlockNumberFor<T>,
6
		support_needed: &Curve,
6
		approval_needed: &Curve,
6
		id: TrackIdOf<T, I>,
6
	) -> bool {
6
		let x = Perbill::from_rational(elapsed.min(period), period);
6
		support_needed.passing(x, tally.support(id)) &&
			approval_needed.passing(x, tally.approval(id))
6
	}
	/// Clear metadata if exist for a given referendum index.
312
	fn do_clear_metadata(index: ReferendumIndex) {
312
		if let Some(hash) = MetadataOf::<T, I>::take(index) {
			Self::deposit_event(Event::<T, I>::MetadataCleared { index, hash });
312
		}
312
	}
	/// Ensure the correctness of the state of this pallet.
	///
	/// The following assertions must always apply.
	///
	/// General assertions:
	///
	/// * [`ReferendumCount`] must always be equal to the number of referenda in
	///   [`ReferendumInfoFor`].
	/// * Referendum indices in [`MetadataOf`] must also be stored in [`ReferendumInfoFor`].
	#[cfg(any(feature = "try-runtime", test))]
107274
	fn do_try_state() -> Result<(), sp_runtime::TryRuntimeError> {
107274
		ensure!(
107274
			ReferendumCount::<T, I>::get() as usize ==
107274
				ReferendumInfoFor::<T, I>::iter_keys().count(),
			"Number of referenda in `ReferendumInfoFor` is different than `ReferendumCount`"
		);
107274
		MetadataOf::<T, I>::iter_keys().try_for_each(|referendum_index| -> DispatchResult {
			ensure!(
				ReferendumInfoFor::<T, I>::contains_key(referendum_index),
				"Referendum indices in `MetadataOf` must also be stored in `ReferendumInfoOf`"
			);
			Ok(())
107274
		})?;
107274
		Self::try_state_referenda_info()?;
107274
		Self::try_state_tracks()?;
107274
		Ok(())
107274
	}
	/// Looking at referenda info:
	///
	/// - Data regarding ongoing phase:
	///
	/// * There must exist track info for the track of the referendum.
	/// * The deciding stage has to begin before confirmation period.
	/// * If alarm is set the nudge call has to be at most [`UndecidingTimeout`] blocks away
	///  from the submission block.
	#[cfg(any(feature = "try-runtime", test))]
107274
	fn try_state_referenda_info() -> Result<(), sp_runtime::TryRuntimeError> {
107274
		ReferendumInfoFor::<T, I>::iter().try_for_each(|(_, referendum)| {
936
			match referendum {
936
				ReferendumInfo::Ongoing(status) => {
936
					ensure!(
936
						Self::track(status.track).is_some(),
						"No track info for the track of the referendum."
					);
936
					if let Some(deciding) = status.deciding {
6
						ensure!(
6
							deciding.since <
6
								deciding.confirming.unwrap_or(BlockNumberFor::<T>::max_value()),
							"Deciding status cannot begin before confirming stage."
						)
930
					}
				},
				_ => {},
			}
936
			Ok(())
107274
		})
107274
	}
	/// Looking at tracks:
	///
	/// * The referendum indices stored in [`TrackQueue`] must exist as keys in the
	///  [`ReferendumInfoFor`] storage map.
	#[cfg(any(feature = "try-runtime", test))]
107274
	fn try_state_tracks() -> Result<(), sp_runtime::TryRuntimeError> {
1340925
		T::Tracks::tracks().iter().try_for_each(|track| {
1340925
			TrackQueue::<T, I>::get(track.0).iter().try_for_each(
1340925
				|(referendum_index, _)| -> Result<(), sp_runtime::TryRuntimeError> {
					ensure!(
					ReferendumInfoFor::<T, I>::contains_key(referendum_index),
					"`ReferendumIndex` inside the `TrackQueue` should be a key in `ReferendumInfoFor`"
				);
					Ok(())
1340925
				},
1340925
			)?;
1340925
			Ok(())
1340925
		})
107274
	}
}