1
// Copyright (C) Moondance Labs Ltd.
2
// This file is part of Tanssi.
3

            
4
// Tanssi is free software: you can redistribute it and/or modify
5
// it under the terms of the GNU General Public License as published by
6
// the Free Software Foundation, either version 3 of the License, or
7
// (at your option) any later version.
8

            
9
// Tanssi is distributed in the hope that it will be useful,
10
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
// GNU General Public License for more details.
13

            
14
// You should have received a copy of the GNU General Public License
15
// along with Tanssi.  If not, see <http://www.gnu.org/licenses/>
16

            
17
//! ExternalValidators pallet.
18
//!
19
//! A pallet to manage external validators for a solochain.
20
//!
21
//! ## Terminology
22
//!
23
//! - WhitelistedValidators: Fixed validators set by root/governance. Have priority over the external validators.
24
//!      Are not rewarded.
25
//! - ExternalValidators: Validators set using storage proofs from another blockchain. Can be disabled by setting
26
//!     `SkipExternalValidators` to true.
27
//!
28
//! Validators only change once per era. By default the era changes after a fixed number of sessions, but new eras
29
//! can be forced or disabled using a root extrinsic.
30
//!
31
//! The structure of this pallet and the concept of eras is inspired by `pallet_staking` from Polkadot.
32

            
33
#![cfg_attr(not(feature = "std"), no_std)]
34

            
35
pub use pallet::*;
36
use {
37
    frame_support::pallet_prelude::Weight,
38
    log::log,
39
    parity_scale_codec::{Decode, DecodeWithMemTracking, Encode, MaxEncodedLen},
40
    scale_info::TypeInfo,
41
    sp_runtime::{traits::Get, RuntimeDebug},
42
    sp_staking::SessionIndex,
43
    sp_std::{collections::btree_set::BTreeSet, vec::Vec},
44
    tp_traits::{
45
        ActiveEraInfo, EraIndex, EraIndexProvider, ExternalIndexProvider, InvulnerablesProvider,
46
        OnEraEnd, OnEraStart, ValidatorProvider,
47
    },
48
};
49

            
50
#[cfg(test)]
51
mod mock;
52

            
53
#[cfg(test)]
54
mod tests;
55

            
56
#[cfg(feature = "runtime-benchmarks")]
57
mod benchmarking;
58
pub mod weights;
59

            
60
#[frame_support::pallet]
61
pub mod pallet {
62
    pub use crate::weights::WeightInfo;
63

            
64
    #[cfg(feature = "runtime-benchmarks")]
65
    use frame_support::traits::Currency;
66
    use {
67
        super::*,
68
        frame_support::{
69
            pallet_prelude::*,
70
            traits::{EnsureOrigin, UnixTime, ValidatorRegistration},
71
            BoundedVec, DefaultNoBound,
72
        },
73
        frame_system::pallet_prelude::*,
74
        sp_runtime::{traits::Convert, SaturatedConversion},
75
        sp_std::vec::Vec,
76
    };
77

            
78
    /// Configure the pallet by specifying the parameters and types on which it depends.
79
    #[pallet::config]
80
    pub trait Config: frame_system::Config {
81
        /// Overarching event type.
82
        type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
83

            
84
        /// Origin that can dictate updating parameters of this pallet.
85
        type UpdateOrigin: EnsureOrigin<Self::RuntimeOrigin>;
86

            
87
        /// Number of eras to keep in history.
88
        ///
89
        /// Following information is kept for eras in `[current_era -
90
        /// HistoryDepth, current_era]`: `ErasStartSessionIndex`
91
        ///
92
        /// Must be more than the number of eras delayed by session.
93
        /// I.e. active era must always be in history. I.e. `active_era >
94
        /// current_era - history_depth` must be guaranteed.
95
        ///
96
        /// If migrating an existing pallet from storage value to config value,
97
        /// this should be set to same value or greater as in storage.
98
        #[pallet::constant]
99
        type HistoryDepth: Get<u32>;
100

            
101
        /// Maximum number of whitelisted validators.
102
        #[pallet::constant]
103
        type MaxWhitelistedValidators: Get<u32>;
104

            
105
        /// Maximum number of external validators.
106
        #[pallet::constant]
107
        type MaxExternalValidators: Get<u32>;
108

            
109
        /// A stable ID for a validator.
110
        type ValidatorId: Member
111
            + Parameter
112
            + Ord
113
            + MaybeSerializeDeserialize
114
            + MaxEncodedLen
115
            + TryFrom<Self::AccountId>;
116

            
117
        /// A conversion from account ID to validator ID.
118
        ///
119
        /// Its cost must be at most one storage read.
120
        type ValidatorIdOf: Convert<Self::AccountId, Option<Self::ValidatorId>>;
121

            
122
        /// Validate a user is registered
123
        type ValidatorRegistration: ValidatorRegistration<Self::ValidatorId>;
124

            
125
        /// Time used for computing era duration.
126
        ///
127
        /// It is guaranteed to start being called from the first `on_finalize`. Thus value at
128
        /// genesis is not used.
129
        type UnixTime: UnixTime;
130

            
131
        /// Number of sessions per era.
132
        #[pallet::constant]
133
        type SessionsPerEra: Get<SessionIndex>;
134

            
135
        type OnEraStart: OnEraStart;
136
        type OnEraEnd: OnEraEnd;
137

            
138
        /// The weight information of this pallet.
139
        type WeightInfo: WeightInfo;
140

            
141
        #[cfg(feature = "runtime-benchmarks")]
142
        type Currency: Currency<Self::AccountId>
143
            + frame_support::traits::fungible::Balanced<Self::AccountId>;
144
    }
145

            
146
326
    #[pallet::pallet]
147
    pub struct Pallet<T>(_);
148

            
149
    /// Fixed validators set by root/governance. Have priority over the external validators.
150
4486
    #[pallet::storage]
151
    pub type WhitelistedValidators<T: Config> =
152
        StorageValue<_, BoundedVec<T::ValidatorId, T::MaxWhitelistedValidators>, ValueQuery>;
153

            
154
    /// Copy of `WhitelistedValidators` at the start of this active era.
155
    /// Used to check which validators we don't need to reward.
156
16988
    #[pallet::storage]
157
    pub type WhitelistedValidatorsActiveEra<T: Config> =
158
        StorageValue<_, BoundedVec<T::ValidatorId, T::MaxWhitelistedValidators>, ValueQuery>;
159

            
160
    /// Same as `WhitelistedValidatorsActiveEra` but only exists for a brief period of time when the
161
    /// next era has been planned but not enacted yet.
162
3946
    #[pallet::storage]
163
    pub type WhitelistedValidatorsActiveEraPending<T: Config> =
164
        StorageValue<_, BoundedVec<T::ValidatorId, T::MaxWhitelistedValidators>, ValueQuery>;
165

            
166
    /// Validators set using storage proofs from another blockchain. Ignored if `SkipExternalValidators` is true.
167
2704
    #[pallet::storage]
168
    pub type ExternalValidators<T: Config> =
169
        StorageValue<_, BoundedVec<T::ValidatorId, T::MaxExternalValidators>, ValueQuery>;
170

            
171
    /// Allow to disable external validators.
172
2628
    #[pallet::storage]
173
    pub type SkipExternalValidators<T: Config> = StorageValue<_, bool, ValueQuery>;
174

            
175
    /// The current era information, it is either ActiveEra or ActiveEra + 1 if the new era validators have been queued.
176
6780
    #[pallet::storage]
177
    pub type CurrentEra<T: Config> = StorageValue<_, EraIndex>;
178

            
179
    /// The active era information, it holds index and start.
180
24242
    #[pallet::storage]
181
    pub type ActiveEra<T: Config> = StorageValue<_, ActiveEraInfo>;
182

            
183
    /// The session index at which the era start for the last [`Config::HistoryDepth`] eras.
184
    ///
185
    /// Note: This tracks the starting session (i.e. session index when era start being active)
186
    /// for the eras in `[CurrentEra - HISTORY_DEPTH, CurrentEra]`.
187
4671
    #[pallet::storage]
188
    pub type ErasStartSessionIndex<T> = StorageMap<_, Twox64Concat, EraIndex, SessionIndex>;
189

            
190
    /// Mode of era forcing.
191
3034
    #[pallet::storage]
192
    pub type ForceEra<T> = StorageValue<_, Forcing, ValueQuery>;
193

            
194
    /// Latest received external index. This index can be a timestamp
195
    /// a set-id, an epoch or in general anything that identifies
196
    /// a particular set of validators selected at a given point in time
197
1646
    #[pallet::storage]
198
    pub type ExternalIndex<T> = StorageValue<_, u64, ValueQuery>;
199

            
200
    /// Pending external index to be applied in the upcoming era
201
2916
    #[pallet::storage]
202
    pub type PendingExternalIndex<T> = StorageValue<_, u64, ValueQuery>;
203

            
204
    /// Current external index attached to the latest validators
205
1464
    #[pallet::storage]
206
    pub type CurrentExternalIndex<T> = StorageValue<_, u64, ValueQuery>;
207

            
208
    #[pallet::genesis_config]
209
    #[derive(DefaultNoBound)]
210
    pub struct GenesisConfig<T: Config> {
211
        pub skip_external_validators: bool,
212
        pub whitelisted_validators: Vec<T::ValidatorId>,
213
        pub external_validators: Vec<T::ValidatorId>,
214
    }
215

            
216
352
    #[pallet::genesis_build]
217
    impl<T: Config> BuildGenesisConfig for GenesisConfig<T> {
218
515
        fn build(&self) {
219
515
            let duplicate_validators = self
220
515
                .whitelisted_validators
221
515
                .iter()
222
515
                // T::ValidatorId does not impl Ord or Hash so we cannot collect into set directly,
223
515
                // but we can check for duplicates if we encode them first.
224
870
                .map(|x| x.encode())
225
515
                .collect::<sp_std::collections::btree_set::BTreeSet<_>>();
226
515
            assert!(
227
515
                duplicate_validators.len() == self.whitelisted_validators.len(),
228
                "duplicate validators in genesis."
229
            );
230

            
231
515
            let bounded_validators = BoundedVec::<_, T::MaxWhitelistedValidators>::try_from(
232
515
                self.whitelisted_validators.clone(),
233
515
            )
234
515
            .expect("genesis validators are more than T::MaxWhitelistedValidators");
235
515

            
236
515
            let bounded_external_validators = BoundedVec::<_, T::MaxExternalValidators>::try_from(
237
515
                self.external_validators.clone(),
238
515
            )
239
515
            .expect("genesis external validators are more than T::MaxExternalValidators");
240
515

            
241
515
            <SkipExternalValidators<T>>::put(self.skip_external_validators);
242
515
            <WhitelistedValidators<T>>::put(&bounded_validators);
243
515
            <WhitelistedValidatorsActiveEra<T>>::put(&bounded_validators);
244
515
            <WhitelistedValidatorsActiveEraPending<T>>::put(&bounded_validators);
245
515
            <ExternalValidators<T>>::put(&bounded_external_validators);
246
515
        }
247
    }
248

            
249
    #[pallet::event]
250
810
    #[pallet::generate_deposit(pub(super) fn deposit_event)]
251
    pub enum Event<T: Config> {
252
        /// A new whitelisted validator was added.
253
        WhitelistedValidatorAdded { account_id: T::AccountId },
254
        /// A whitelisted validator was removed.
255
        WhitelistedValidatorRemoved { account_id: T::AccountId },
256
        /// A new era has started.
257
        NewEra { era: EraIndex },
258
        /// A new force era mode was set.
259
        ForceEra { mode: Forcing },
260
        /// External validators were set.
261
        ExternalValidatorsSet {
262
            validators: Vec<T::ValidatorId>,
263
            external_index: u64,
264
        },
265
    }
266

            
267
    #[pallet::error]
268
    pub enum Error<T> {
269
        /// There are too many whitelisted validators.
270
        TooManyWhitelisted,
271
        /// Account is already whitelisted.
272
        AlreadyWhitelisted,
273
        /// Account is not whitelisted.
274
        NotWhitelisted,
275
        /// Account does not have keys registered
276
        NoKeysRegistered,
277
        /// Unable to derive validator id from account id
278
        UnableToDeriveValidatorId,
279
    }
280

            
281
    #[pallet::call]
282
    impl<T: Config> Pallet<T> {
283
        /// Allow to ignore external validators and use only whitelisted ones.
284
        ///
285
        /// The origin for this call must be the `UpdateOrigin`.
286
        #[pallet::call_index(0)]
287
        #[pallet::weight(T::WeightInfo::skip_external_validators())]
288
13
        pub fn skip_external_validators(origin: OriginFor<T>, skip: bool) -> DispatchResult {
289
13
            T::UpdateOrigin::ensure_origin(origin)?;
290

            
291
13
            <SkipExternalValidators<T>>::put(skip);
292
13

            
293
13
            Ok(())
294
        }
295

            
296
        /// Add a new account `who` to the list of `WhitelistedValidators`.
297
        ///
298
        /// The origin for this call must be the `UpdateOrigin`.
299
        #[pallet::call_index(1)]
300
        #[pallet::weight(T::WeightInfo::add_whitelisted(
301
			T::MaxWhitelistedValidators::get().saturating_sub(1),
302
		))]
