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
//! GRANDPA Consensus module for runtime.
19
//!
20
//! This manages the GRANDPA authority set ready for the native code.
21
//! These authorities are only for GRANDPA finality, not for consensus overall.
22
//!
23
//! In the future, it will also handle misbehavior reports, and on-chain
24
//! finality notifications.
25
//!
26
//! For full integration with GRANDPA, the `GrandpaApi` should be implemented.
27
//! The necessary items are re-exported via the `fg_primitives` crate.
28

            
29
#![cfg_attr(not(feature = "std"), no_std)]
30

            
31
extern crate alloc;
32

            
33
// Re-export since this is necessary for `impl_apis` in runtime.
34
pub use sp_consensus_grandpa::{
35
	self as fg_primitives, AuthorityId, AuthorityList, AuthorityWeight,
36
};
37

            
38
use alloc::{boxed::Box, vec::Vec};
39
use codec::{Decode, Encode, MaxEncodedLen};
40
use frame_support::{
41
	dispatch::{DispatchResultWithPostInfo, Pays},
42
	pallet_prelude::Get,
43
	traits::OneSessionHandler,
44
	weights::Weight,
45
	WeakBoundedVec,
46
};
47
use frame_system::pallet_prelude::BlockNumberFor;
48
use scale_info::TypeInfo;
49
use sp_consensus_grandpa::{
50
	ConsensusLog, EquivocationProof, ScheduledChange, SetId, GRANDPA_ENGINE_ID,
51
	RUNTIME_LOG_TARGET as LOG_TARGET,
52
};
53
use sp_runtime::{generic::DigestItem, traits::Zero, DispatchResult};
54
use sp_session::{GetSessionNumber, GetValidatorCount};
55
use sp_staking::{offence::OffenceReportSystem, SessionIndex};
56

            
57
mod default_weights;
58
mod equivocation;
59
pub mod migrations;
60

            
61
#[cfg(any(feature = "runtime-benchmarks", test))]
62
mod benchmarking;
63
#[cfg(all(feature = "std", test))]
64
mod mock;
65
#[cfg(all(feature = "std", test))]
66
mod tests;
67

            
68
pub use equivocation::{EquivocationOffence, EquivocationReportSystem, TimeSlot};
69

            
70
pub use pallet::*;
71

            
72
1711
#[frame_support::pallet]
73
pub mod pallet {
74
	use super::*;
75
	use frame_support::{dispatch::DispatchResult, pallet_prelude::*};
76
	use frame_system::pallet_prelude::*;
77

            
78
	/// The in-code storage version.
79
	const STORAGE_VERSION: StorageVersion = StorageVersion::new(5);
80

            
81
1698
	#[pallet::pallet]
82
	#[pallet::storage_version(STORAGE_VERSION)]
83
	pub struct Pallet<T>(_);
84

            
85
	#[pallet::config]
86
	pub trait Config: frame_system::Config {
87
		/// The event type of this module.
88
		type RuntimeEvent: From<Event>
89
			+ Into<<Self as frame_system::Config>::RuntimeEvent>
90
			+ IsType<<Self as frame_system::Config>::RuntimeEvent>;
91

            
92
		/// Weights for this pallet.
93
		type WeightInfo: WeightInfo;
94

            
95
		/// Max Authorities in use
96
		#[pallet::constant]
97
		type MaxAuthorities: Get<u32>;
98

            
99
		/// The maximum number of nominators for each validator.
100
		#[pallet::constant]
101
		type MaxNominators: Get<u32>;
102

            
103
		/// The maximum number of entries to keep in the set id to session index mapping.
104
		///
105
		/// Since the `SetIdSession` map is only used for validating equivocations this
106
		/// value should relate to the bonding duration of whatever staking system is
107
		/// being used (if any). If equivocation handling is not enabled then this value
108
		/// can be zero.
109
		#[pallet::constant]
110
		type MaxSetIdSessionEntries: Get<u64>;
111

            
112
		/// The proof of key ownership, used for validating equivocation reports
113
		/// The proof include the session index and validator count of the
114
		/// session at which the equivocation occurred.
115
		type KeyOwnerProof: Parameter + GetSessionNumber + GetValidatorCount;
116

            
117
		/// The equivocation handling subsystem, defines methods to check/report an
118
		/// offence and for submitting a transaction to report an equivocation
119
		/// (from an offchain context).
120
		type EquivocationReportSystem: OffenceReportSystem<
121
			Option<Self::AccountId>,
122
			(EquivocationProof<Self::Hash, BlockNumberFor<Self>>, Self::KeyOwnerProof),
123
		>;
124
	}
125

            
126
554367
	#[pallet::hooks]
127
	impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {
128
194763
		fn on_finalize(block_number: BlockNumberFor<T>) {
129
			// check for scheduled pending authority set changes
130
194763
			if let Some(pending_change) = <PendingChange<T>>::get() {
131
				// emit signal if we're at the block that scheduled the change
132
15411
				if block_number == pending_change.scheduled_at {
133
15411
					let next_authorities = pending_change.next_authorities.to_vec();
134
15411
					if let Some(median) = pending_change.forced {
135
						Self::deposit_log(ConsensusLog::ForcedChange(
136
							median,
137
							ScheduledChange { delay: pending_change.delay, next_authorities },
138
						))
139
15411
					} else {
140
15411
						Self::deposit_log(ConsensusLog::ScheduledChange(ScheduledChange {
141
15411
							delay: pending_change.delay,
142
15411
							next_authorities,
143
15411
						}));
144
15411
					}
145
				}
146

            
147
				// enact the change if we've reached the enacting block
148
15411
				if block_number == pending_change.scheduled_at + pending_change.delay {
149
15411
					Authorities::<T>::put(&pending_change.next_authorities);
150
15411
					Self::deposit_event(Event::NewAuthorities {
151
15411
						authority_set: pending_change.next_authorities.into_inner(),
152
15411
					});
153
15411
					<PendingChange<T>>::kill();
154
15411
				}
155
179352
			}
156

            
157
			// check for scheduled pending state changes
158
194763
			match <State<T>>::get() {
159
				StoredState::PendingPause { scheduled_at, delay } => {
160
					// signal change to pause
161
					if block_number == scheduled_at {
162
						Self::deposit_log(ConsensusLog::Pause(delay));
163
					}
164

            
165
					// enact change to paused state
166
					if block_number == scheduled_at + delay {
167
						<State<T>>::put(StoredState::Paused);
168
						Self::deposit_event(Event::Paused);
169
					}
170
				},
171
				StoredState::PendingResume { scheduled_at, delay } => {
172
					// signal change to resume
173
					if block_number == scheduled_at {
174
						Self::deposit_log(ConsensusLog::Resume(delay));
175
					}
176

            
177
					// enact change to live state
178
					if block_number == scheduled_at + delay {
179
						<State<T>>::put(StoredState::Live);
180
						Self::deposit_event(Event::Resumed);
181
					}
182
				},
183
194763
				_ => {},
184
			}
185
194763
		}
186
	}
187

            
188
7893
	#[pallet::call]
189
	impl<T: Config> Pallet<T> {
190
		/// Report voter equivocation/misbehavior. This method will verify the
191
		/// equivocation proof and validate the given key ownership proof
192
		/// against the extracted offender. If both are valid, the offence
193
		/// will be reported.
194
		#[pallet::call_index(0)]
195
		#[pallet::weight(T::WeightInfo::report_equivocation(
196
			key_owner_proof.validator_count(),
197
			T::MaxNominators::get(),
198
		))]
