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
//! # Authority Mapping Pallet
18
//!
19
//! This pallet stores the AuthorityId -> AccountID mapping for two sessions
20
//! In particular it holds the mapping for the current and the past session
21
//! Both are necessary to verify block-authorship with respect to current
22
//! block proposals or blocks that have been proposed in the past-session
23

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

            
26
pub use pallet::*;
27
use {
28
    frame_support::pallet_prelude::*,
29
    sp_runtime::{
30
        traits::{AtLeast32BitUnsigned, CheckedSub},
31
        RuntimeAppPublic,
32
    },
33
    sp_std::{collections::btree_map::BTreeMap, vec},
34
};
35

            
36
#[cfg(test)]
37
mod mock;
38

            
39
#[cfg(test)]
40
mod tests;
41

            
42
3090
#[frame_support::pallet]
43
pub mod pallet {
44
    use super::*;
45

            
46
68755
    #[pallet::pallet]
47
    pub struct Pallet<T>(_);
48

            
49
    /// Configure the pallet by specifying the parameters and types on which it depends.
50
    #[pallet::config]
51
    pub trait Config: frame_system::Config {
52
        type SessionIndex: parity_scale_codec::FullCodec
53
            + TypeInfo
54
            + Copy
55
            + AtLeast32BitUnsigned
56
            + MaxEncodedLen;
57

            
58
        // Sessions after which keys should be removed
59
        #[pallet::constant]
60
        type SessionRemovalBoundary: Get<Self::SessionIndex>;
61

            
62
        type AuthorityId: Member
63
            + Parameter
64
            + Ord
65
            + RuntimeAppPublic
66
            + MaybeSerializeDeserialize
67
            + MaxEncodedLen;
68
    }
69

            
70
12144
    #[pallet::storage]
71
    #[pallet::unbounded]
72
    pub type AuthorityIdMapping<T: Config> = StorageMap<
73
        _,
74
        Twox64Concat,
75
        T::SessionIndex,
76
        BTreeMap<T::AuthorityId, T::AccountId>,
77
        OptionQuery,
78
    >;
79

            
80
    impl<T: Config> Pallet<T> {
81
5188
        pub fn initializer_on_new_session(
82
5188
            session_index: &T::SessionIndex,
83
5188
            authorities: &[(T::AccountId, T::AuthorityId)],
84
5188
        ) {
85
            // Remove only if the checked sub does not saturate
86
2736
            if let Some(session_index_to_remove) =
87
5188
                session_index.checked_sub(&T::SessionRemovalBoundary::get())
88
            {
89
2736
                AuthorityIdMapping::<T>::remove(session_index_to_remove)
90
2452
            }
91

            
92
5188
            let assignation: BTreeMap<T::AuthorityId, T::AccountId> =
93
14862
                authorities.iter().cloned().map(|(a, b)| (b, a)).collect();
94
5188
            AuthorityIdMapping::<T>::insert(session_index, assignation);
95
5188
        }
96

            
97
3596
        pub fn authority_id_mapping(
98
3596
            session_index: T::SessionIndex,
99
3596
        ) -> Option<BTreeMap<T::AuthorityId, T::AccountId>> {
100
3596
            AuthorityIdMapping::<T>::get(session_index)
101
3596
        }
102
    }
103
}