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}