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, 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
82
#[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
            dispatch::DispatchResultWithPostInfo,
70
            pallet_prelude::*,
71
            traits::{EnsureOrigin, UnixTime, ValidatorRegistration},
72
            BoundedVec, DefaultNoBound,
73
        },
74
        frame_system::pallet_prelude::*,
75
        sp_runtime::{traits::Convert, SaturatedConversion},
76
        sp_std::vec::Vec,
77
    };
78

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

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

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

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

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

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

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

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

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

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

            
136
        type OnEraStart: OnEraStart;
137
        type OnEraEnd: OnEraEnd;
138

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

            
294
13
            Ok(())
295
        }
296

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

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

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

            
325
26
            Self::deposit_event(Event::WhitelistedValidatorAdded { account_id: who });
326
26

            
327
26
            let weight_used = <T as Config>::WeightInfo::add_whitelisted(
328
26
                WhitelistedValidators::<T>::decode_len()
329
26
                    .unwrap_or_default()
330
26
                    .try_into()
331
26
                    .unwrap_or(T::MaxWhitelistedValidators::get().saturating_sub(1)),
332
26
            );
333
26

            
334
26
            Ok(Some(weight_used).into())
335
        }
336

            
337
        /// Remove an account `who` from the list of `WhitelistedValidators` collators.
338
        ///
339
        /// The origin for this call must be the `UpdateOrigin`.
340
        #[pallet::call_index(2)]
341
        #[pallet::weight(T::WeightInfo::remove_whitelisted(T::MaxWhitelistedValidators::get()))]
342
31
        pub fn remove_whitelisted(origin: OriginFor<T>, who: T::AccountId) -> DispatchResult {
343
31
            T::UpdateOrigin::ensure_origin(origin)?;
344

            
345
30
            let validator_id = T::ValidatorIdOf::convert(who.clone())
346
30
                .ok_or(Error::<T>::UnableToDeriveValidatorId)?;
347

            
348
30
            <WhitelistedValidators<T>>::try_mutate(|whitelisted| -> DispatchResult {
349
30
                let pos = whitelisted
350
30
                    .iter()
351
33
                    .position(|x| x == &validator_id)
352
30
                    .ok_or(Error::<T>::NotWhitelisted)?;
353
29
                whitelisted.remove(pos);
354
29
                Ok(())
355
30
            })?;
356

            
357
29
            Self::deposit_event(Event::WhitelistedValidatorRemoved { account_id: who });
358
29
            Ok(())
359
        }
360

            
361
        /// Force when the next era will start. Possible values: next session, never, same as always.
362
        #[pallet::call_index(3)]
363
        #[pallet::weight(T::WeightInfo::force_era())]
364
6
        pub fn force_era(origin: OriginFor<T>, mode: Forcing) -> DispatchResult {
365
6
            T::UpdateOrigin::ensure_origin(origin)?;
366
6
            Self::set_force_era(mode);
367
6
            Ok(())
368
        }
369

            
370
        /// Manually set external validators. Should only be needed for tests, validators are set
371
        /// automatically by the bridge.
372
        #[pallet::call_index(4)]
373
        #[pallet::weight(T::WeightInfo::set_external_validators())]
374
        pub fn set_external_validators(
375
            origin: OriginFor<T>,
376
            validators: Vec<T::ValidatorId>,
377
            external_index: u64,
378
        ) -> DispatchResult {
379
            T::UpdateOrigin::ensure_origin(origin)?;
380

            
381
            Self::set_external_validators_inner(validators, external_index)
382
        }
383
    }
