polkadot_runtime_parachains/
shared.rs1use alloc::{
23 collections::{btree_map::BTreeMap, btree_set::BTreeSet, vec_deque::VecDeque},
24 vec::Vec,
25};
26use frame_support::{pallet_prelude::*, traits::DisabledValidators};
27use frame_system::pallet_prelude::BlockNumberFor;
28use polkadot_primitives::{
29 transpose_claim_queue, vstaging::RelayParentInfo, CoreIndex, Id as ParaId, Id, SessionIndex,
30 ValidatorId, ValidatorIndex,
31};
32use sp_runtime::traits::AtLeast32BitUnsigned;
33
34use rand::{seq::SliceRandom, SeedableRng};
35use rand_chacha::ChaCha20Rng;
36
37use crate::configuration::HostConfiguration;
38
39pub use pallet::*;
40
41pub(crate) const SESSION_DELAY: SessionIndex = 2;
45
46#[cfg(test)]
47mod tests;
48
49pub mod migration;
50
51#[derive(Encode, Decode, Default, TypeInfo, Debug)]
53pub struct SchedulingParentInfo<Hash> {
54 pub scheduling_parent: Hash,
56 pub claim_queue: BTreeMap<Id, BTreeMap<u8, BTreeSet<CoreIndex>>>,
59}
60
61#[derive(Encode, Decode, Default, TypeInfo)]
63pub struct AllowedSchedulingParentsTracker<Hash, BlockNumber> {
64 buffer: VecDeque<SchedulingParentInfo<Hash>>,
69
70 latest_number: BlockNumber,
74}
75
76impl<Hash: PartialEq + Copy, BlockNumber: AtLeast32BitUnsigned + Copy>
77 AllowedSchedulingParentsTracker<Hash, BlockNumber>
78{
79 pub(crate) fn update(
84 &mut self,
85 scheduling_parent: Hash,
86 claim_queue: BTreeMap<CoreIndex, VecDeque<Id>>,
87 number: BlockNumber,
88 max_ancestry_len: u32,
89 ) {
90 if self.buffer.iter().any(|info| info.scheduling_parent == scheduling_parent) {
91 return;
93 }
94
95 let claim_queue = transpose_claim_queue(claim_queue);
96
97 self.buffer.push_back(SchedulingParentInfo { scheduling_parent, claim_queue });
98
99 self.latest_number = number;
100 while self.buffer.len() > (max_ancestry_len as usize) {
101 let _ = self.buffer.pop_front();
102 }
103
104 }
107
108 pub(crate) fn acquire_info(
111 &self,
112 scheduling_parent: Hash,
113 ) -> Option<(&SchedulingParentInfo<Hash>, BlockNumber)> {
114 let pos = self
115 .buffer
116 .iter()
117 .position(|info| info.scheduling_parent == scheduling_parent)?;
118 let age = (self.buffer.len() - 1) - pos;
119 let number = self.latest_number - BlockNumber::from(age as u32);
120
121 Some((&self.buffer[pos], number))
122 }
123}
124
125#[frame_support::pallet]
126pub mod pallet {
127 use super::*;
128
129 const STORAGE_VERSION: StorageVersion = StorageVersion::new(2);
130
131 #[pallet::pallet]
132 #[pallet::without_storage_info]
133 #[pallet::storage_version(STORAGE_VERSION)]
134 pub struct Pallet<T>(_);
135
136 #[pallet::config]
137 pub trait Config: frame_system::Config {
138 type DisabledValidators: frame_support::traits::DisabledValidators;
139 }
140
141 #[pallet::storage]
143 pub type CurrentSessionIndex<T: Config> = StorageValue<_, SessionIndex, ValueQuery>;
144
145 #[pallet::storage]
148 pub type ActiveValidatorIndices<T: Config> = StorageValue<_, Vec<ValidatorIndex>, ValueQuery>;
149
150 #[pallet::storage]
153 pub type ActiveValidatorKeys<T: Config> = StorageValue<_, Vec<ValidatorId>, ValueQuery>;
154
155 #[pallet::storage]
157 pub(crate) type AllowedSchedulingParents<T: Config> =
158 StorageValue<_, AllowedSchedulingParentsTracker<T::Hash, BlockNumberFor<T>>, ValueQuery>;
159
160 #[pallet::storage]
162 pub(crate) type AllowedRelayParents<T: Config> = StorageDoubleMap<
163 _,
164 Twox64Concat,
165 SessionIndex,
166 Blake2_128Concat,
167 T::Hash,
168 RelayParentInfo<T::Hash, BlockNumberFor<T>>,
169 >;
170
171 #[pallet::storage]
175 pub(crate) type OldestRelayParentSession<T: Config> = StorageValue<_, SessionIndex, ValueQuery>;
176
177 #[pallet::storage]
181 pub(crate) type MinimumRelayParentNumber<T: Config> =
182 StorageMap<_, Twox64Concat, SessionIndex, BlockNumberFor<T>>;
183
184 #[pallet::call]
185 impl<T: Config> Pallet<T> {}
186}
187
188impl<T: Config> Pallet<T> {
189 pub(crate) fn initializer_initialize(_now: BlockNumberFor<T>) -> Weight {
191 Weight::zero()
192 }
193
194 pub(crate) fn initializer_finalize() {}
196
197 pub(crate) fn initializer_on_new_session(
201 session_index: SessionIndex,
202 random_seed: [u8; 32],
203 new_config: &HostConfiguration<BlockNumberFor<T>>,
204 all_validators: Vec<ValidatorId>,
205 ) -> Vec<ValidatorId> {
206 AllowedSchedulingParents::<T>::mutate(|tracker| tracker.buffer.clear());
216
217 CurrentSessionIndex::<T>::set(session_index);
218 let mut rng: ChaCha20Rng = SeedableRng::from_seed(random_seed);
219
220 let mut shuffled_indices: Vec<_> = (0..all_validators.len())
221 .enumerate()
222 .map(|(i, _)| ValidatorIndex(i as _))
223 .collect();
224
225 shuffled_indices.shuffle(&mut rng);
226
227 if let Some(max) = new_config.max_validators {
228 shuffled_indices.truncate(max as usize);
229 }
230
231 let active_validator_keys =
232 crate::util::take_active_subset(&shuffled_indices, &all_validators);
233
234 ActiveValidatorIndices::<T>::set(shuffled_indices);
235 ActiveValidatorKeys::<T>::set(active_validator_keys.clone());
236
237 active_validator_keys
238 }
239
240 pub fn scheduled_session() -> SessionIndex {
242 CurrentSessionIndex::<T>::get().saturating_add(SESSION_DELAY)
243 }
244
245 pub fn disabled_validators() -> Vec<ValidatorIndex> {
248 let shuffled_indices = ActiveValidatorIndices::<T>::get();
249 let reverse_index = shuffled_indices
252 .iter()
253 .enumerate()
254 .map(|(i, v)| (v.0, ValidatorIndex(i as u32)))
255 .collect::<BTreeMap<u32, ValidatorIndex>>();
256
257 T::DisabledValidators::disabled_validators()
259 .iter()
260 .filter_map(|v| reverse_index.get(v).cloned())
261 .collect()
262 }
263
264 pub fn new_block(
269 hash: T::Hash,
270 cq: BTreeMap<CoreIndex, VecDeque<ParaId>>,
271 block_number: BlockNumberFor<T>,
272 max_ancestry_len: u32,
273 storage_root: T::Hash,
274 session_index: SessionIndex,
275 max_relay_parent_session_age: u32,
276 ) {
277 AllowedSchedulingParents::<T>::mutate(|tracker| {
279 tracker.update(hash, cq, block_number, max_ancestry_len);
280 });
281
282 AllowedRelayParents::<T>::insert(
284 session_index,
285 hash,
286 RelayParentInfo { number: block_number, state_root: storage_root },
287 );
288
289 if !MinimumRelayParentNumber::<T>::contains_key(session_index) {
293 MinimumRelayParentNumber::<T>::insert(session_index, block_number);
294 }
295
296 let oldest_allowed_session = session_index.saturating_sub(max_relay_parent_session_age);
298 let oldest_stored = OldestRelayParentSession::<T>::get();
299
300 if oldest_allowed_session > oldest_stored {
306 for expired in oldest_stored..oldest_allowed_session {
307 let _ = AllowedRelayParents::<T>::clear_prefix(expired, u32::MAX, None);
308 MinimumRelayParentNumber::<T>::remove(expired);
309 }
310 OldestRelayParentSession::<T>::set(oldest_allowed_session);
311 }
312 }
313
314 pub fn get_relay_parent_info(
316 session_index: SessionIndex,
317 relay_parent: T::Hash,
318 ) -> Option<RelayParentInfo<T::Hash, BlockNumberFor<T>>> {
319 AllowedRelayParents::<T>::get(session_index, relay_parent)
320 }
321
322 pub fn get_minimum_relay_parent_number() -> Option<BlockNumberFor<T>> {
325 let oldest_session = OldestRelayParentSession::<T>::get();
326 MinimumRelayParentNumber::<T>::get(oldest_session)
327 }
328
329 #[cfg(any(feature = "std", feature = "runtime-benchmarks", test))]
331 pub fn set_session_index(index: SessionIndex) {
332 CurrentSessionIndex::<T>::set(index);
333 }
334
335 #[cfg(any(feature = "std", feature = "runtime-benchmarks", test))]
336 pub fn set_active_validators_ascending(active: Vec<ValidatorId>) {
337 ActiveValidatorIndices::<T>::set(
338 (0..active.len()).map(|i| ValidatorIndex(i as _)).collect(),
339 );
340 ActiveValidatorKeys::<T>::set(active);
341 }
342
343 #[cfg(test)]
344 pub(crate) fn set_active_validators_with_indices(
345 indices: Vec<ValidatorIndex>,
346 keys: Vec<ValidatorId>,
347 ) {
348 assert_eq!(indices.len(), keys.len());
349 ActiveValidatorIndices::<T>::set(indices);
350 ActiveValidatorKeys::<T>::set(keys);
351 }
352
353 #[cfg(test)]
354 pub(crate) fn add_allowed_scheduling_parent(
355 scheduling_parent: T::Hash,
356 claim_queue: BTreeMap<CoreIndex, VecDeque<Id>>,
357 number: BlockNumberFor<T>,
358 max_ancestry_len: u32,
359 ) {
360 AllowedSchedulingParents::<T>::mutate(|tracker| {
361 tracker.update(scheduling_parent, claim_queue, number, max_ancestry_len + 1)
362 });
363
364 let session_index = CurrentSessionIndex::<T>::get();
367 AllowedRelayParents::<T>::insert(
368 session_index,
369 scheduling_parent,
370 RelayParentInfo { number, state_root: Default::default() },
371 );
372 }
373}