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 let oldest_allowed_session =
219 session_index.saturating_sub(new_config.max_relay_parent_session_age);
220 let oldest_stored = OldestRelayParentSession::<T>::get();
221
222 if oldest_allowed_session > oldest_stored {
228 for expired in oldest_stored..oldest_allowed_session {
229 let _ = AllowedRelayParents::<T>::clear_prefix(expired, u32::MAX, None);
230 MinimumRelayParentNumber::<T>::remove(expired);
231 }
232 OldestRelayParentSession::<T>::set(oldest_allowed_session);
233 }
234
235 CurrentSessionIndex::<T>::set(session_index);
236 let mut rng: ChaCha20Rng = SeedableRng::from_seed(random_seed);
237
238 let mut shuffled_indices: Vec<_> = (0..all_validators.len())
239 .enumerate()
240 .map(|(i, _)| ValidatorIndex(i as _))
241 .collect();
242
243 shuffled_indices.shuffle(&mut rng);
244
245 if let Some(max) = new_config.max_validators {
246 shuffled_indices.truncate(max as usize);
247 }
248
249 let active_validator_keys =
250 crate::util::take_active_subset(&shuffled_indices, &all_validators);
251
252 ActiveValidatorIndices::<T>::set(shuffled_indices);
253 ActiveValidatorKeys::<T>::set(active_validator_keys.clone());
254
255 active_validator_keys
256 }
257
258 pub fn scheduled_session() -> SessionIndex {
260 CurrentSessionIndex::<T>::get().saturating_add(SESSION_DELAY)
261 }
262
263 pub fn disabled_validators() -> Vec<ValidatorIndex> {
266 let shuffled_indices = ActiveValidatorIndices::<T>::get();
267 let reverse_index = shuffled_indices
270 .iter()
271 .enumerate()
272 .map(|(i, v)| (v.0, ValidatorIndex(i as u32)))
273 .collect::<BTreeMap<u32, ValidatorIndex>>();
274
275 T::DisabledValidators::disabled_validators()
277 .iter()
278 .filter_map(|v| reverse_index.get(v).cloned())
279 .collect()
280 }
281
282 pub fn new_block(
286 hash: T::Hash,
287 cq: BTreeMap<CoreIndex, VecDeque<ParaId>>,
288 block_number: BlockNumberFor<T>,
289 max_ancestry_len: u32,
290 storage_root: T::Hash,
291 session_index: SessionIndex,
292 ) {
293 AllowedSchedulingParents::<T>::mutate(|tracker| {
295 tracker.update(hash, cq, block_number, max_ancestry_len);
296 });
297
298 AllowedRelayParents::<T>::insert(
300 session_index,
301 hash,
302 RelayParentInfo { number: block_number, state_root: storage_root },
303 );
304
305 if !MinimumRelayParentNumber::<T>::contains_key(session_index) {
309 MinimumRelayParentNumber::<T>::insert(session_index, block_number);
310 }
311 }
312
313 pub fn get_relay_parent_info(
315 session_index: SessionIndex,
316 relay_parent: T::Hash,
317 ) -> Option<RelayParentInfo<T::Hash, BlockNumberFor<T>>> {
318 AllowedRelayParents::<T>::get(session_index, relay_parent)
319 }
320
321 pub fn get_minimum_relay_parent_number() -> Option<BlockNumberFor<T>> {
324 let oldest_session = OldestRelayParentSession::<T>::get();
325 MinimumRelayParentNumber::<T>::get(oldest_session)
326 }
327
328 #[cfg(any(feature = "std", feature = "runtime-benchmarks", test))]
330 pub fn set_session_index(index: SessionIndex) {
331 CurrentSessionIndex::<T>::set(index);
332 }
333
334 #[cfg(any(feature = "std", feature = "runtime-benchmarks", test))]
335 pub fn set_active_validators_ascending(active: Vec<ValidatorId>) {
336 ActiveValidatorIndices::<T>::set(
337 (0..active.len()).map(|i| ValidatorIndex(i as _)).collect(),
338 );
339 ActiveValidatorKeys::<T>::set(active);
340 }
341
342 #[cfg(test)]
343 pub(crate) fn set_active_validators_with_indices(
344 indices: Vec<ValidatorIndex>,
345 keys: Vec<ValidatorId>,
346 ) {
347 assert_eq!(indices.len(), keys.len());
348 ActiveValidatorIndices::<T>::set(indices);
349 ActiveValidatorKeys::<T>::set(keys);
350 }
351
352 #[cfg(test)]
353 pub(crate) fn add_allowed_scheduling_parent(
354 scheduling_parent: T::Hash,
355 claim_queue: BTreeMap<CoreIndex, VecDeque<Id>>,
356 number: BlockNumberFor<T>,
357 max_ancestry_len: u32,
358 ) {
359 AllowedSchedulingParents::<T>::mutate(|tracker| {
360 tracker.update(scheduling_parent, claim_queue, number, max_ancestry_len + 1)
361 });
362
363 let session_index = CurrentSessionIndex::<T>::get();
366 AllowedRelayParents::<T>::insert(
367 session_index,
368 scheduling_parent,
369 RelayParentInfo { number, state_root: Default::default() },
370 );
371 }
372}