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, CoreIndex, Id, SessionIndex, ValidatorId, ValidatorIndex,
30};
31use sp_runtime::traits::AtLeast32BitUnsigned;
32
33use rand::{seq::SliceRandom, SeedableRng};
34use rand_chacha::ChaCha20Rng;
35
36use crate::configuration::HostConfiguration;
37
38pub use pallet::*;
39
40pub(crate) const SESSION_DELAY: SessionIndex = 2;
44
45#[cfg(test)]
46mod tests;
47
48pub mod migration;
49
50#[derive(Encode, Decode, Default, TypeInfo, Debug)]
52pub struct RelayParentInfo<Hash> {
53 pub relay_parent: Hash,
55 pub state_root: Hash,
57 pub claim_queue: BTreeMap<Id, BTreeMap<u8, BTreeSet<CoreIndex>>>,
60}
61
62#[derive(Encode, Decode, Default, TypeInfo)]
64pub struct AllowedRelayParentsTracker<Hash, BlockNumber> {
65 buffer: VecDeque<RelayParentInfo<Hash>>,
70
71 latest_number: BlockNumber,
75}
76
77impl<Hash: PartialEq + Copy, BlockNumber: AtLeast32BitUnsigned + Copy>
78 AllowedRelayParentsTracker<Hash, BlockNumber>
79{
80 pub(crate) fn update(
85 &mut self,
86 relay_parent: Hash,
87 state_root: Hash,
88 claim_queue: BTreeMap<CoreIndex, VecDeque<Id>>,
89 number: BlockNumber,
90 max_ancestry_len: u32,
91 ) {
92 if self.buffer.iter().any(|info| info.relay_parent == relay_parent) {
93 return
95 }
96
97 let claim_queue = transpose_claim_queue(claim_queue);
98
99 self.buffer.push_back(RelayParentInfo { relay_parent, state_root, claim_queue });
100
101 self.latest_number = number;
102 while self.buffer.len() > (max_ancestry_len as usize) {
103 let _ = self.buffer.pop_front();
104 }
105
106 }
109
110 pub(crate) fn acquire_info(
117 &self,
118 relay_parent: Hash,
119 prev: Option<BlockNumber>,
120 ) -> Option<(&RelayParentInfo<Hash>, BlockNumber)> {
121 let pos = self.buffer.iter().position(|info| info.relay_parent == relay_parent)?;
122 let age = (self.buffer.len() - 1) - pos;
123 let number = self.latest_number - BlockNumber::from(age as u32);
124
125 if let Some(prev) = prev {
126 if prev > number {
127 return None
128 }
129 }
130
131 Some((&self.buffer[pos], number))
132 }
133
134 pub(crate) fn hypothetical_earliest_block_number(
137 &self,
138 now: BlockNumber,
139 max_ancestry_len: u32,
140 ) -> BlockNumber {
141 let allowed_ancestry_len = max_ancestry_len.min(self.buffer.len() as u32);
142
143 now - allowed_ancestry_len.into()
144 }
145}
146
147#[frame_support::pallet]
148pub mod pallet {
149 use super::*;
150
151 const STORAGE_VERSION: StorageVersion = StorageVersion::new(1);
152
153 #[pallet::pallet]
154 #[pallet::without_storage_info]
155 #[pallet::storage_version(STORAGE_VERSION)]
156 pub struct Pallet<T>(_);
157
158 #[pallet::config]
159 pub trait Config: frame_system::Config {
160 type DisabledValidators: frame_support::traits::DisabledValidators;
161 }
162
163 #[pallet::storage]
165 pub type CurrentSessionIndex<T: Config> = StorageValue<_, SessionIndex, ValueQuery>;
166
167 #[pallet::storage]
170 pub type ActiveValidatorIndices<T: Config> = StorageValue<_, Vec<ValidatorIndex>, ValueQuery>;
171
172 #[pallet::storage]
175 pub type ActiveValidatorKeys<T: Config> = StorageValue<_, Vec<ValidatorId>, ValueQuery>;
176
177 #[pallet::storage]
179 pub(crate) type AllowedRelayParents<T: Config> =
180 StorageValue<_, AllowedRelayParentsTracker<T::Hash, BlockNumberFor<T>>, ValueQuery>;
181
182 #[pallet::call]
183 impl<T: Config> Pallet<T> {}
184}
185
186impl<T: Config> Pallet<T> {
187 pub(crate) fn initializer_initialize(_now: BlockNumberFor<T>) -> Weight {
189 Weight::zero()
190 }
191
192 pub(crate) fn initializer_finalize() {}
194
195 pub(crate) fn initializer_on_new_session(
199 session_index: SessionIndex,
200 random_seed: [u8; 32],
201 new_config: &HostConfiguration<BlockNumberFor<T>>,
202 all_validators: Vec<ValidatorId>,
203 ) -> Vec<ValidatorId> {
204 AllowedRelayParents::<T>::mutate(|tracker| tracker.buffer.clear());
214
215 CurrentSessionIndex::<T>::set(session_index);
216 let mut rng: ChaCha20Rng = SeedableRng::from_seed(random_seed);
217
218 let mut shuffled_indices: Vec<_> = (0..all_validators.len())
219 .enumerate()
220 .map(|(i, _)| ValidatorIndex(i as _))
221 .collect();
222
223 shuffled_indices.shuffle(&mut rng);
224
225 if let Some(max) = new_config.max_validators {
226 shuffled_indices.truncate(max as usize);
227 }
228
229 let active_validator_keys =
230 crate::util::take_active_subset(&shuffled_indices, &all_validators);
231
232 ActiveValidatorIndices::<T>::set(shuffled_indices);
233 ActiveValidatorKeys::<T>::set(active_validator_keys.clone());
234
235 active_validator_keys
236 }
237
238 pub fn scheduled_session() -> SessionIndex {
240 CurrentSessionIndex::<T>::get().saturating_add(SESSION_DELAY)
241 }
242
243 pub fn disabled_validators() -> Vec<ValidatorIndex> {
246 let shuffled_indices = ActiveValidatorIndices::<T>::get();
247 let reverse_index = shuffled_indices
250 .iter()
251 .enumerate()
252 .map(|(i, v)| (v.0, ValidatorIndex(i as u32)))
253 .collect::<BTreeMap<u32, ValidatorIndex>>();
254
255 T::DisabledValidators::disabled_validators()
257 .iter()
258 .filter_map(|v| reverse_index.get(v).cloned())
259 .collect()
260 }
261
262 #[cfg(any(feature = "std", feature = "runtime-benchmarks", test))]
264 pub fn set_session_index(index: SessionIndex) {
265 CurrentSessionIndex::<T>::set(index);
266 }
267
268 #[cfg(any(feature = "std", feature = "runtime-benchmarks", test))]
269 pub fn set_active_validators_ascending(active: Vec<ValidatorId>) {
270 ActiveValidatorIndices::<T>::set(
271 (0..active.len()).map(|i| ValidatorIndex(i as _)).collect(),
272 );
273 ActiveValidatorKeys::<T>::set(active);
274 }
275
276 #[cfg(test)]
277 pub(crate) fn set_active_validators_with_indices(
278 indices: Vec<ValidatorIndex>,
279 keys: Vec<ValidatorId>,
280 ) {
281 assert_eq!(indices.len(), keys.len());
282 ActiveValidatorIndices::<T>::set(indices);
283 ActiveValidatorKeys::<T>::set(keys);
284 }
285
286 #[cfg(test)]
287 pub(crate) fn add_allowed_relay_parent(
288 relay_parent: T::Hash,
289 state_root: T::Hash,
290 claim_queue: BTreeMap<CoreIndex, VecDeque<Id>>,
291 number: BlockNumberFor<T>,
292 max_ancestry_len: u32,
293 ) {
294 AllowedRelayParents::<T>::mutate(|tracker| {
295 tracker.update(relay_parent, state_root, claim_queue, number, max_ancestry_len + 1)
296 })
297 }
298}