199
		pub fn report_equivocation(
200
			origin: OriginFor<T>,
201
			equivocation_proof: Box<EquivocationProof<T::Hash, BlockNumberFor<T>>>,
202
			key_owner_proof: T::KeyOwnerProof,
203
1476
		) -> DispatchResultWithPostInfo {
204
1476
			let reporter = ensure_signed(origin)?;
205

            
206
1476
			T::EquivocationReportSystem::process_evidence(
207
1476
				Some(reporter),
208
1476
				(*equivocation_proof, key_owner_proof),
209
1476
			)?;
210
			// Waive the fee since the report is valid and beneficial
211
			Ok(Pays::No.into())
212
		}
213

            
214
		/// Report voter equivocation/misbehavior. This method will verify the
215
		/// equivocation proof and validate the given key ownership proof
216
		/// against the extracted offender. If both are valid, the offence
217
		/// will be reported.
218
		///
219
		/// This extrinsic must be called unsigned and it is expected that only
220
		/// block authors will call it (validated in `ValidateUnsigned`), as such
221
		/// if the block author is defined it will be defined as the equivocation
222
		/// reporter.
223
		#[pallet::call_index(1)]
224
		#[pallet::weight(T::WeightInfo::report_equivocation(
225
			key_owner_proof.validator_count(),
