referrerpolicy=no-referrer-when-downgrade

polkadot_runtime_parachains/
session_info.rs

1// Copyright (C) Parity Technologies (UK) Ltd.
2// This file is part of Polkadot.
3
4// Polkadot 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// Polkadot 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 Polkadot.  If not, see <http://www.gnu.org/licenses/>.
16
17//! The session info pallet provides information about validator sets
18//! from prior sessions needed for approvals and disputes.
19//!
20//! See the documentation on [session info][session-info-page] in the implementers' guide.
21//!
22//! [session-info-page]: https://paritytech.github.io/polkadot-sdk/book/runtime/session_info.html
23use crate::{
24	configuration, paras, scheduler, shared,
25	util::{take_active_subset, take_active_subset_and_inactive},
26};
27use alloc::vec::Vec;
28use frame_support::{
29	pallet_prelude::*,
30	traits::{OneSessionHandler, ValidatorSet, ValidatorSetWithIdentification},
31};
32use frame_system::pallet_prelude::BlockNumberFor;
33use polkadot_primitives::{
34	AssignmentId, AuthorityDiscoveryId, ExecutorParams, SessionIndex, SessionInfo,
35};
36
37pub use pallet::*;
38
39pub mod migration;
40
41#[cfg(test)]
42mod tests;
43
44/// A type for representing the validator account id in a session.
45pub type AccountId<T> = <<T as Config>::ValidatorSet as ValidatorSet<
46	<T as frame_system::Config>::AccountId,
47>>::ValidatorId;
48
49/// A tuple of `(AccountId, Identification)` where `Identification`
50/// is the full identification of `AccountId`.
51pub type IdentificationTuple<T> = (
52	AccountId<T>,
53	<<T as Config>::ValidatorSet as ValidatorSetWithIdentification<
54		<T as frame_system::Config>::AccountId,
55	>>::Identification,
56);
57
58#[frame_support::pallet]
59pub mod pallet {
60	use super::*;
61
62	#[pallet::pallet]
63	#[pallet::storage_version(migration::STORAGE_VERSION)]
64	#[pallet::without_storage_info]
65	pub struct Pallet<T>(_);
66
67	#[pallet::config]
68	pub trait Config:
69		frame_system::Config
70		+ configuration::Config
71		+ shared::Config
72		+ paras::Config
73		+ scheduler::Config
74		+ AuthorityDiscoveryConfig
75	{
76		/// A type for retrieving `AccountId`s of the validators in the current session.
77		/// These are stash keys of the validators.
78		/// It's used for rewards and slashing. `Identification` is only needed for slashing.
79		type ValidatorSet: ValidatorSetWithIdentification<Self::AccountId>;
80	}
81
82	/// Assignment keys for the current session.
83	/// Note that this API is private due to it being prone to 'off-by-one' at session boundaries.
84	/// When in doubt, use `Sessions` API instead.
85	#[pallet::storage]
86	pub(super) type AssignmentKeysUnsafe<T: Config> =
87		StorageValue<_, Vec<AssignmentId>, ValueQuery>;
88
89	/// The earliest session for which previous session info is stored.
90	#[pallet::storage]
91	pub type EarliestStoredSession<T: Config> = StorageValue<_, SessionIndex, ValueQuery>;
92
93	/// Session information in a rolling window.
94	/// Should have an entry in range `EarliestStoredSession..=CurrentSessionIndex`.
95	/// Does not have any entries before the session index in the first session change notification.
96	#[pallet::storage]
97	pub type Sessions<T: Config> = StorageMap<_, Identity, SessionIndex, SessionInfo>;
98
99	/// The validator account keys of the validators actively participating in parachain consensus.
100	// We do not store this in `SessionInfo` to avoid leaking the `AccountId` type to the client,
101	// which would complicate the migration process if we are to change it in the future.
102	#[pallet::storage]
103	pub type AccountKeys<T: Config> = StorageMap<_, Identity, SessionIndex, Vec<AccountId<T>>>;
104
105	/// Executor parameter set for a given session index
106	#[pallet::storage]
107	pub type SessionExecutorParams<T: Config> =
108		StorageMap<_, Identity, SessionIndex, ExecutorParams>;
109}
110
111/// An abstraction for the authority discovery pallet
112/// to help with mock testing.
113pub trait AuthorityDiscoveryConfig {
114	/// Retrieve authority identifiers of the current authority set in canonical ordering.
115	fn authorities() -> Vec<AuthorityDiscoveryId>;
116}
117
118impl<T: pallet_authority_discovery::Config> AuthorityDiscoveryConfig for T {
119	fn authorities() -> Vec<AuthorityDiscoveryId> {
120		pallet_authority_discovery::Pallet::<T>::current_authorities().to_vec()
121	}
122}
123
124impl<T: Config> Pallet<T> {
125	/// Handle an incoming session change.
126	pub(crate) fn initializer_on_new_session(
127		notification: &crate::initializer::SessionChangeNotification<BlockNumberFor<T>>,
128	) {
129		let config = configuration::ActiveConfig::<T>::get();
130
131		let dispute_period = config.dispute_period;
132
133		let validators = notification.validators.clone().into();
134		let discovery_keys = <T as AuthorityDiscoveryConfig>::authorities();
135		let assignment_keys = AssignmentKeysUnsafe::<T>::get();
136		let active_set = shared::ActiveValidatorIndices::<T>::get();
137
138		let validator_groups = scheduler::ValidatorGroups::<T>::get();
139		let n_cores = validator_groups.len() as u32;
140		let zeroth_delay_tranche_width = config.zeroth_delay_tranche_width;
141		let relay_vrf_modulo_samples = config.relay_vrf_modulo_samples;
142		let n_delay_tranches = config.n_delay_tranches;
143		let no_show_slots = config.no_show_slots;
144		let needed_approvals = config.needed_approvals;
145
146		let new_session_index = notification.session_index;
147		let random_seed = notification.random_seed;
148		let old_earliest_stored_session = EarliestStoredSession::<T>::get();
149		let new_earliest_stored_session = new_session_index.saturating_sub(dispute_period);
150		let new_earliest_stored_session =
151			core::cmp::max(new_earliest_stored_session, old_earliest_stored_session);
152		// remove all entries from `Sessions` from the previous value up to the new value
153		// avoid a potentially heavy loop when introduced on a live chain
154		if old_earliest_stored_session != 0 || Sessions::<T>::get(0).is_some() {
155			for idx in old_earliest_stored_session..new_earliest_stored_session {
156				Sessions::<T>::remove(&idx);
157				// Idx will be missing for a few sessions after the runtime upgrade.
158				// But it shouldn't be a problem.
159				AccountKeys::<T>::remove(&idx);
160				SessionExecutorParams::<T>::remove(&idx);
161			}
162			// update `EarliestStoredSession` based on `config.dispute_period`
163			EarliestStoredSession::<T>::set(new_earliest_stored_session);
164		} else {
165			// just introduced on a live chain
166			EarliestStoredSession::<T>::set(new_session_index);
167		}
168
169		// The validator set is guaranteed to be of the current session
170		// because we delay `on_new_session` till the end of the block.
171		let account_ids = T::ValidatorSet::validators();
172		let active_account_ids = take_active_subset(&active_set, &account_ids);
173		AccountKeys::<T>::insert(&new_session_index, &active_account_ids);
174
175		// create a new entry in `Sessions` with information about the current session
176		let new_session_info = SessionInfo {
177			validators, // these are from the notification and are thus already correct.
178			discovery_keys: take_active_subset_and_inactive(&active_set, &discovery_keys),
179			assignment_keys: take_active_subset(&active_set, &assignment_keys),
180			validator_groups: validator_groups.into(),
181			n_cores,
182			zeroth_delay_tranche_width,
183			relay_vrf_modulo_samples,
184			n_delay_tranches,
185			no_show_slots,
186			needed_approvals,
187			active_validator_indices: active_set,
188			random_seed,
189			dispute_period,
190		};
191		Sessions::<T>::insert(&new_session_index, &new_session_info);
192
193		SessionExecutorParams::<T>::insert(&new_session_index, config.executor_params);
194	}
195
196	/// Called by the initializer to initialize the session info pallet.
197	pub(crate) fn initializer_initialize(_now: BlockNumberFor<T>) -> Weight {
198		Weight::zero()
199	}
200
201	/// Called by the initializer to finalize the session info pallet.
202	pub(crate) fn initializer_finalize() {}
203}
204
205impl<T: Config> sp_runtime::BoundToRuntimeAppPublic for Pallet<T> {
206	type Public = AssignmentId;
207}
208
209impl<T: pallet_session::Config + Config> OneSessionHandler<T::AccountId> for Pallet<T> {
210	type Key = AssignmentId;
211
212	fn on_genesis_session<'a, I: 'a>(_validators: I)
213	where
214		I: Iterator<Item = (&'a T::AccountId, Self::Key)>,
215	{
216	}
217
218	fn on_new_session<'a, I: 'a>(_changed: bool, validators: I, _queued: I)
219	where
220		I: Iterator<Item = (&'a T::AccountId, Self::Key)>,
221	{
222		let assignment_keys: Vec<_> = validators.map(|(_, v)| v).collect();
223		AssignmentKeysUnsafe::<T>::set(assignment_keys);
224	}
225
226	fn on_disabled(_i: u32) {}
227}