384

            
385
    impl<T: Config> Pallet<T> {
386
56
        pub fn set_external_validators_inner(
387
56
            validators: Vec<T::ValidatorId>,
388
56
            external_index: u64,
389
56
        ) -> DispatchResult {
390
56
            // If more validators than max, take the first n
391
56
            let validators = BoundedVec::truncate_from(validators);
392
56
            <ExternalValidators<T>>::put(&validators);
393
56
            <ExternalIndex<T>>::put(external_index);
394
56

            
395
56
            Self::deposit_event(Event::<T>::ExternalValidatorsSet {
396
56
                validators: validators.into_inner(),
397
56
                external_index,
398
56
            });
399
56
            Ok(())
400
56
        }
401

            
402
        /// Helper to set a new `ForceEra` mode.
403
8
        pub(crate) fn set_force_era(mode: Forcing) {
404
8
            log::info!("Setting force era mode {:?}.", mode);
405
8
            ForceEra::<T>::put(mode);
406
8
            Self::deposit_event(Event::<T>::ForceEra { mode });
407
8
        }
408

            
409
60
        pub fn whitelisted_validators() -> Vec<T::ValidatorId> {
410
60
            <WhitelistedValidators<T>>::get().into()
411
60
        }
412

            
413
1986
        pub fn active_era() -> Option<ActiveEraInfo> {
414
1986
            <ActiveEra<T>>::get()
415
1986
        }
416

            
417
1822
        pub fn current_era() -> Option<EraIndex> {
418
1822
            <CurrentEra<T>>::get()
419
1822
        }
420

            
421
3222
        pub fn eras_start_session_index(era: EraIndex) -> Option<u32> {
422
3222
            <ErasStartSessionIndex<T>>::get(era)
423
3222
        }
424

            
425
        /// Returns validators for the next session. Whitelisted validators first, then external validators.
426
        /// The returned list is deduplicated, but the order is respected.
427
        /// If `SkipExternalValidators` is true, this function will ignore external validators.
428
769
        pub fn validators() -> Vec<T::ValidatorId> {
429
769
            let mut validators: Vec<_> = WhitelistedValidators::<T>::get().into();
430
769

            
431
769
            if !SkipExternalValidators::<T>::get() {
432
764
                validators.extend(ExternalValidators::<T>::get())
433
5
            }
434

            
435
769
            remove_duplicates(validators)
436
769
        }
437

            
438
        /// Plan a new session potentially trigger a new era.
439
1738
        pub(crate) fn new_session(session_index: SessionIndex) -> Option<Vec<T::ValidatorId>> {
440
1738
            if let Some(current_era) = Self::current_era() {
441
                // Initial era has been set.
442
1240
                let current_era_start_session_index = Self::eras_start_session_index(current_era)
443
1240
                    .unwrap_or_else(|| {
444
                        frame_support::print(
445
                            "Error: start_session_index must be set for current_era",
446
                        );
447
                        0
448
1240
                    });
449
1240

            
450
1240
                let era_length = session_index.saturating_sub(current_era_start_session_index); // Must never happen.
451

            
452
1224
                match ForceEra::<T>::get() {
453
                    // Will be set to `NotForcing` again if a new era has been triggered.
454
2
                    Forcing::ForceNew => (),
455
                    // Short circuit to `try_trigger_new_era`.
456
8
                    Forcing::ForceAlways => (),
457
                    // Only go to `try_trigger_new_era` if deadline reached.
458
1224
                    Forcing::NotForcing if era_length >= T::SessionsPerEra::get() => (),
459
                    _ => {
460
                        // Either `Forcing::ForceNone`,
461
                        // or `Forcing::NotForcing if era_length < T::SessionsPerEra::get()`.
462
988
                        return None;
463
                    }
464
                }
465

            
466
                // New era.
467
252
                let maybe_new_era_validators = Self::try_trigger_new_era(session_index);
468
252
                if maybe_new_era_validators.is_some()
469
252
                    && matches!(ForceEra::<T>::get(), Forcing::ForceNew)
470
2
                {
471
2
                    Self::set_force_era(Forcing::NotForcing);
472
250
                }
473

            
474
252
                maybe_new_era_validators
475
            } else {
476
                // Set initial era.
477
498
                log!(log::Level::Debug, "Starting the first era.");
478
498
                Self::try_trigger_new_era(session_index)
479
            }
480
1738
        }
481

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

            
503
        /// End a session potentially ending an era.
504
742
        pub(crate) fn end_session(session_index: SessionIndex) {
505
742
            if let Some(active_era) = Self::active_era() {
506
176
                if let Some(next_active_era_start_session_index) =
507
742
                    Self::eras_start_session_index(active_era.index.saturating_add(1))
508
                {
509
176
                    if next_active_era_start_session_index == session_index.saturating_add(1) {
510
176
                        Self::end_era(active_era, session_index);
511
176
                    }
512
566
                }
513
            }
514
742
        }
515

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

            
543
        /// End era. It does:
544
        /// * call `OnEraEnd` hook,
545
176
        pub(crate) fn end_era(active_era: ActiveEraInfo, _session_index: SessionIndex) {
546
176
            // Note: active_era.start can be None if end era is called during genesis config.
547
176
            T::OnEraEnd::on_era_end(active_era.index);
548
176
        }
549

            
550
        /// Plan a new era.
551
        ///
552
        /// * Bump the current era storage (which holds the latest planned era).
553
        /// * Store start session index for the new planned era.
554
        /// * Clean old era information.
555
        ///
556
        /// Returns the new validator set.
557
750
        pub fn trigger_new_era(start_session_index: SessionIndex) -> Vec<T::ValidatorId> {
558
750
            // Increment or set current era.
559
750
            let new_planned_era = CurrentEra::<T>::mutate(|s| {
560
750
                *s = Some(s.map(|s| s.saturating_add(1)).unwrap_or(0));
561
750
                s.unwrap()
562
750
            });
563
750
            ErasStartSessionIndex::<T>::insert(&new_planned_era, &start_session_index);
564

            
565
            // Clean old era information.
566
            if let Some(old_era) =
567
750
                new_planned_era.checked_sub(T::HistoryDepth::get().saturating_add(1))
568
            {
569
                Self::clear_era_information(old_era);
570
750
            }
571

            
572
            // Save whitelisted validators for when the era truly changes (start_era)
573
750
            WhitelistedValidatorsActiveEraPending::<T>::put(WhitelistedValidators::<T>::get());
574
750
            // Save the external index for when the era truly changes (start_era)
575
750
            PendingExternalIndex::<T>::put(ExternalIndex::<T>::get());
576
750

            
577
750
            // Returns new validators
578
750
            Self::validators()
579
750
        }
580

            
581
        /// Potentially plan a new era.
582
        ///
583
        /// In case a new era is planned, the new validator set is returned.
584
750
        pub(crate) fn try_trigger_new_era(
585
750
            start_session_index: SessionIndex,
586
750
        ) -> Option<Vec<T::ValidatorId>> {
587
750
            Some(Self::trigger_new_era(start_session_index))
588
750
        }
589

            
590
        /// Clear all era information for given era.
591
        pub(crate) fn clear_era_information(era_index: EraIndex) {
592
            ErasStartSessionIndex::<T>::remove(era_index);
593
        }
594
    }