226
			T::MaxNominators::get(),
227
		))]
228
		pub fn report_equivocation_unsigned(
229
			origin: OriginFor<T>,
230
			equivocation_proof: Box<EquivocationProof<T::Hash, BlockNumberFor<T>>>,
231
			key_owner_proof: T::KeyOwnerProof,
232
129
		) -> DispatchResultWithPostInfo {
233
129
			ensure_none(origin)?;
234

            
235
			T::EquivocationReportSystem::process_evidence(
236
				None,
237
				(*equivocation_proof, key_owner_proof),
238
			)?;
239
			Ok(Pays::No.into())
240
		}
241

            
242
		/// Note that the current authority set of the GRANDPA finality gadget has stalled.
243
		///
244
		/// This will trigger a forced authority set change at the beginning of the next session, to
245
		/// be enacted `delay` blocks after that. The `delay` should be high enough to safely assume
246
		/// that the block signalling the forced change will not be re-orged e.g. 1000 blocks.
247
		/// The block production rate (which may be slowed down because of finality lagging) should
248
		/// be taken into account when choosing the `delay`. The GRANDPA voters based on the new
249
		/// authority will start voting on top of `best_finalized_block_number` for new finalized
250
		/// blocks. `best_finalized_block_number` should be the highest of the latest finalized
251
		/// block of all validators of the new authority set.
252
		///
253
		/// Only callable by root.
254
		#[pallet::call_index(2)]
255
		#[pallet::weight(T::WeightInfo::note_stalled())]
256
		pub fn note_stalled(
257
			origin: OriginFor<T>,
258
			delay: BlockNumberFor<T>,
259
			best_finalized_block_number: BlockNumberFor<T>,
260
99
		) -> DispatchResult {
261
99
			ensure_root(origin)?;
262

            
263
			Self::on_stalled(delay, best_finalized_block_number);
264
			Ok(())
265
		}
266
	}
267

            
268
	#[pallet::event]
269
15411
	#[pallet::generate_deposit(fn deposit_event)]
270
	pub enum Event {
271
		/// New authority set has been applied.
272
		NewAuthorities { authority_set: AuthorityList },
273
		/// Current authority set has been paused.
274
		Paused,
275
		/// Current authority set has been resumed.
276
		Resumed,
277
	}
278

            
279
2952
	#[pallet::error]
280
	pub enum Error<T> {
281
		/// Attempt to signal GRANDPA pause when the authority set isn't live
282
		/// (either paused or already pending pause).
283
		PauseFailed,
284
		/// Attempt to signal GRANDPA resume when the authority set isn't paused
285
		/// (either live or already pending resume).
286
		ResumeFailed,
287
		/// Attempt to signal GRANDPA change with one already pending.
288
		ChangePending,
289
		/// Cannot signal forced change so soon after last.
290
		TooSoon,
291
		/// A key ownership proof provided as part of an equivocation report is invalid.
292
		InvalidKeyOwnershipProof,
293
		/// An equivocation proof provided as part of an equivocation report is invalid.
294
		InvalidEquivocationProof,
295
		/// A given equivocation report is valid but already previously reported.
296
		DuplicateOffenceReport,
297
	}
