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
//! A pallet for managing validators on Dancelight.
18

            
19
use {sp_staking::SessionIndex, sp_std::vec::Vec};
20

            
21
pub use pallet::*;
22

            
23
type Session<T> = pallet_session::Pallet<T>;
24

            
25
1
#[frame_support::pallet]
26
pub mod pallet {
27
    use {
28
        super::*,
29
        frame_support::{dispatch::DispatchResult, pallet_prelude::*, traits::EnsureOrigin},
30
        frame_system::pallet_prelude::*,
31
    };
32

            
33
1
    #[pallet::pallet]
34
    pub struct Pallet<T>(_);
35

            
36
    /// Configuration for the parachain proposer.
37
    #[pallet::config]
38
    pub trait Config: frame_system::Config + pallet_session::Config {
39
        /// The overreaching event type.
40
        type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
41

            
42
        /// Privileged origin that can add or remove validators.
43
        type PrivilegedOrigin: EnsureOrigin<<Self as frame_system::Config>::RuntimeOrigin>;
44
    }
45

            
46
    #[pallet::event]
47
    #[pallet::generate_deposit(pub(super) fn deposit_event)]
48
    pub enum Event<T: Config> {
49
        /// New validators were added to the set.
50
        ValidatorsRegistered(Vec<T::ValidatorId>),
51
        /// Validators were removed from the set.
52
        ValidatorsDeregistered(Vec<T::ValidatorId>),
53
    }
54

            
55
    /// Validators that should be retired, because their Parachain was deregistered.
56
428
    #[pallet::storage]
57
    #[pallet::unbounded]
58
    pub(crate) type ValidatorsToRetire<T: Config> =
59
        StorageValue<_, Vec<T::ValidatorId>, ValueQuery>;
60

            
61
    /// Validators that should be added.
62
428
    #[pallet::storage]
63
    #[pallet::unbounded]
64
    pub(crate) type ValidatorsToAdd<T: Config> = StorageValue<_, Vec<T::ValidatorId>, ValueQuery>;
65

            
66
    #[pallet::call]
67
    impl<T: Config> Pallet<T> {
68
        /// Add new validators to the set.
69
        ///
70
        /// The new validators will be active from current session + 2.
71
        #[pallet::call_index(0)]
72
        #[pallet::weight({100_000})]
73
        pub fn register_validators(
74
            origin: OriginFor<T>,
75
            validators: Vec<T::ValidatorId>,
76
        ) -> DispatchResult {
77
            T::PrivilegedOrigin::ensure_origin(origin)?;
78

            
79
            validators
80
                .clone()
81
                .into_iter()
82
                .for_each(ValidatorsToAdd::<T>::append);
83

            
84
            Self::deposit_event(Event::ValidatorsRegistered(validators));
85
            Ok(())
86
        }
87

            
88
        /// Remove validators from the set.
89
        ///
90
        /// The removed validators will be deactivated from current session + 2.
91
        #[pallet::call_index(1)]
92
        #[pallet::weight({100_000})]
93
        pub fn deregister_validators(
94
            origin: OriginFor<T>,
95
            validators: Vec<T::ValidatorId>,
96
        ) -> DispatchResult {
97
            T::PrivilegedOrigin::ensure_origin(origin)?;
98

            
99
            validators
100
                .clone()
101
                .into_iter()
102
                .for_each(ValidatorsToRetire::<T>::append);
103

            
104
            Self::deposit_event(Event::ValidatorsDeregistered(validators));
105
            Ok(())
106
        }
107
    }
108
}
109

            
110
impl<T: Config> pallet_session::SessionManager<T::ValidatorId> for Pallet<T> {
111
352
    fn new_session(new_index: SessionIndex) -> Option<Vec<T::ValidatorId>> {
112
352
        if new_index <= 1 {
113
138
            return None;
114
214
        }
115
214

            
116
214
        let mut validators = Session::<T>::validators();
117
214

            
118
214
        ValidatorsToRetire::<T>::take().iter().for_each(|v| {
119
            if let Some(pos) = validators.iter().position(|r| r == v) {
120
                validators.swap_remove(pos);
121
            }
122
214
        });
123
214

            
124
214
        ValidatorsToAdd::<T>::take().into_iter().for_each(|v| {
125
            if !validators.contains(&v) {
126
                validators.push(v);
127
            }
128
214
        });
129
214

            
130
214
        Some(validators)
131
352
    }
132

            
133
214
    fn end_session(_: SessionIndex) {}
134

            
135
283
    fn start_session(_start_index: SessionIndex) {}
136
}
137

            
138
impl<T: Config> pallet_session::historical::SessionManager<T::ValidatorId, ()> for Pallet<T> {
139
352
    fn new_session(new_index: SessionIndex) -> Option<Vec<(T::ValidatorId, ())>> {
140
352
        <Self as pallet_session::SessionManager<_>>::new_session(new_index)
141
526
            .map(|r| r.into_iter().map(|v| (v, Default::default())).collect())
142
352
    }
143

            
144
283
    fn start_session(start_index: SessionIndex) {
145
283
        <Self as pallet_session::SessionManager<_>>::start_session(start_index)
146
283
    }
147

            
148
214
    fn end_session(end_index: SessionIndex) {
149
214
        <Self as pallet_session::SessionManager<_>>::end_session(end_index)
150
214
    }
151
}