595

            
596
669
    #[pallet::hooks]
597
    impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {
598
333
        fn on_initialize(_now: BlockNumberFor<T>) -> Weight {
599
333
            // just return the weight of the on_finalize.
600
333
            T::DbWeight::get().reads(1)
601
333
        }
602

            
603
333
        fn on_finalize(_n: BlockNumberFor<T>) {
604
            // Set the start of the first era.
605
333
            if let Some(mut active_era) = <ActiveEra<T>>::get() {
606
333
                if active_era.start.is_none() {
607
23
                    let now_as_millis_u64 = T::UnixTime::now().as_millis().saturated_into::<u64>();
608
23
                    active_era.start = Some(now_as_millis_u64);
609
23
                    // This write only ever happens once, we don't include it in the weight in
610
23
                    // general
611
23
                    ActiveEra::<T>::put(active_era);
612
310
                }
613
            }
614
            // `on_finalize` weight is tracked in `on_initialize`
615
333
        }
616
    }
617

            
618
    impl<T: Config> ExternalIndexProvider for Pallet<T> {
619
41
        fn get_external_index() -> u64 {
620
41
            CurrentExternalIndex::<T>::get()
621
41
        }
622
    }
623
}
624

            
625
/// Keeps only the first instance of each element in the input vec. Respects ordering of elements.
626
769
fn remove_duplicates<T: Ord + Clone>(input: Vec<T>) -> Vec<T> {
627
769
    let mut seen = BTreeSet::new();
628
769
    let mut result = Vec::with_capacity(input.len());
629

            
630
2360
    for item in input {
631
1591
        if seen.insert(item.clone()) {
632
1584
            result.push(item);
633
1584
        }
634
    }
635

            
636
769
    result
637
769
}
638

            
639
impl<T: Config> pallet_session::SessionManager<T::ValidatorId> for Pallet<T> {
640
1706
    fn new_session(new_index: SessionIndex) -> Option<Vec<T::ValidatorId>> {
641
1706
        log!(log::Level::Trace, "planning new session {}", new_index);
642
1706
        Self::new_session(new_index)
643
1706
    }
644
32
    fn new_session_genesis(new_index: SessionIndex) -> Option<Vec<T::ValidatorId>> {
645
32
        log!(
646
32
            log::Level::Trace,
647
            "planning new session {} at genesis",
648
            new_index
649
        );
650
32
        Self::new_session(new_index)
651
32
    }
652
1240
    fn start_session(start_index: SessionIndex) {
653
1240
        log!(log::Level::Trace, "starting session {}", start_index);
654
1240
        Self::start_session(start_index)
655
1240
    }
656
742
    fn end_session(end_index: SessionIndex) {
657
742
        log!(log::Level::Trace, "ending session {}", end_index);
658
742
        Self::end_session(end_index)
659
742
    }
660
}
661

            
662
impl<T: Config> pallet_session::historical::SessionManager<T::ValidatorId, ()> for Pallet<T> {
663
1642
    fn new_session(new_index: SessionIndex) -> Option<Vec<(T::ValidatorId, ())>> {
664
1642
        <Self as pallet_session::SessionManager<_>>::new_session(new_index)
665
1678
            .map(|r| r.into_iter().map(|v| (v, Default::default())).collect())
666
1642
    }
667

            
668
1160
    fn start_session(start_index: SessionIndex) {
669
1160
        <Self as pallet_session::SessionManager<_>>::start_session(start_index)
670
1160
    }
671

            
672
678
    fn end_session(end_index: SessionIndex) {
673
678
        <Self as pallet_session::SessionManager<_>>::end_session(end_index)
674
678
    }
675
}
676

            
677
impl<T: Config> EraIndexProvider for Pallet<T> {
678
8372
    fn active_era() -> ActiveEraInfo {
679
8372
        <ActiveEra<T>>::get().unwrap_or(ActiveEraInfo {
680
8372
            index: 0,
681
8372
            start: None,
682
8372
        })
683
8372
    }
684

            
685
648
    fn era_to_session_start(era_index: EraIndex) -> Option<u32> {
686
648
        <ErasStartSessionIndex<T>>::get(era_index)
687
648
    }
688
}
689

            
690
impl<T: Config> ValidatorProvider<T::ValidatorId> for Pallet<T> {
691
1
    fn validators() -> Vec<T::ValidatorId> {
692
1
        Self::validators()
693
1
    }
694
}
695

            
696
impl<T: Config> InvulnerablesProvider<T::ValidatorId> for Pallet<T> {
697
24
    fn invulnerables() -> Vec<T::ValidatorId> {
698
24
        Self::whitelisted_validators()
699
24
    }
700
}
701

            
702
/// Mode of era-forcing.
703
#[derive(
704
    Copy, Clone, PartialEq, Eq, Default, Encode, Decode, RuntimeDebug, TypeInfo, 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
}