298

            
299
194763
	#[pallet::type_value]
300
194763
	pub(super) fn DefaultForState<T: Config>() -> StoredState<BlockNumberFor<T>> {
301
194763
		StoredState::Live
302
194763
	}
303

            
304
	/// State of the current authority set.
305
389526
	#[pallet::storage]
306
	#[pallet::getter(fn state)]
307
	pub(super) type State<T: Config> =
308
		StorageValue<_, StoredState<BlockNumberFor<T>>, ValueQuery, DefaultForState<T>>;
309

            
310
	/// Pending change: (signaled at, scheduled change).
311
481992
	#[pallet::storage]
312
	#[pallet::getter(fn pending_change)]
313
	pub(super) type PendingChange<T: Config> =
314
		StorageValue<_, StoredPendingChange<BlockNumberFor<T>, T::MaxAuthorities>>;
315

            
316
	/// next block number where we can force a change.
317
	#[pallet::storage]
318
	#[pallet::getter(fn next_forced)]
319
	pub(super) type NextForced<T: Config> = StorageValue<_, BlockNumberFor<T>>;
320

            
321
	/// `true` if we are currently stalled.
322
270462
	#[pallet::storage]
323
	#[pallet::getter(fn stalled)]
324
	pub(super) type Stalled<T: Config> = StorageValue<_, (BlockNumberFor<T>, BlockNumberFor<T>)>;
325

            
326
	/// The number of changes (both in terms of keys and underlying economic responsibilities)
327
	/// in the "set" of Grandpa validators from genesis.
328
421110
	#[pallet::storage]
329
	#[pallet::getter(fn current_set_id)]
330
	pub(super) type CurrentSetId<T: Config> = StorageValue<_, SetId, ValueQuery>;
331

            
332
	/// A mapping from grandpa set ID to the index of the *most recent* session for which its
333
	/// members were responsible.
334
	///
335
	/// This is only used for validating equivocation proofs. An equivocation proof must
336
	/// contains a key-ownership proof for a given session, therefore we need a way to tie
337
	/// together sessions and GRANDPA set ids, i.e. we need to validate that a validator
338
	/// was the owner of a given key on a given session, and what the active set ID was
339
	/// during that session.
340
	///
341
	/// TWOX-NOTE: `SetId` is not under user control.
342
135237
	#[pallet::storage]
343
	#[pallet::getter(fn session_for_set)]
344
	pub(super) type SetIdSession<T: Config> = StorageMap<_, Twox64Concat, SetId, SessionIndex>;
345

            
346
	/// The current list of authorities.
347
30822
	#[pallet::storage]
348
	pub(crate) type Authorities<T: Config> =
349
		StorageValue<_, BoundedAuthorityList<T::MaxAuthorities>, ValueQuery>;
350

            
351
	#[derive(frame_support::DefaultNoBound)]
352
	#[pallet::genesis_config]
353
	pub struct GenesisConfig<T: Config> {
354
		pub authorities: AuthorityList,
355
		#[serde(skip)]
356
		pub _config: core::marker::PhantomData<T>,
357
	}
358

            
359
	#[pallet::genesis_build]
360
	impl<T: Config> BuildGenesisConfig for GenesisConfig<T> {
361
3
		fn build(&self) {
362
3
			CurrentSetId::<T>::put(SetId::default());
363
3
			Pallet::<T>::initialize(self.authorities.clone())
364
3
		}
365
	}
366

            
367
	#[pallet::validate_unsigned]
