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
extern crate alloc;
26

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

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

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

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

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

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

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

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

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

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

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

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