1
// Copyright (C) Parity Technologies (UK) Ltd.
2
// This file is part of Polkadot.
3

            
4
// Polkadot is free software: you can redistribute it and/or modify
5
// it under the terms of the GNU General Public License as published by
6
// the Free Software Foundation, either version 3 of the License, or
7
// (at your option) any later version.
8

            
9
// Polkadot is distributed in the hope that it will be useful,
10
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
// GNU General Public License for more details.
13

            
14
// You should have received a copy of the GNU General Public License
15
// along with Polkadot.  If not, see <http://www.gnu.org/licenses/>.
16

            
17
//! A pallet for any shared state that other pallets may want access to.
18
//!
19
//! To avoid cyclic dependencies, it is important that this pallet is not
20
//! dependent on any of the other pallets.
21

            
22
use alloc::{
23
	collections::{btree_map::BTreeMap, vec_deque::VecDeque},
24
	vec::Vec,
25
};
26
use frame_support::{pallet_prelude::*, traits::DisabledValidators};
27
use frame_system::pallet_prelude::BlockNumberFor;
28
use polkadot_primitives::{SessionIndex, ValidatorId, ValidatorIndex};
29
use sp_runtime::traits::AtLeast32BitUnsigned;
30

            
31
use rand::{seq::SliceRandom, SeedableRng};
32
use rand_chacha::ChaCha20Rng;
33

            
34
use crate::configuration::HostConfiguration;
35

            
36
pub use pallet::*;
37

            
38
// `SESSION_DELAY` is used to delay any changes to Paras registration or configurations.
39
// Wait until the session index is 2 larger then the current index to apply any changes,
40
// which guarantees that at least one full session has passed before any changes are applied.
41
pub(crate) const SESSION_DELAY: SessionIndex = 2;
42

            
43
#[cfg(test)]
44
mod tests;
45

            
46
/// Information about past relay-parents.
47
#[derive(Encode, Decode, Default, TypeInfo)]
48
pub struct AllowedRelayParentsTracker<Hash, BlockNumber> {
49
	// The past relay parents, paired with state roots, that are viable to build upon.
50
	//
51
	// They are in ascending chronologic order, so the newest relay parents are at
52
	// the back of the deque.
53
	//
54
	// (relay_parent, state_root)
55
	buffer: VecDeque<(Hash, Hash)>,
56

            
57
	// The number of the most recent relay-parent, if any.
58
	// If the buffer is empty, this value has no meaning and may
59
	// be nonsensical.
60
	latest_number: BlockNumber,
61
}
62

            
63
impl<Hash: PartialEq + Copy, BlockNumber: AtLeast32BitUnsigned + Copy>
64
	AllowedRelayParentsTracker<Hash, BlockNumber>
