polkadot_runtime_parachains/
initializer.rs1use crate::{
24	configuration::{self, HostConfiguration},
25	disputes::{self, DisputesHandler as _, SlashingHandler as _},
26	dmp, hrmp, inclusion, paras, scheduler, session_info, shared,
27};
28use alloc::vec::Vec;
29use codec::{Decode, Encode};
30use frame_support::{
31	traits::{OneSessionHandler, Randomness},
32	weights::Weight,
33};
34use frame_system::limits::BlockWeights;
35use polkadot_primitives::{BlockNumber, ConsensusLog, SessionIndex, ValidatorId};
36use scale_info::TypeInfo;
37
38#[cfg(test)]
39mod tests;
40
41#[cfg(feature = "runtime-benchmarks")]
42mod benchmarking;
43
44pub use pallet::*;
45
46#[derive(Clone)]
48pub struct SessionChangeNotification<BlockNumber> {
49	pub validators: Vec<ValidatorId>,
51	pub queued: Vec<ValidatorId>,
53	pub prev_config: HostConfiguration<BlockNumber>,
55	pub new_config: HostConfiguration<BlockNumber>,
57	pub random_seed: [u8; 32],
59	pub session_index: SessionIndex,
61}
62
63pub trait OnNewSession<N> {
65	fn on_new_session(notification: &SessionChangeNotification<N>);
67}
68
69impl<N> OnNewSession<N> for () {
70	fn on_new_session(_: &SessionChangeNotification<N>) {}
71}
72
73pub type ValidatorSetCount = u32;
75
76impl<BlockNumber: Default + From<u32>> Default for SessionChangeNotification<BlockNumber> {
77	fn default() -> Self {
78		Self {
79			validators: Vec::new(),
80			queued: Vec::new(),
81			prev_config: HostConfiguration::default(),
82			new_config: HostConfiguration::default(),
83			random_seed: Default::default(),
84			session_index: Default::default(),
85		}
86	}
87}
88
89#[derive(Encode, Decode, TypeInfo)]
90pub(crate) struct BufferedSessionChange {
91	pub validators: Vec<ValidatorId>,
92	pub queued: Vec<ValidatorId>,
93	pub session_index: SessionIndex,
94}
95
96pub trait WeightInfo {
97	fn force_approve(d: u32) -> Weight;
98}
99
100impl WeightInfo for () {
101	fn force_approve(_: u32) -> Weight {
102		BlockWeights::default().max_block
103	}
104}
105
106#[frame_support::pallet]
107pub mod pallet {
108	use super::*;
109	use frame_support::pallet_prelude::*;
110	use frame_system::pallet_prelude::*;
111
112	#[pallet::pallet]
113	#[pallet::without_storage_info]
114	pub struct Pallet<T>(_);
115
116	#[pallet::config]
117	pub trait Config:
118		frame_system::Config
119		+ configuration::Config
120		+ shared::Config
121		+ paras::Config
122		+ scheduler::Config
123		+ inclusion::Config
124		+ session_info::Config
125		+ disputes::Config
126		+ dmp::Config
127		+ hrmp::Config
128	{
129		type Randomness: Randomness<Self::Hash, BlockNumberFor<Self>>;
131		type ForceOrigin: EnsureOrigin<<Self as frame_system::Config>::RuntimeOrigin>;
133		type CoretimeOnNewSession: OnNewSession<BlockNumberFor<Self>>;
137		type WeightInfo: WeightInfo;
139	}
140
141	#[pallet::storage]
150	pub(super) type HasInitialized<T: Config> = StorageValue<_, ()>;
151
152	#[pallet::storage]
160	pub(crate) type BufferedSessionChanges<T: Config> =
161		StorageValue<_, Vec<BufferedSessionChange>, ValueQuery>;
162
163	#[pallet::hooks]
164	impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {
165		fn on_initialize(now: BlockNumberFor<T>) -> Weight {
166			let total_weight = configuration::Pallet::<T>::initializer_initialize(now) +
177				shared::Pallet::<T>::initializer_initialize(now) +
178				paras::Pallet::<T>::initializer_initialize(now) +
179				scheduler::Pallet::<T>::initializer_initialize(now) +
180				inclusion::Pallet::<T>::initializer_initialize(now) +
181				session_info::Pallet::<T>::initializer_initialize(now) +
182				T::DisputesHandler::initializer_initialize(now) +
183				T::SlashingHandler::initializer_initialize(now) +
184				dmp::Pallet::<T>::initializer_initialize(now) +
185				hrmp::Pallet::<T>::initializer_initialize(now);
186
187			HasInitialized::<T>::set(Some(()));
188
189			total_weight
190		}
191
192		fn on_finalize(now: BlockNumberFor<T>) {
193			hrmp::Pallet::<T>::initializer_finalize();
195			dmp::Pallet::<T>::initializer_finalize();
196			T::SlashingHandler::initializer_finalize();
197			T::DisputesHandler::initializer_finalize();
198			session_info::Pallet::<T>::initializer_finalize();
199			inclusion::Pallet::<T>::initializer_finalize();
200			scheduler::Pallet::<T>::initializer_finalize();
201			paras::Pallet::<T>::initializer_finalize(now);
202			shared::Pallet::<T>::initializer_finalize();
203			configuration::Pallet::<T>::initializer_finalize();
204
205			if let Some(BufferedSessionChange { session_index, validators, queued }) =
211				BufferedSessionChanges::<T>::take().pop()
212			{
213				Self::apply_new_session(session_index, validators, queued);
214			}
215
216			HasInitialized::<T>::take();
217		}
218	}
219
220	#[pallet::call]
221	impl<T: Config> Pallet<T> {
222		#[pallet::call_index(0)]
226		#[pallet::weight((
227			<T as Config>::WeightInfo::force_approve(
228				frame_system::Pallet::<T>::digest().logs.len() as u32,
229			),
230			DispatchClass::Operational,
231		))]
232		pub fn force_approve(origin: OriginFor<T>, up_to: BlockNumber) -> DispatchResult {
233			T::ForceOrigin::ensure_origin(origin)?;
234
235			frame_system::Pallet::<T>::deposit_log(ConsensusLog::ForceApprove(up_to).into());
236			Ok(())
237		}
238	}
239}
240
241impl<T: Config> Pallet<T> {
242	fn apply_new_session(
243		session_index: SessionIndex,
244		all_validators: Vec<ValidatorId>,
245		queued: Vec<ValidatorId>,
246	) {
247		let random_seed = {
248			let mut buf = [0u8; 32];
249			let (random_hash, _) = T::Randomness::random(&b"paras"[..]);
252			let len = core::cmp::min(32, random_hash.as_ref().len());
253			buf[..len].copy_from_slice(&random_hash.as_ref()[..len]);
254			buf
255		};
256
257		let configuration::SessionChangeOutcome { prev_config, new_config } =
258			configuration::Pallet::<T>::initializer_on_new_session(&session_index);
259		let new_config = new_config.unwrap_or_else(|| prev_config.clone());
260
261		let validators = shared::Pallet::<T>::initializer_on_new_session(
262			session_index,
263			random_seed,
264			&new_config,
265			all_validators,
266		);
267
268		let notification = SessionChangeNotification {
269			validators,
270			queued,
271			prev_config,
272			new_config,
273			random_seed,
274			session_index,
275		};
276
277		let outgoing_paras = paras::Pallet::<T>::initializer_on_new_session(¬ification);
278		scheduler::Pallet::<T>::initializer_on_new_session(¬ification);
279		inclusion::Pallet::<T>::initializer_on_new_session(¬ification, &outgoing_paras);
280		session_info::Pallet::<T>::initializer_on_new_session(¬ification);
281		T::DisputesHandler::initializer_on_new_session(¬ification);
282		T::SlashingHandler::initializer_on_new_session(session_index);
283		dmp::Pallet::<T>::initializer_on_new_session(¬ification, &outgoing_paras);
284		hrmp::Pallet::<T>::initializer_on_new_session(¬ification, &outgoing_paras);
285		T::CoretimeOnNewSession::on_new_session(¬ification);
286	}
287
288	fn on_new_session<'a, I: 'a>(
291		_changed: bool,
292		session_index: SessionIndex,
293		validators: I,
294		queued: Option<I>,
295	) where
296		I: Iterator<Item = (&'a T::AccountId, ValidatorId)>,
297	{
298		let validators: Vec<_> = validators.map(|(_, v)| v).collect();
299		let queued: Vec<_> = if let Some(queued) = queued {
300			queued.map(|(_, v)| v).collect()
301		} else {
302			validators.clone()
303		};
304
305		if session_index == 0 {
306			Self::apply_new_session(0, validators, queued);
308		} else {
309			BufferedSessionChanges::<T>::mutate(|v| {
310				v.push(BufferedSessionChange { validators, queued, session_index })
311			});
312		}
313	}
314
315	#[cfg(any(test, feature = "runtime-benchmarks"))]
318	pub(crate) fn test_trigger_on_new_session<'a, I: 'a>(
319		changed: bool,
320		session_index: SessionIndex,
321		validators: I,
322		queued: Option<I>,
323	) where
324		I: Iterator<Item = (&'a T::AccountId, ValidatorId)>,
325	{
326		Self::on_new_session(changed, session_index, validators, queued)
327	}
328
329	pub(crate) fn upcoming_session_change() -> bool {
331		!BufferedSessionChanges::<T>::get().is_empty()
332	}
333}
334
335impl<T: Config> sp_runtime::BoundToRuntimeAppPublic for Pallet<T> {
336	type Public = ValidatorId;
337}
338
339impl<T: pallet_session::Config + Config> OneSessionHandler<T::AccountId> for Pallet<T> {
340	type Key = ValidatorId;
341
342	fn on_genesis_session<'a, I: 'a>(validators: I)
343	where
344		I: Iterator<Item = (&'a T::AccountId, Self::Key)>,
345	{
346		Pallet::<T>::on_new_session(false, 0, validators, None);
347	}
348
349	fn on_new_session<'a, I: 'a>(changed: bool, validators: I, queued: I)
350	where
351		I: Iterator<Item = (&'a T::AccountId, Self::Key)>,
352	{
353		let session_index = pallet_session::Pallet::<T>::current_index();
354		Pallet::<T>::on_new_session(changed, session_index, validators, Some(queued));
355	}
356
357	fn on_disabled(_i: u32) {}
358}