303
        #[allow(clippy::useless_conversion)]
304
30
        pub fn add_whitelisted(origin: OriginFor<T>, who: T::AccountId) -> DispatchResult {
305
30
            T::UpdateOrigin::ensure_origin(origin)?;
306
            // don't let one unprepared validator ruin things for everyone.
307
29
            let maybe_validator_id = T::ValidatorIdOf::convert(who.clone())
308
29
                .filter(T::ValidatorRegistration::is_registered);
309

            
310
29
            let validator_id = maybe_validator_id.ok_or(Error::<T>::NoKeysRegistered)?;
311

            
312
28
            <WhitelistedValidators<T>>::try_mutate(|whitelisted| -> DispatchResult {
313
28
                if whitelisted.contains(&validator_id) {
314
1
                    Err(Error::<T>::AlreadyWhitelisted)?;
315
27
                }
316
27
                whitelisted
317
27
                    .try_push(validator_id.clone())
318
27
                    .map_err(|_| Error::<T>::TooManyWhitelisted)?;
319
26
                Ok(())
320
28
            })?;
321

            
322
26
            Self::deposit_event(Event::WhitelistedValidatorAdded { account_id: who });
323
26

            
324
26
            Ok(())
325
        }
326

            
327
        /// Remove an account `who` from the list of `WhitelistedValidators` collators.