65
{
66
	/// Add a new relay-parent to the allowed relay parents, along with info about the header.
67
	/// Provide a maximum ancestry length for the buffer, which will cause old relay-parents to be
68
	/// pruned.
69
194763
	pub(crate) fn update(
70
194763
		&mut self,
71
194763
		relay_parent: Hash,
72
194763
		state_root: Hash,
73
194763
		number: BlockNumber,
74
194763
		max_ancestry_len: u32,
75
194763
	) {
76
194763
		// + 1 for the most recent block, which is always allowed.
77
194763
		let buffer_size_limit = max_ancestry_len as usize + 1;
78
194763

            
79
194763
		self.buffer.push_back((relay_parent, state_root));
80
194763
		self.latest_number = number;
81
194763
		while self.buffer.len() > buffer_size_limit {
82
			let _ = self.buffer.pop_front();
83
		}
84

            
85
		// We only allow relay parents within the same sessions, the buffer
86
		// gets cleared on session changes.
87
194763
	}
88

            
89
	/// Attempt to acquire the state root and block number to be used when building
90
	/// upon the given relay-parent.
91
	///
92
	/// This only succeeds if the relay-parent is one of the allowed relay-parents.
93
	/// If a previous relay-parent number is passed, then this only passes if the new relay-parent
94
	/// is more recent than the previous.
95
	pub(crate) fn acquire_info(
96
		&self,
97
		relay_parent: Hash,
98
		prev: Option<BlockNumber>,
99
	) -> Option<(Hash, BlockNumber)> {
100
		let pos = self.buffer.iter().position(|(rp, _)| rp == &relay_parent)?;
101
		let age = (self.buffer.len() - 1) - pos;
102
		let number = self.latest_number - BlockNumber::from(age as u32);
103

            
104
		if let Some(prev) = prev {
105
			if prev > number {
106
				return None
107
			}
108
		}
109

            
110
		Some((self.buffer[pos].1, number))
111
	}
112

            
113
	/// Returns block number of the earliest block the buffer would contain if
114
	/// `now` is pushed into it.
115
	pub(crate) fn hypothetical_earliest_block_number(
116
		&self,
117
		now: BlockNumber,
118
		max_ancestry_len: u32,
119
	) -> BlockNumber {
120
		let allowed_ancestry_len = max_ancestry_len.min(self.buffer.len() as u32);
121

            
122
		now - allowed_ancestry_len.into()
123
	}
124
}
125

            
126
22
#[frame_support::pallet]
127
pub mod pallet {
128
	use super::*;
129

            
130
554790
	#[pallet::pallet]
131
	#[pallet::without_storage_info]
132
	pub struct Pallet<T>(_);
133

            
134
	#[pallet::config]
135
	pub trait Config: frame_system::Config {
136
		type DisabledValidators: frame_support::traits::DisabledValidators;
137
	}
138

            
139
	/// The current session index.
140
659994
	#[pallet::storage]
141
	pub type CurrentSessionIndex<T: Config> = StorageValue<_, SessionIndex, ValueQuery>;
142

            
143
	/// All the validators actively participating in parachain consensus.
144
	/// Indices are into the broader validator set.
145
930462
	#[pallet::storage]
146
	pub type ActiveValidatorIndices<T: Config> = StorageValue<_, Vec<ValidatorIndex>, ValueQuery>;
147

            
148
	/// The parachain attestation keys of the validators actively participating in parachain
149
	/// consensus. This should be the same length as `ActiveValidatorIndices`.
150
661026
	#[pallet::storage]
151
	pub type ActiveValidatorKeys<T: Config> = StorageValue<_, Vec<ValidatorId>, ValueQuery>;
152

            
153
	/// All allowed relay-parents.
154
1709514
	#[pallet::storage]
155
	pub(crate) type AllowedRelayParents<T: Config> =
156
		StorageValue<_, AllowedRelayParentsTracker<T::Hash, BlockNumberFor<T>>, ValueQuery>;
157

            
158
	#[pallet::call]
159
	impl<T: Config> Pallet<T> {}
160
}
161

            
162
impl<T: Config> Pallet<T> {
163
	/// Called by the initializer to initialize the configuration pallet.
164
194763
	pub(crate) fn initializer_initialize(_now: BlockNumberFor<T>) -> Weight {
165
194763
		Weight::zero()
166
194763
	}
167

            
168
	/// Called by the initializer to finalize the configuration pallet.
169
194763
	pub(crate) fn initializer_finalize() {}
170

            
171
	/// Called by the initializer to note that a new session has started.
172
	///
173
	/// Returns the list of outgoing paras from the actions queue.
174
135234
	pub(crate) fn initializer_on_new_session(
175
135234
		session_index: SessionIndex,
176
135234
		random_seed: [u8; 32],
177
135234
		new_config: &HostConfiguration<BlockNumberFor<T>>,
178
135234
		all_validators: Vec<ValidatorId>,
179
135234
	) -> Vec<ValidatorId> {
180
135234
		// Drop allowed relay parents buffer on a session change.
181
135234
		//
182
135234
		// During the initialization of the next block we always add its parent
183
135234
		// to the tracker.
184
135234
		//
185
135234
		// With asynchronous backing candidates built on top of relay
186
135234
		// parent `R` are still restricted by the runtime to be backed
187
135234
		// by the group assigned at `number(R) + 1`, which is guaranteed
188
135234
		// to be in the current session.
189
180312
		AllowedRelayParents::<T>::mutate(|tracker| tracker.buffer.clear());
190
135234

            
191
135234
		CurrentSessionIndex::<T>::set(session_index);
192
135234
		let mut rng: ChaCha20Rng = SeedableRng::from_seed(random_seed);
193
135234

            
194
135234
		let mut shuffled_indices: Vec<_> = (0..all_validators.len())
195
135234
			.enumerate()
196
135234
			.map(|(i, _)| ValidatorIndex(i as _))
197
135234
			.collect();
198
135234

            
199
135234
		shuffled_indices.shuffle(&mut rng);
200

            
201
135234
		if let Some(max) = new_config.max_validators {
202
			shuffled_indices.truncate(max as usize);
203
135234
		}
204

            
205
135234
		let active_validator_keys =
206
135234
			crate::util::take_active_subset(&shuffled_indices, &all_validators);
207
135234

            
208
135234
		ActiveValidatorIndices::<T>::set(shuffled_indices);
209
135234
		ActiveValidatorKeys::<T>::set(active_validator_keys.clone());
210
135234

            
211
135234
		active_validator_keys
212
135234
	}
213

            
214
	/// Return the session index that should be used for any future scheduled changes.
215
	pub fn scheduled_session() -> SessionIndex {
216
		CurrentSessionIndex::<T>::get().saturating_add(SESSION_DELAY)
217
	}
218

            
219
	/// Fetches disabled validators list from session pallet.
220
	/// CAVEAT: this might produce incorrect results on session boundaries
221
194763
	pub fn disabled_validators() -> Vec<ValidatorIndex> {
222
194763
		let shuffled_indices = ActiveValidatorIndices::<T>::get();
223
194763
		// mapping from raw validator index to `ValidatorIndex`
224
194763
		// this computation is the same within a session, but should be cheap
225
194763
		let reverse_index = shuffled_indices
226
194763
			.iter()
227
194763
			.enumerate()
228
194763
			.map(|(i, v)| (v.0, ValidatorIndex(i as u32)))
229
194763
			.collect::<BTreeMap<u32, ValidatorIndex>>();
230
194763

            
231
194763
		// we might have disabled validators who are not parachain validators
232
194763
		T::DisabledValidators::disabled_validators()
233
194763
			.iter()
234
194763
			.filter_map(|v| reverse_index.get(v).cloned())
235
194763
			.collect()
236
194763
	}
237

            
238
	/// Test function for setting the current session index.
239
	#[cfg(any(feature = "std", feature = "runtime-benchmarks", test))]
240
	pub fn set_session_index(index: SessionIndex) {
241
		CurrentSessionIndex::<T>::set(index);
242
	}
243

            
244
	#[cfg(any(feature = "std", feature = "runtime-benchmarks", test))]
245
	pub fn set_active_validators_ascending(active: Vec<ValidatorId>) {
246
		ActiveValidatorIndices::<T>::set(
247
			(0..active.len()).map(|i| ValidatorIndex(i as _)).collect(),
248
		);
249
		ActiveValidatorKeys::<T>::set(active);
250
	}
251

            
252
	#[cfg(test)]
253
	pub(crate) fn set_active_validators_with_indices(
254
		indices: Vec<ValidatorIndex>,
255
		keys: Vec<ValidatorId>,
256
	) {
257
		assert_eq!(indices.len(), keys.len());
258
		ActiveValidatorIndices::<T>::set(indices);
259
		ActiveValidatorKeys::<T>::set(keys);
260
	}
261

            
262
	#[cfg(test)]
263
	pub(crate) fn add_allowed_relay_parent(
264
		relay_parent: T::Hash,
265
		state_root: T::Hash,
266
		number: BlockNumberFor<T>,
267
		max_ancestry_len: u32,
268
	) {
269
		AllowedRelayParents::<T>::mutate(|tracker| {
270
			tracker.update(relay_parent, state_root, number, max_ancestry_len)
271
		})
272
	}
273
}