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
//! # Initializer Pallet
18
//!
19
//! This pallet is in charge of organizing what happens on session changes.
20
//! In particular this pallet has implemented the OneSessionHandler trait
21
//! which will be called upon a session change. There it will call the
22
//! SessionHandler config trait
23

            
24
#![cfg_attr(not(feature = "std"), no_std)]
25

            
26
#[cfg(test)]
27
mod mock;
28

            
29
#[cfg(test)]
30
mod tests;
31

            
32
pub use pallet::*;
33
use {
34
    frame_support::{pallet_prelude::*, traits::OneSessionHandler},
35
    scale_info::TypeInfo,
36
    sp_runtime::{traits::AtLeast32BitUnsigned, RuntimeAppPublic},
37
    sp_std::prelude::*,
38
};
39

            
40
1165
#[frame_support::pallet]
41
pub mod pallet {
42
    use super::*;
43

            
44
    // The apply_new_session trait. We need to comply with this
45
    pub trait ApplyNewSession<T: Config> {
46
        fn apply_new_session(
47
            changed: bool,
48
            session_index: T::SessionIndex,
49
            all_validators: Vec<(T::AccountId, T::AuthorityId)>,
50
            queued: Vec<(T::AccountId, T::AuthorityId)>,
51
        );
52
    }
53

            
54
48356
    #[pallet::pallet]
55
    pub struct Pallet<T>(_);
56

            
57
    #[pallet::config]
58
    pub trait Config: frame_system::Config {
59
        type SessionIndex: parity_scale_codec::FullCodec + TypeInfo + Copy + AtLeast32BitUnsigned;
60

            
61
        /// The identifier type for an authority.
62
        type AuthorityId: Member
63
            + Parameter
64
            + RuntimeAppPublic
65
            + MaybeSerializeDeserialize
66
            + MaxEncodedLen;
67

            
68
        type SessionHandler: ApplyNewSession<Self>;
69
    }
70
}
71

            
72
impl<T: Config> Pallet<T> {
73
    /// Should be called when a new session occurs. If `queued` is `None`,
74
    /// the `validators` are considered queued.
75
2946
    fn on_new_session<'a, I>(
76
2946
        changed: bool,
77
2946
        session_index: T::SessionIndex,
78
2946
        validators: I,
79
2946
        queued: Option<I>,
80
2946
    ) where
81
2946
        I: Iterator<Item = (&'a T::AccountId, T::AuthorityId)> + 'a,
82
2946
    {
83
10560
        let validators: Vec<_> = validators.map(|(k, v)| (k.clone(), v)).collect();
84
2946
        let queued: Vec<_> = if let Some(queued) = queued {
85
9715
            queued.map(|(k, v)| (k.clone(), v)).collect()
86
        } else {
87
360
            validators.clone()
88
        };
89

            
90
2946
        T::SessionHandler::apply_new_session(changed, session_index, validators, queued);
91
2946
    }
92

            
93
    /// Should be called when a new session occurs. Buffers the session notification to be applied
94
    /// at the end of the block. If `queued` is `None`, the `validators` are considered queued.
95
360
    fn on_genesis_session<'a, I>(validators: I)
96
360
    where
97
360
        I: Iterator<Item = (&'a T::AccountId, T::AuthorityId)> + 'a,
98
360
    {
99
360
        <Pallet<T>>::on_new_session(false, 0u32.into(), validators, None);
100
360
    }
101

            
102
    // Allow to trigger `on_new_session` in tests, this is needed as long as `pallet_session` is not
103
    // implemented in mock.
104
    #[cfg(test)]
105
2
    pub(crate) fn test_trigger_on_new_session<'a, I>(
106
2
        changed: bool,
107
2
        session_index: T::SessionIndex,
108
2
        validators: I,
109
2
        queued: Option<I>,
110
2
    ) where
111
2
        I: Iterator<Item = (&'a T::AccountId, T::AuthorityId)> + 'a,
112
2
    {
113
2
        Self::on_new_session(changed, session_index, validators, queued)
114
2
    }
115
}
116

            
117
impl<T: Config> sp_runtime::BoundToRuntimeAppPublic for Pallet<T> {
118
    type Public = T::AuthorityId;
119
}
120

            
121
impl<T: pallet_session::Config + Config> OneSessionHandler<T::AccountId> for Pallet<T> {
122
    type Key = T::AuthorityId;
123

            
124
360
    fn on_genesis_session<'a, I>(validators: I)
125
360
    where
126
360
        I: Iterator<Item = (&'a T::AccountId, Self::Key)> + 'a,
127
360
    {
128
360
        <Pallet<T>>::on_genesis_session(validators);
129
360
    }
130

            
131
2584
    fn on_new_session<'a, I>(changed: bool, validators: I, queued: I)
132
2584
    where
133
2584
        I: Iterator<Item = (&'a T::AccountId, Self::Key)> + 'a,
134
2584
    {
135
2584
        let session_index = <pallet_session::Pallet<T>>::current_index();
136
2584
        <Pallet<T>>::on_new_session(changed, session_index.into(), validators, Some(queued));
137
2584
    }
138

            
139
    fn on_disabled(_i: u32) {}
140
}