328
        ///
329
        /// The origin for this call must be the `UpdateOrigin`.
330
        #[pallet::call_index(2)]
331
        #[pallet::weight(T::WeightInfo::remove_whitelisted(T::MaxWhitelistedValidators::get()))]
332
31
        pub fn remove_whitelisted(origin: OriginFor<T>, who: T::AccountId) -> DispatchResult {
333
31
            T::UpdateOrigin::ensure_origin(origin)?;
334

            
335
30
            let validator_id = T::ValidatorIdOf::convert(who.clone())
336
30
                .ok_or(Error::<T>::UnableToDeriveValidatorId)?;
337

            
338
30
            <WhitelistedValidators<T>>::try_mutate(|whitelisted| -> DispatchResult {
339
30
                let pos = whitelisted
340
30
                    .iter()
341
33
                    .position(|x| x == &validator_id)
342
30
                    .ok_or(Error::<T>::NotWhitelisted)?;
343
29
                whitelisted.remove(pos);
344
29
                Ok(())
345
30
            })?;
346

            
347
29
            Self::deposit_event(Event::WhitelistedValidatorRemoved { account_id: who });
348
29
            Ok(())
349
        }
350

            
351
        /// Force when the next era will start. Possible values: next session, never, same as always.
352
        #[pallet::call_index(3)]