368
	impl<T: Config> ValidateUnsigned for Pallet<T> {
369
		type Call = Call<T>;
370

            
371
		fn validate_unsigned(source: TransactionSource, call: &Self::Call) -> TransactionValidity {
372
			Self::validate_unsigned(source, call)
373
		}
374

            
375
		fn pre_dispatch(call: &Self::Call) -> Result<(), TransactionValidityError> {
376
			Self::pre_dispatch(call)
377
		}
378
	}
379
}
380

            
381
pub trait WeightInfo {
382
	fn report_equivocation(validator_count: u32, max_nominators_per_validator: u32) -> Weight;
383
	fn note_stalled() -> Weight;
384
}
385

            
386
/// Bounded version of `AuthorityList`, `Limit` being the bound
387
pub type BoundedAuthorityList<Limit> = WeakBoundedVec<(AuthorityId, AuthorityWeight), Limit>;
388

            
389
/// A stored pending change.
390
/// `Limit` is the bound for `next_authorities`
391
#[derive(Encode, Decode, TypeInfo, MaxEncodedLen)]
392
#[codec(mel_bound(N: MaxEncodedLen, Limit: Get<u32>))]
393
#[scale_info(skip_type_params(Limit))]
394
pub struct StoredPendingChange<N, Limit> {
395
	/// The block number this was scheduled at.
396
	pub scheduled_at: N,
397
	/// The delay in blocks until it will be applied.
398
	pub delay: N,
399
	/// The next authority set, weakly bounded in size by `Limit`.
400
	pub next_authorities: BoundedAuthorityList<Limit>,
401
	/// If defined it means the change was forced and the given block number
402
	/// indicates the median last finalized block when the change was signaled.
403
	pub forced: Option<N>,
404
}
405

            
406
/// Current state of the GRANDPA authority set. State transitions must happen in
407
/// the same order of states defined below, e.g. `Paused` implies a prior
408
/// `PendingPause`.
409
#[derive(Decode, Encode, TypeInfo, MaxEncodedLen)]
410
#[cfg_attr(test, derive(Debug, PartialEq))]
411
pub enum StoredState<N> {
412
	/// The current authority set is live, and GRANDPA is enabled.
413
	Live,
414
	/// There is a pending pause event which will be enacted at the given block
415
	/// height.
416
	PendingPause {
417
		/// Block at which the intention to pause was scheduled.
418
		scheduled_at: N,
419
		/// Number of blocks after which the change will be enacted.
420
		delay: N,
421
	},
422
	/// The current GRANDPA authority set is paused.
423
	Paused,
424
	/// There is a pending resume event which will be enacted at the given block
425
	/// height.
426
	PendingResume {
427
		/// Block at which the intention to resume was scheduled.
428
		scheduled_at: N,
429
		/// Number of blocks after which the change will be enacted.
430
		delay: N,
431
	},
432
}
433

            
434
impl<T: Config> Pallet<T> {
435
	/// Get the current set of authorities, along with their respective weights.
436
	pub fn grandpa_authorities() -> AuthorityList {
437
		Authorities::<T>::get().into_inner()
438
	}
439

            
440
	/// Schedule GRANDPA to pause starting in the given number of blocks.
441
	/// Cannot be done when already paused.
442
	pub fn schedule_pause(in_blocks: BlockNumberFor<T>) -> DispatchResult {
443
		if let StoredState::Live = <State<T>>::get() {
444
			let scheduled_at = <frame_system::Pallet<T>>::block_number();
445
			<State<T>>::put(StoredState::PendingPause { delay: in_blocks, scheduled_at });
446

            
447
			Ok(())
448
		} else {
449
			Err(Error::<T>::PauseFailed.into())
450
		}
451
	}
452

            
453
	/// Schedule a resume of GRANDPA after pausing.
454
	pub fn schedule_resume(in_blocks: BlockNumberFor<T>) -> DispatchResult {
455
		if let StoredState::Paused = <State<T>>::get() {
456
			let scheduled_at = <frame_system::Pallet<T>>::block_number();
457
			<State<T>>::put(StoredState::PendingResume { delay: in_blocks, scheduled_at });
458

            
459
			Ok(())
460
		} else {
461
			Err(Error::<T>::ResumeFailed.into())
462
		}
463
	}
464

            
465
	/// Schedule a change in the authorities.
466
	///
467
	/// The change will be applied at the end of execution of the block
468
	/// `in_blocks` after the current block. This value may be 0, in which
469
	/// case the change is applied at the end of the current block.
470
	///
471
	/// If the `forced` parameter is defined, this indicates that the current
472
	/// set has been synchronously determined to be offline and that after
473
	/// `in_blocks` the given change should be applied. The given block number
474
	/// indicates the median last finalized block number and it should be used
475
	/// as the canon block when starting the new grandpa voter.
476
	///
477
	/// No change should be signaled while any change is pending. Returns
478
	/// an error if a change is already pending.
479
15411
	pub fn schedule_change(
480
15411
		next_authorities: AuthorityList,
481
15411
		in_blocks: BlockNumberFor<T>,
482
15411
		forced: Option<BlockNumberFor<T>>,
483
15411
	) -> DispatchResult {
484
15411
		if !<PendingChange<T>>::exists() {
485
15411
			let scheduled_at = <frame_system::Pallet<T>>::block_number();
486
15411

            
487
15411
			if forced.is_some() {
488
				if Self::next_forced().map_or(false, |next| next > scheduled_at) {
489
					return Err(Error::<T>::TooSoon.into())
490
				}
491

            
492
				// only allow the next forced change when twice the window has passed since
493
				// this one.
494
				<NextForced<T>>::put(scheduled_at + in_blocks * 2u32.into());
495
15411
			}
496

            
497
15411
			let next_authorities = WeakBoundedVec::<_, T::MaxAuthorities>::force_from(
498
15411
				next_authorities,
499
15411
				Some(
500
15411
					"Warning: The number of authorities given is too big. \
501
15411
					A runtime configuration adjustment may be needed.",
502
15411
				),
503
15411
			);
504
15411

            
505
15411
			<PendingChange<T>>::put(StoredPendingChange {
506
15411
				delay: in_blocks,
507
15411
				scheduled_at,
508
15411
				next_authorities,
509
15411
				forced,
510
15411
			});
511
15411

            
512
15411
			Ok(())
513
		} else {
514
			Err(Error::<T>::ChangePending.into())
515
		}
516
15411
	}
517

            
518
	/// Deposit one of this module's logs.
519
15411
	fn deposit_log(log: ConsensusLog<BlockNumberFor<T>>) {
520
15411
		let log = DigestItem::Consensus(GRANDPA_ENGINE_ID, log.encode());
521
15411
		<frame_system::Pallet<T>>::deposit_log(log);
522
15411
	}
523

            
524
	// Perform module initialization, abstracted so that it can be called either through genesis
525
	// config builder or through `on_genesis_session`.
526
6
	fn initialize(authorities: AuthorityList) {
527
6
		if !authorities.is_empty() {
528
			assert!(Self::grandpa_authorities().is_empty(), "Authorities are already initialized!");
529
			Authorities::<T>::put(
530
				&BoundedAuthorityList::<T::MaxAuthorities>::try_from(authorities).expect(
531
					"Grandpa: `Config::MaxAuthorities` is smaller than the number of genesis authorities!",
532
				),
533
			);
534
6
		}
535

            
536
		// NOTE: initialize first session of first set. this is necessary for
537
		// the genesis set and session since we only update the set -> session
538
		// mapping whenever a new session starts, i.e. through `on_new_session`.
539
6
		SetIdSession::<T>::insert(0, 0);
540
6
	}
541

            
542
	/// Submits an extrinsic to report an equivocation. This method will create
543
	/// an unsigned extrinsic with a call to `report_equivocation_unsigned` and
544
	/// will push the transaction to the pool. Only useful in an offchain
545
	/// context.
546
	pub fn submit_unsigned_equivocation_report(
547
		equivocation_proof: EquivocationProof<T::Hash, BlockNumberFor<T>>,
548
		key_owner_proof: T::KeyOwnerProof,
549
	) -> Option<()> {
550
		T::EquivocationReportSystem::publish_evidence((equivocation_proof, key_owner_proof)).ok()
551
	}
552

            
553
	fn on_stalled(further_wait: BlockNumberFor<T>, median: BlockNumberFor<T>) {
554
		// when we record old authority sets we could try to figure out _who_
555
		// failed. until then, we can't meaningfully guard against
556
		// `next == last` the way that normal session changes do.
557
		<Stalled<T>>::put((further_wait, median));
558
	}
559
}
560

            
561
impl<T: Config> sp_runtime::BoundToRuntimeAppPublic for Pallet<T> {
562
	type Public = AuthorityId;
563
}
564

            
565
impl<T: Config> OneSessionHandler<T::AccountId> for Pallet<T>
566
where
567
	T: pallet_session::Config,
