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 vstaging::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 let buffer_size_limit = max_ancestry_len as usize + 1;
101
102 self.buffer.push_back(RelayParentInfo { relay_parent, state_root, claim_queue });
103
104 self.latest_number = number;
105 while self.buffer.len() > buffer_size_limit {
106 let _ = self.buffer.pop_front();
107 }
108
109 }
112
113 pub(crate) fn acquire_info(
120 &self,
121 relay_parent: Hash,
122 prev: Option<BlockNumber>,
123 ) -> Option<(&RelayParentInfo<Hash>, BlockNumber)> {
124 let pos = self.buffer.iter().position(|info| info.relay_parent == relay_parent)?;
125 let age = (self.buffer.len() - 1) - pos;
126 let number = self.latest_number - BlockNumber::from(age as u32);
127
128 if let Some(prev) = prev {
129 if prev > number {
130 return None
131 }
132 }
133
134 Some((&self.buffer[pos], number))
135 }
136
137 pub(crate) fn hypothetical_earliest_block_number(
140 &self,
141 now: BlockNumber,
142 max_ancestry_len: u32,
143 ) -> BlockNumber {
144 let allowed_ancestry_len = max_ancestry_len.min(self.buffer.len() as u32);
145
146 now - allowed_ancestry_len.into()
147 }
148}
149
150#[frame_support::pallet]
151pub mod pallet {
152 use super::*;
153
154 const STORAGE_VERSION: StorageVersion = StorageVersion::new(1);
155
156 #[pallet::pallet]
157 #[pallet::without_storage_info]
158 #[pallet::storage_version(STORAGE_VERSION)]
159 pub struct Pallet<T>(_);
160
161 #[pallet::config]
162 pub trait Config: frame_system::Config {
163 type DisabledValidators: frame_support::traits::DisabledValidators;
164 }
165
166 #[pallet::storage]
168 pub type CurrentSessionIndex<T: Config> = StorageValue<_, SessionIndex, ValueQuery>;
169
170 #[pallet::storage]
173 pub type ActiveValidatorIndices<T: Config> = StorageValue<_, Vec<ValidatorIndex>, ValueQuery>;
174
175 #[pallet::storage]
178 pub type ActiveValidatorKeys<T: Config> = StorageValue<_, Vec<ValidatorId>, ValueQuery>;
179
180 #[pallet::storage]
182 pub(crate) type AllowedRelayParents<T: Config> =
183 StorageValue<_, AllowedRelayParentsTracker<T::Hash, BlockNumberFor<T>>, ValueQuery>;
184
185 #[pallet::call]
186 impl<T: Config> Pallet<T> {}
187}
188
189impl<T: Config> Pallet<T> {
190 pub(crate) fn initializer_initialize(_now: BlockNumberFor<T>) -> Weight {
192 Weight::zero()
193 }
194
195 pub(crate) fn initializer_finalize() {}
197
198 pub(crate) fn initializer_on_new_session(
202 session_index: SessionIndex,
203 random_seed: [u8; 32],
204 new_config: &HostConfiguration<BlockNumberFor<T>>,
205 all_validators: Vec<ValidatorId>,
206 ) -> Vec<ValidatorId> {
207 AllowedRelayParents::<T>::mutate(|tracker| tracker.buffer.clear());
217
218 CurrentSessionIndex::<T>::set(session_index);
219 let mut rng: ChaCha20Rng = SeedableRng::from_seed(random_seed);
220
221 let mut shuffled_indices: Vec<_> = (0..all_validators.len())
222 .enumerate()
223 .map(|(i, _)| ValidatorIndex(i as _))
224 .collect();
225
226 shuffled_indices.shuffle(&mut rng);
227
228 if let Some(max) = new_config.max_validators {
229 shuffled_indices.truncate(max as usize);
230 }
231
232 let active_validator_keys =
233 crate::util::take_active_subset(&shuffled_indices, &all_validators);
234
235 ActiveValidatorIndices::<T>::set(shuffled_indices);
236 ActiveValidatorKeys::<T>::set(active_validator_keys.clone());
237
238 active_validator_keys
239 }
240
241 pub fn scheduled_session() -> SessionIndex {
243 CurrentSessionIndex::<T>::get().saturating_add(SESSION_DELAY)
244 }
245
246 pub fn disabled_validators() -> Vec<ValidatorIndex> {
249 let shuffled_indices = ActiveValidatorIndices::<T>::get();
250 let reverse_index = shuffled_indices
253 .iter()
254 .enumerate()
255 .map(|(i, v)| (v.0, ValidatorIndex(i as u32)))
256 .collect::<BTreeMap<u32, ValidatorIndex>>();
257
258 T::DisabledValidators::disabled_validators()
260 .iter()
261 .filter_map(|v| reverse_index.get(v).cloned())
262 .collect()
263 }
264
265 #[cfg(any(feature = "std", feature = "runtime-benchmarks", test))]
267 pub fn set_session_index(index: SessionIndex) {
268 CurrentSessionIndex::<T>::set(index);
269 }
270
271 #[cfg(any(feature = "std", feature = "runtime-benchmarks", test))]
272 pub fn set_active_validators_ascending(active: Vec<ValidatorId>) {
273 ActiveValidatorIndices::<T>::set(
274 (0..active.len()).map(|i| ValidatorIndex(i as _)).collect(),
275 );
276 ActiveValidatorKeys::<T>::set(active);
277 }
278
279 #[cfg(test)]
280 pub(crate) fn set_active_validators_with_indices(
281 indices: Vec<ValidatorIndex>,
282 keys: Vec<ValidatorId>,
283 ) {
284 assert_eq!(indices.len(), keys.len());
285 ActiveValidatorIndices::<T>::set(indices);
286 ActiveValidatorKeys::<T>::set(keys);
287 }
288
289 #[cfg(test)]
290 pub(crate) fn add_allowed_relay_parent(
291 relay_parent: T::Hash,
292 state_root: T::Hash,
293 claim_queue: BTreeMap<CoreIndex, VecDeque<Id>>,
294 number: BlockNumberFor<T>,
295 max_ancestry_len: u32,
296 ) {
297 AllowedRelayParents::<T>::mutate(|tracker| {
298 tracker.update(relay_parent, state_root, claim_queue, number, max_ancestry_len)
299 })
300 }
301}