353
        #[pallet::weight(T::WeightInfo::force_era())]
354
6
        pub fn force_era(origin: OriginFor<T>, mode: Forcing) -> DispatchResult {
355
6
            T::UpdateOrigin::ensure_origin(origin)?;
356
6
            Self::set_force_era(mode);
357
6
            Ok(())
358
        }
359

            
360
        /// Manually set external validators. Should only be needed for tests, validators are set
361
        /// automatically by the bridge.
362
        #[pallet::call_index(4)]
363
        #[pallet::weight(T::WeightInfo::set_external_validators())]
364
        pub fn set_external_validators(
365
            origin: OriginFor<T>,
366
            validators: Vec<T::ValidatorId>,
367
            external_index: u64,
368
        ) -> DispatchResult {
369
            T::UpdateOrigin::ensure_origin(origin)?;
370

            
371
            Self::set_external_validators_inner(validators, external_index)
372
        }
373
    }
374

            
375
    impl<T: Config> Pallet<T> {
376
56
        pub fn set_external_validators_inner(
377
56
            validators: Vec<T::ValidatorId>,
378
56
            external_index: u64,
379
56
        ) -> DispatchResult {
380
56
            // If more validators than max, take the first n
381
56
            let validators = BoundedVec::truncate_from(validators);
382
56
            <ExternalValidators<T>>::put(&validators);
383
56
            <ExternalIndex<T>>::put(external_index);
384
56

            
385
56
            Self::deposit_event(Event::<T>::ExternalValidatorsSet {
386
56
                validators: validators.into_inner(),
387
56
                external_index,
388
56
            });
389
56
            Ok(())
390
56
        }
391

            
392
        /// Helper to set a new `ForceEra` mode.
393
8
        pub(crate) fn set_force_era(mode: Forcing) {
394
8
            log::info!("Setting force era mode {:?}.", mode);
395
8
            ForceEra::<T>::put(mode);
396
8
            Self::deposit_event(Event::<T>::ForceEra { mode });
397
8
        }
398

            
399
60
        pub fn whitelisted_validators() -> Vec<T::ValidatorId> {
400
60
            <WhitelistedValidators<T>>::get().into()
401
60
        }
402

            
403
2003
        pub fn active_era() -> Option<ActiveEraInfo> {
404
2003
            <ActiveEra<T>>::get()
405
2003
        }
406

            
407
1856
        pub fn current_era() -> Option<EraIndex> {
408
1856
            <CurrentEra<T>>::get()
409
1856
        }
410

            
411
3256
        pub fn eras_start_session_index(era: EraIndex) -> Option<u32> {
412
3256
            <ErasStartSessionIndex<T>>::get(era)
413
3256
        }
414

            
415
        /// Returns validators for the next session. Whitelisted validators first, then external validators.
416
        /// The returned list is deduplicated, but the order is respected.
417
        /// If `SkipExternalValidators` is true, this function will ignore external validators.
418
786
        pub fn validators() -> Vec<T::ValidatorId> {
419
786
            let mut validators: Vec<_> = WhitelistedValidators::<T>::get().into();
420
786

            
421
786
            if !SkipExternalValidators::<T>::get() {
422
781
                validators.extend(ExternalValidators::<T>::get())
423
5
            }
424

            
425
786
            remove_duplicates(validators)
426
786
        }
427

            
428
        /// Plan a new session potentially trigger a new era.
429
1772
        pub(crate) fn new_session(session_index: SessionIndex) -> Option<Vec<T::ValidatorId>> {
430
1772
            if let Some(current_era) = Self::current_era() {
431
                // Initial era has been set.
432
1257
                let current_era_start_session_index = Self::eras_start_session_index(current_era)
433
1257
                    .unwrap_or_else(|| {
434
                        frame_support::print(
435
                            "Error: start_session_index must be set for current_era",
436
                        );
437
                        0
438
1257
                    });
439
1257

            
440
1257
                let era_length = session_index.saturating_sub(current_era_start_session_index); // Must never happen.
441

            
442
1241
                match ForceEra::<T>::get() {
443
                    // Will be set to `NotForcing` again if a new era has been triggered.
444
2
                    Forcing::ForceNew => (),
445
                    // Short circuit to `try_trigger_new_era`.
446
8
                    Forcing::ForceAlways => (),
447
                    // Only go to `try_trigger_new_era` if deadline reached.
448
1241
                    Forcing::NotForcing if era_length >= T::SessionsPerEra::get() => (),
449
                    _ => {
450
                        // Either `Forcing::ForceNone`,
451
                        // or `Forcing::NotForcing if era_length < T::SessionsPerEra::get()`.
452
1005
                        return None;
453
                    }
454
                }
455

            
456
                // New era.
457
252
                let maybe_new_era_validators = Self::try_trigger_new_era(session_index);
458
252
                if maybe_new_era_validators.is_some()
459
252
                    && matches!(ForceEra::<T>::get(), Forcing::ForceNew)
460
2
                {
461
2
                    Self::set_force_era(Forcing::NotForcing);
462
250
                }
463

            
464
252
                maybe_new_era_validators
465
            } else {
466
                // Set initial era.
467
515
                log!(log::Level::Debug, "Starting the first era.");
468
515
                Self::try_trigger_new_era(session_index)
469
            }
470
1772
        }
471

            
472
        /// Start a session potentially starting an era.
473
1257
        pub(crate) fn start_session(start_session: SessionIndex) {
474
1257
            let next_active_era = Self::active_era()
475
1257
                .map(|e| e.index.saturating_add(1))
476
1257
                .unwrap_or(0);
477
            // This is only `Some` when current era has already progressed to the next era, while the
478
            // active era is one behind (i.e. in the *last session of the active era*, or *first session
479
            // of the new current era*, depending on how you look at it).
480
691
            if let Some(next_active_era_start_session_index) =
481
1257
                Self::eras_start_session_index(next_active_era)
482
            {
483
691
                if next_active_era_start_session_index == start_session {
484
691
                    Self::start_era(start_session);
485
691
                } else if next_active_era_start_session_index < start_session {
486
                    // This arm should never happen, but better handle it than to stall the pallet.
487
                    frame_support::print("Warning: A session appears to have been skipped.");
488
                    Self::start_era(start_session);
489
                }
490
566
            }
491
1257
        }
492

            
493
        /// End a session potentially ending an era.
494
742
        pub(crate) fn end_session(session_index: SessionIndex) {
495
742
            if let Some(active_era) = Self::active_era() {
496
176
                if let Some(next_active_era_start_session_index) =
497
742
                    Self::eras_start_session_index(active_era.index.saturating_add(1))
498
                {
499
176
                    if next_active_era_start_session_index == session_index.saturating_add(1) {
500
176
                        Self::end_era(active_era, session_index);
501
176
                    }
502
566
                }
503
            }
504
742
        }
505

            
506
        /// Start a new era. It does:
507
        /// * Increment `active_era.index`,
508
        /// * reset `active_era.start`,
509
        /// * emit `NewEra` event,
510
        /// * call `OnEraStart` hook,
511
691
        pub(crate) fn start_era(start_session: SessionIndex) {
512
691
            let active_era = ActiveEra::<T>::mutate(|active_era| {
513
691
                let new_index = active_era
514
691
                    .as_ref()
515
691
                    .map(|info| info.index.saturating_add(1))
516
691
                    .unwrap_or(0);
517
691
                *active_era = Some(ActiveEraInfo {
518
691
                    index: new_index,
519
691
                    // Set new active era start in next `on_finalize`. To guarantee usage of `Time`
520
691
                    start: None,
521
691
                });
522
691
                new_index
523
691
            });
524
691
            WhitelistedValidatorsActiveEra::<T>::put(
525
691
                WhitelistedValidatorsActiveEraPending::<T>::take(),
526
691
            );
527
691
            let external_idx = PendingExternalIndex::<T>::take();
528
691
            CurrentExternalIndex::<T>::put(external_idx);
529
691
            Self::deposit_event(Event::NewEra { era: active_era });
530
691
            T::OnEraStart::on_era_start(active_era, start_session, external_idx);
531
691
        }
532

            
533
        /// End era. It does:
534
        /// * call `OnEraEnd` hook,
535
176
        pub(crate) fn end_era(active_era: ActiveEraInfo, _session_index: SessionIndex) {
536
176
            // Note: active_era.start can be None if end era is called during genesis config.
537
176
            T::OnEraEnd::on_era_end(active_era.index);
538
176
        }
539

            
540
        /// Plan a new era.
541
        ///
542
        /// * Bump the current era storage (which holds the latest planned era).
543
        /// * Store start session index for the new planned era.
544
        /// * Clean old era information.
545
        ///
546
        /// Returns the new validator set.
547
767
        pub fn trigger_new_era(start_session_index: SessionIndex) -> Vec<T::ValidatorId> {
548
767
            // Increment or set current era.
549
767
            let new_planned_era = CurrentEra::<T>::mutate(|s| {
550
767
                *s = Some(s.map(|s| s.saturating_add(1)).unwrap_or(0));
551
767
                s.unwrap()
552
767
            });
553
767
            ErasStartSessionIndex::<T>::insert(&new_planned_era, &start_session_index);
554

            
555
            // Clean old era information.
556
            if let Some(old_era) =
557
767
                new_planned_era.checked_sub(T::HistoryDepth::get().saturating_add(1))
558
            {
559
                Self::clear_era_information(old_era);
560
767
            }
561

            
562
            // Save whitelisted validators for when the era truly changes (start_era)
563
767
            WhitelistedValidatorsActiveEraPending::<T>::put(WhitelistedValidators::<T>::get());
564
767
            // Save the external index for when the era truly changes (start_era)
565
767
            PendingExternalIndex::<T>::put(ExternalIndex::<T>::get());
566
767

            
567
767
            // Returns new validators
568
767
            Self::validators()
569
767
        }
570

            
571
        /// Potentially plan a new era.
572
        ///
573
        /// In case a new era is planned, the new validator set is returned.
574
767
        pub(crate) fn try_trigger_new_era(
575
767
            start_session_index: SessionIndex,
576
767
        ) -> Option<Vec<T::ValidatorId>> {
577
767
            Some(Self::trigger_new_era(start_session_index))
578
767
        }
579

            
580
        /// Clear all era information for given era.
581
        pub(crate) fn clear_era_information(era_index: EraIndex) {
582
            ErasStartSessionIndex::<T>::remove(era_index);
583
        }
584
    }