568
{
569
	type Key = AuthorityId;
570

            
571
3
	fn on_genesis_session<'a, I: 'a>(validators: I)
572
3
	where
573
3
		I: Iterator<Item = (&'a T::AccountId, AuthorityId)>,
574
3
	{
575
3
		let authorities = validators.map(|(_, k)| (k, 1)).collect::<Vec<_>>();
576
3
		Self::initialize(authorities);
577
3
	}
578

            
579
135231
	fn on_new_session<'a, I: 'a>(changed: bool, validators: I, _queued_validators: I)
580
135231
	where
581
135231
		I: Iterator<Item = (&'a T::AccountId, AuthorityId)>,
582
135231
	{
583
		// Always issue a change if `session` says that the validators have changed.
584
		// Even if their session keys are the same as before, the underlying economic
585
		// identities have changed.
586
135231
		let current_set_id = if changed || <Stalled<T>>::exists() {
587
15411
			let next_authorities = validators.map(|(_, k)| (k, 1)).collect::<Vec<_>>();
588

            
589
15411
			let res = if let Some((further_wait, median)) = <Stalled<T>>::take() {
590
				Self::schedule_change(next_authorities, further_wait, Some(median))
591
			} else {
592
15411
				Self::schedule_change(next_authorities, Zero::zero(), None)
593
			};
594

            
595
15411
			if res.is_ok() {
596
20548
				let current_set_id = CurrentSetId::<T>::mutate(|s| {
597
15411
					*s += 1;
598
15411
					*s
599
20548
				});
600
15411

            
601
15411
				let max_set_id_session_entries = T::MaxSetIdSessionEntries::get().max(1);
602
15411
				if current_set_id >= max_set_id_session_entries {
603
					SetIdSession::<T>::remove(current_set_id - max_set_id_session_entries);
604
15411
				}
605

            
606
15411
				current_set_id
607
			} else {
608
				// either the session module signalled that the validators have changed
609
				// or the set was stalled. but since we didn't successfully schedule
610
				// an authority set change we do not increment the set id.
611
				Self::current_set_id()
612
			}
613
		} else {
614
			// nothing's changed, neither economic conditions nor session keys. update the pointer
615
			// of the current set.
616
119820
			Self::current_set_id()
617
		};
618

            
619
		// update the mapping to note that the current set corresponds to the
620
		// latest equivalent session (i.e. now).
621
135231
		let session_index = <pallet_session::Pallet<T>>::current_index();
622
135231
		SetIdSession::<T>::insert(current_set_id, &session_index);
623
135231
	}
624

            
625
	fn on_disabled(i: u32) {
626
		Self::deposit_log(ConsensusLog::OnDisabled(i as u64))
627
	}
628
}