585

            
586
3
    #[pallet::hooks]
587
    impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {
588
333
        fn on_initialize(_now: BlockNumberFor<T>) -> Weight {
589
333
            // just return the weight of the on_finalize.
590
333
            T::DbWeight::get().reads(1)
591
333
        }
592

            
593
333
        fn on_finalize(_n: BlockNumberFor<T>) {
594
            // Set the start of the first era.
595
333
            if let Some(mut active_era) = <ActiveEra<T>>::get() {
596
333
                if active_era.start.is_none() {
597
23
                    let now_as_millis_u64 = T::UnixTime::now().as_millis().saturated_into::<u64>();
598
23
                    active_era.start = Some(now_as_millis_u64);
599
23
                    // This write only ever happens once, we don't include it in the weight in
600
23
                    // general
601
23
                    ActiveEra::<T>::put(active_era);
602
310
                }
603
            }
604
            // `on_finalize` weight is tracked in `on_initialize`
605
333
        }
606
    }
607

            
608
    impl<T: Config> ExternalIndexProvider for Pallet<T> {
609
41
        fn get_external_index() -> u64 {
610
41
            CurrentExternalIndex::<T>::get()
611
41
        }
612
    }
613
}
614

            
615
/// Keeps only the first instance of each element in the input vec. Respects ordering of elements.
616
786
fn remove_duplicates<T: Ord + Clone>(input: Vec<T>) -> Vec<T> {
617
786
    let mut seen = BTreeSet::new();
618
786
    let mut result = Vec::with_capacity(input.len());
619

            
620
2395
    for item in input {
621
1609
        if seen.insert(item.clone()) {
622
1602
            result.push(item);
623
1602
        }
624
    }
625

            
626
786
    result
627
786
}
628

            
629
impl<T: Config> pallet_session::SessionManager<T::ValidatorId> for Pallet<T> {
630
1740
    fn new_session(new_index: SessionIndex) -> Option<Vec<T::ValidatorId>> {
631
1740
        log!(log::Level::Trace, "planning new session {}", new_index);
632
1740
        Self::new_session(new_index)
633
1740
    }
634
32
    fn new_session_genesis(new_index: SessionIndex) -> Option<Vec<T::ValidatorId>> {
635
32
        log!(
636
32
            log::Level::Trace,
637
            "planning new session {} at genesis",
638
            new_index
639
        );
640
32
        Self::new_session(new_index)
641
32
    }
642
1257
    fn start_session(start_index: SessionIndex) {
643
1257
        log!(log::Level::Trace, "starting session {}", start_index);
644
1257
        Self::start_session(start_index)
645
1257
    }
646
742
    fn end_session(end_index: SessionIndex) {
647
742
        log!(log::Level::Trace, "ending session {}", end_index);
648
742
        Self::end_session(end_index)
649
742
    }
650
}
651

            
652
impl<T: Config> pallet_session::historical::SessionManager<T::ValidatorId, ()> for Pallet<T> {
653
1676
    fn new_session(new_index: SessionIndex) -> Option<Vec<(T::ValidatorId, ())>> {
654
1676
        <Self as pallet_session::SessionManager<_>>::new_session(new_index)
655
1712
            .map(|r| r.into_iter().map(|v| (v, Default::default())).collect())
656
1676
    }
657

            
658
1177
    fn start_session(start_index: SessionIndex) {
659
1177
        <Self as pallet_session::SessionManager<_>>::start_session(start_index)
660
1177
    }
661

            
662
678
    fn end_session(end_index: SessionIndex) {
663
678
        <Self as pallet_session::SessionManager<_>>::end_session(end_index)
664
678
    }
665
}
666

            
667
impl<T: Config> EraIndexProvider for Pallet<T> {
668
8380
    fn active_era() -> ActiveEraInfo {
669
8380
        <ActiveEra<T>>::get().unwrap_or(ActiveEraInfo {
670
8380
            index: 0,
671
8380
            start: None,
672
8380
        })
673
8380
    }
674

            
675
648
    fn era_to_session_start(era_index: EraIndex) -> Option<u32> {
676
648
        <ErasStartSessionIndex<T>>::get(era_index)
677
648
    }
678
}
679

            
680
impl<T: Config> ValidatorProvider<T::ValidatorId> for Pallet<T> {
681
1
    fn validators() -> Vec<T::ValidatorId> {
682
1
        Self::validators()
683
1
    }
684
}
685

            
686
impl<T: Config> InvulnerablesProvider<T::ValidatorId> for Pallet<T> {
687
24
    fn invulnerables() -> Vec<T::ValidatorId> {
688
24
        Self::whitelisted_validators()
689
24
    }
690
}
691

            
692
/// Mode of era-forcing.
693
#[derive(
694
    Copy,
695
    Clone,
696
    PartialEq,
697
    Eq,
698
    Default,
699
    Encode,
700
    Decode,
701
    DecodeWithMemTracking,
702
    RuntimeDebug,
703
    TypeInfo,
704
    MaxEncodedLen,
705
)]
706
pub enum Forcing {
707
10
    /// Not forcing anything - just let whatever happen.
708
    #[default]
709
    NotForcing,
710
4
    /// Force a new era on the next session start, then reset to `NotForcing` as soon as it is done.
711
    ForceNew,
712
6
    /// Avoid a new era indefinitely.
713
    ForceNone,
714
16
    /// Force a new era at the end of all sessions indefinitely.
715
    ForceAlways,
716
}