polkadot_runtime_parachains/paras/
mod.rs

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//! The paras pallet acts as the main registry of paras.
18//!
19//! # Tracking State of Paras
20//!
21//! The most important responsibility of this module is to track which parachains
22//! are active and what their current state is. The current state of a para consists of the current
23//! head data and the current validation code (AKA Parachain Validation Function (PVF)).
24//!
25//! A para is not considered live until it is registered and activated in this pallet.
26//!
27//! The set of parachains cannot change except at session boundaries. This is primarily to ensure
28//! that the number and meaning of bits required for the availability bitfields does not change
29//! except at session boundaries.
30//!
31//! # Validation Code Upgrades
32//!
33//! When a para signals the validation code upgrade it will be processed by this module. This can
34//! be in turn split into more fine grained items:
35//!
36//! - Part of the acceptance criteria checks if the para can indeed signal an upgrade,
37//!
38//! - When the candidate is enacted, this module schedules code upgrade, storing the prospective
39//!   validation code.
40//!
41//! - Actually assign the prospective validation code to be the current one after all conditions are
42//!   fulfilled.
43//!
44//! The conditions that must be met before the para can use the new validation code are:
45//!
46//! 1. The validation code should have been "soaked" in the storage for a given number of blocks.
47//! That    is, the validation code should have been stored in on-chain storage for some time, so
48//! that in    case of a revert with a non-extreme height difference, that validation code can still
49//! be    found on-chain.
50//!
51//! 2. The validation code was vetted by the validators and declared as non-malicious in a processes
52//!    known as PVF pre-checking.
53//!
54//! # Validation Code Management
55//!
56//! Potentially, one validation code can be used by several different paras. For example, during
57//! initial stages of deployment several paras can use the same "shell" validation code, or
58//! there can be shards of the same para that use the same validation code.
59//!
60//! In case a validation code ceases to have any users it must be pruned from the on-chain storage.
61//!
62//! # Para Lifecycle Management
63//!
64//! A para can be in one of the two stable states: it is either a lease holding parachain or an
65//! on-demand parachain.
66//!
67//! However, in order to get into one of those two states, it must first be onboarded. Onboarding
68//! can be only enacted at session boundaries. Onboarding must take at least one full session.
69//! Moreover, a brand new validation code should go through the PVF pre-checking process.
70//!
71//! Once the para is in one of the two stable states, it can switch to the other stable state or to
72//! initiate offboarding process. The result of offboarding is removal of all data related to that
73//! para.
74//!
75//! # PVF Pre-checking
76//!
77//! As was mentioned above, a brand new validation code should go through a process of approval. As
78//! part of this process, validators from the active set will take the validation code and check if
79//! it is malicious. Once they did that and have their judgement, either accept or reject, they
80//! issue a statement in a form of an unsigned extrinsic. This extrinsic is processed by this
81//! pallet. Once supermajority is gained for accept, then the process that initiated the check is
82//! resumed (as mentioned before this can be either upgrading of validation code or onboarding). If
83//! getting a supermajority becomes impossible (>1/3 of validators have already voted against), then
84//! we reject.
85//!
86//! Below is a state diagram that depicts states of a single PVF pre-checking vote.
87//!
88//! ```text
89//!                                            ┌──────────┐
90//!                        supermajority       │          │
91//!                    ┌────────for───────────▶│ accepted │
92//!        vote────┐   │                       │          │
93//!         │      │   │                       └──────────┘
94//!         │      │   │
95//!         │  ┌───────┐
96//!         │  │       │
97//!         └─▶│ init  │──── >1/3 against      ┌──────────┐
98//!            │       │           │           │          │
99//!            └───────┘           └──────────▶│ rejected │
100//!             ▲  │                           │          │
101//!             │  │ session                   └──────────┘
102//!             │  └──change
103//!             │     │
104//!             │     ▼
105//!             ┌─────┐
106//! start──────▶│reset│
107//!             └─────┘
108//! ```
109
110use crate::{
111	configuration,
112	inclusion::{QueueFootprinter, UmpQueueId},
113	initializer::SessionChangeNotification,
114	shared,
115};
116use alloc::{collections::btree_set::BTreeSet, vec::Vec};
117use bitvec::{order::Lsb0 as BitOrderLsb0, vec::BitVec};
118use codec::{Decode, Encode};
119use core::{cmp, mem};
120use frame_support::{pallet_prelude::*, traits::EstimateNextSessionRotation, DefaultNoBound};
121use frame_system::pallet_prelude::*;
122use polkadot_primitives::{
123	ConsensusLog, HeadData, Id as ParaId, PvfCheckStatement, SessionIndex, UpgradeGoAhead,
124	UpgradeRestriction, ValidationCode, ValidationCodeHash, ValidatorSignature, MIN_CODE_SIZE,
125};
126use scale_info::{Type, TypeInfo};
127use sp_core::RuntimeDebug;
128use sp_runtime::{
129	traits::{AppVerify, One, Saturating},
130	DispatchResult, SaturatedConversion,
131};
132
133use serde::{Deserialize, Serialize};
134
135pub use crate::Origin as ParachainOrigin;
136
137#[cfg(feature = "runtime-benchmarks")]
138pub mod benchmarking;
139
140#[cfg(test)]
141pub(crate) mod tests;
142
143pub use pallet::*;
144
145const LOG_TARGET: &str = "runtime::paras";
146
147// the two key times necessary to track for every code replacement.
148#[derive(Default, Encode, Decode, TypeInfo)]
149#[cfg_attr(test, derive(Debug, Clone, PartialEq))]
150pub struct ReplacementTimes<N> {
151	/// The relay-chain block number that the code upgrade was expected to be activated.
152	/// This is when the code change occurs from the para's perspective - after the
153	/// first parablock included with a relay-parent with number >= this value.
154	expected_at: N,
155	/// The relay-chain block number at which the parablock activating the code upgrade was
156	/// actually included. This means considered included and available, so this is the time at
157	/// which that parablock enters the acceptance period in this fork of the relay-chain.
158	activated_at: N,
159}
160
161/// Metadata used to track previous parachain validation code that we keep in
162/// the state.
163#[derive(Default, Encode, Decode, TypeInfo)]
164#[cfg_attr(test, derive(Debug, Clone, PartialEq))]
165pub struct ParaPastCodeMeta<N> {
166	/// Block numbers where the code was expected to be replaced and where the code
167	/// was actually replaced, respectively. The first is used to do accurate look-ups
168	/// of historic code in historic contexts, whereas the second is used to do
169	/// pruning on an accurate timeframe. These can be used as indices
170	/// into the `PastCodeHash` map along with the `ParaId` to fetch the code itself.
171	upgrade_times: Vec<ReplacementTimes<N>>,
172	/// Tracks the highest pruned code-replacement, if any. This is the `activated_at` value,
173	/// not the `expected_at` value.
174	last_pruned: Option<N>,
175}
176
177/// The possible states of a para, to take into account delayed lifecycle changes.
178///
179/// If the para is in a "transition state", it is expected that the parachain is
180/// queued in the `ActionsQueue` to transition it into a stable state. Its lifecycle
181/// state will be used to determine the state transition to apply to the para.
182#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, TypeInfo)]
183pub enum ParaLifecycle {
184	/// Para is new and is onboarding as an on-demand or lease holding Parachain.
185	Onboarding,
186	/// Para is a Parathread (on-demand parachain).
187	Parathread,
188	/// Para is a lease holding Parachain.
189	Parachain,
190	/// Para is a Parathread (on-demand parachain) which is upgrading to a lease holding Parachain.
191	UpgradingParathread,
192	/// Para is a lease holding Parachain which is downgrading to an on-demand parachain.
193	DowngradingParachain,
194	/// Parathread (on-demand parachain) is queued to be offboarded.
195	OffboardingParathread,
196	/// Parachain is queued to be offboarded.
197	OffboardingParachain,
198}
199
200impl ParaLifecycle {
201	/// Returns true if parachain is currently onboarding. To learn if the
202	/// parachain is onboarding as a lease holding or on-demand parachain, look at the
203	/// `UpcomingGenesis` storage item.
204	pub fn is_onboarding(&self) -> bool {
205		matches!(self, ParaLifecycle::Onboarding)
206	}
207
208	/// Returns true if para is in a stable state, i.e. it is currently
209	/// a lease holding or on-demand parachain, and not in any transition state.
210	pub fn is_stable(&self) -> bool {
211		matches!(self, ParaLifecycle::Parathread | ParaLifecycle::Parachain)
212	}
213
214	/// Returns true if para is currently treated as a parachain.
215	/// This also includes transitioning states, so you may want to combine
216	/// this check with `is_stable` if you specifically want `Paralifecycle::Parachain`.
217	pub fn is_parachain(&self) -> bool {
218		matches!(
219			self,
220			ParaLifecycle::Parachain |
221				ParaLifecycle::DowngradingParachain |
222				ParaLifecycle::OffboardingParachain
223		)
224	}
225
226	/// Returns true if para is currently treated as a parathread (on-demand parachain).
227	/// This also includes transitioning states, so you may want to combine
228	/// this check with `is_stable` if you specifically want `Paralifecycle::Parathread`.
229	pub fn is_parathread(&self) -> bool {
230		matches!(
231			self,
232			ParaLifecycle::Parathread |
233				ParaLifecycle::UpgradingParathread |
234				ParaLifecycle::OffboardingParathread
235		)
236	}
237
238	/// Returns true if para is currently offboarding.
239	pub fn is_offboarding(&self) -> bool {
240		matches!(self, ParaLifecycle::OffboardingParathread | ParaLifecycle::OffboardingParachain)
241	}
242
243	/// Returns true if para is in any transitionary state.
244	pub fn is_transitioning(&self) -> bool {
245		!Self::is_stable(self)
246	}
247}
248
249impl<N: Ord + Copy + PartialEq> ParaPastCodeMeta<N> {
250	// note a replacement has occurred at a given block number.
251	pub(crate) fn note_replacement(&mut self, expected_at: N, activated_at: N) {
252		self.upgrade_times.push(ReplacementTimes { expected_at, activated_at })
253	}
254
255	/// Returns `true` if the upgrade logs list is empty.
256	fn is_empty(&self) -> bool {
257		self.upgrade_times.is_empty()
258	}
259
260	// The block at which the most recently tracked code change occurred, from the perspective
261	// of the para.
262	#[cfg(test)]
263	fn most_recent_change(&self) -> Option<N> {
264		self.upgrade_times.last().map(|x| x.expected_at)
265	}
266
267	// prunes all code upgrade logs occurring at or before `max`.
268	// note that code replaced at `x` is the code used to validate all blocks before
269	// `x`. Thus, `max` should be outside of the slashing window when this is invoked.
270	//
271	// Since we don't want to prune anything inside the acceptance period, and the parablock only
272	// enters the acceptance period after being included, we prune based on the activation height of
273	// the code change, not the expected height of the code change.
274	//
275	// returns an iterator of block numbers at which code was replaced, where the replaced
276	// code should be now pruned, in ascending order.
277	fn prune_up_to(&'_ mut self, max: N) -> impl Iterator<Item = N> + '_ {
278		let to_prune = self.upgrade_times.iter().take_while(|t| t.activated_at <= max).count();
279		let drained = if to_prune == 0 {
280			// no-op prune.
281			self.upgrade_times.drain(self.upgrade_times.len()..)
282		} else {
283			// if we are actually pruning something, update the `last_pruned` member.
284			self.last_pruned = Some(self.upgrade_times[to_prune - 1].activated_at);
285			self.upgrade_times.drain(..to_prune)
286		};
287
288		drained.map(|times| times.expected_at)
289	}
290}
291
292/// Arguments for initializing a para.
293#[derive(
294	PartialEq,
295	Eq,
296	Clone,
297	Encode,
298	Decode,
299	DecodeWithMemTracking,
300	RuntimeDebug,
301	TypeInfo,
302	Serialize,
303	Deserialize,
304)]
305pub struct ParaGenesisArgs {
306	/// The initial head data to use.
307	pub genesis_head: HeadData,
308	/// The initial validation code to use.
309	pub validation_code: ValidationCode,
310	/// Lease holding or on-demand parachain.
311	#[serde(rename = "parachain")]
312	pub para_kind: ParaKind,
313}
314
315/// Distinguishes between lease holding Parachain and Parathread (on-demand parachain)
316#[derive(DecodeWithMemTracking, PartialEq, Eq, Clone, RuntimeDebug)]
317pub enum ParaKind {
318	Parathread,
319	Parachain,
320}
321
322impl Serialize for ParaKind {
323	fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
324	where
325		S: serde::Serializer,
326	{
327		match self {
328			ParaKind::Parachain => serializer.serialize_bool(true),
329			ParaKind::Parathread => serializer.serialize_bool(false),
330		}
331	}
332}
333
334impl<'de> Deserialize<'de> for ParaKind {
335	fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
336	where
337		D: serde::Deserializer<'de>,
338	{
339		match serde::de::Deserialize::deserialize(deserializer) {
340			Ok(true) => Ok(ParaKind::Parachain),
341			Ok(false) => Ok(ParaKind::Parathread),
342			_ => Err(serde::de::Error::custom("invalid ParaKind serde representation")),
343		}
344	}
345}
346
347// Manual encoding, decoding, and TypeInfo as the parakind field in ParaGenesisArgs used to be a
348// bool
349impl Encode for ParaKind {
350	fn size_hint(&self) -> usize {
351		true.size_hint()
352	}
353
354	fn using_encoded<R, F: FnOnce(&[u8]) -> R>(&self, f: F) -> R {
355		match self {
356			ParaKind::Parachain => true.using_encoded(f),
357			ParaKind::Parathread => false.using_encoded(f),
358		}
359	}
360}
361
362impl Decode for ParaKind {
363	fn decode<I: codec::Input>(input: &mut I) -> Result<Self, codec::Error> {
364		match bool::decode(input) {
365			Ok(true) => Ok(ParaKind::Parachain),
366			Ok(false) => Ok(ParaKind::Parathread),
367			_ => Err("Invalid ParaKind representation".into()),
368		}
369	}
370}
371
372impl TypeInfo for ParaKind {
373	type Identity = bool;
374	fn type_info() -> Type {
375		bool::type_info()
376	}
377}
378
379/// This enum describes a reason why a particular PVF pre-checking vote was initiated. When the
380/// PVF vote in question is concluded, this enum indicates what changes should be performed.
381#[derive(Debug, Encode, Decode, TypeInfo)]
382pub(crate) enum PvfCheckCause<BlockNumber> {
383	/// PVF vote was initiated by the initial onboarding process of the given para.
384	Onboarding(ParaId),
385	/// PVF vote was initiated by signalling of an upgrade by the given para.
386	Upgrade {
387		/// The ID of the parachain that initiated or is waiting for the conclusion of
388		/// pre-checking.
389		id: ParaId,
390		/// The relay-chain block number of **inclusion** of candidate that that initiated the
391		/// upgrade.
392		///
393		/// It's important to count upgrade enactment delay from the inclusion of this candidate
394		/// instead of its relay parent -- in order to keep PVF available in case of chain
395		/// reversions.
396		///
397		/// See https://github.com/paritytech/polkadot/issues/4601 for detailed explanation.
398		included_at: BlockNumber,
399		/// Whether or not the upgrade should be enacted directly.
400		///
401		/// If set to `Yes` it means that no `GoAheadSignal` will be set and the parachain code
402		/// will also be overwritten directly.
403		upgrade_strategy: UpgradeStrategy,
404	},
405}
406
407/// The strategy on how to handle a validation code upgrade.
408///
409/// When scheduling a parachain code upgrade the upgrade first is checked by all validators. The
410/// validators ensure that the new validation code can be compiled and instantiated. After the
411/// majority of the validators have reported their checking result the upgrade is either scheduled
412/// or aborted. This strategy then comes into play around the relay chain block this upgrade was
413/// scheduled in.
414#[derive(Debug, Copy, Clone, PartialEq, TypeInfo, Decode, Encode)]
415pub enum UpgradeStrategy {
416	/// Set the `GoAhead` signal to inform the parachain that it is time to upgrade.
417	///
418	/// The upgrade will then be applied after the first parachain block was enacted that must have
419	/// observed the `GoAhead` signal.
420	SetGoAheadSignal,
421	/// Apply the upgrade directly at the expected relay chain block.
422	///
423	/// This doesn't wait for the parachain to make any kind of progress.
424	ApplyAtExpectedBlock,
425}
426
427impl<BlockNumber> PvfCheckCause<BlockNumber> {
428	/// Returns the ID of the para that initiated or subscribed to the pre-checking vote.
429	fn para_id(&self) -> ParaId {
430		match *self {
431			PvfCheckCause::Onboarding(id) => id,
432			PvfCheckCause::Upgrade { id, .. } => id,
433		}
434	}
435}
436
437/// Specifies what was the outcome of a PVF pre-checking vote.
438#[derive(Copy, Clone, Encode, Decode, RuntimeDebug, TypeInfo)]
439enum PvfCheckOutcome {
440	Accepted,
441	Rejected,
442}
443
444/// This struct describes the current state of an in-progress PVF pre-checking vote.
445#[derive(Encode, Decode, TypeInfo)]
446pub(crate) struct PvfCheckActiveVoteState<BlockNumber> {
447	// The two following vectors have their length equal to the number of validators in the active
448	// set. They start with all zeroes. A 1 is set at an index when the validator at the that index
449	// makes a vote. Once a 1 is set for either of the vectors, that validator cannot vote anymore.
450	// Since the active validator set changes each session, the bit vectors are reinitialized as
451	// well: zeroed and resized so that each validator gets its own bit.
452	votes_accept: BitVec<u8, BitOrderLsb0>,
453	votes_reject: BitVec<u8, BitOrderLsb0>,
454
455	/// The number of session changes this PVF vote has observed. Therefore, this number is
456	/// increased at each session boundary. When created, it is initialized with 0.
457	age: SessionIndex,
458	/// The block number at which this PVF vote was created.
459	created_at: BlockNumber,
460	/// A list of causes for this PVF pre-checking. Has at least one.
461	causes: Vec<PvfCheckCause<BlockNumber>>,
462}
463
464impl<BlockNumber> PvfCheckActiveVoteState<BlockNumber> {
465	/// Returns a new instance of vote state, started at the specified block `now`, with the
466	/// number of validators in the current session `n_validators` and the originating `cause`.
467	fn new(now: BlockNumber, n_validators: usize, cause: PvfCheckCause<BlockNumber>) -> Self {
468		let mut causes = Vec::with_capacity(1);
469		causes.push(cause);
470		Self {
471			created_at: now,
472			votes_accept: bitvec::bitvec![u8, BitOrderLsb0; 0; n_validators],
473			votes_reject: bitvec::bitvec![u8, BitOrderLsb0; 0; n_validators],
474			age: 0,
475			causes,
476		}
477	}
478
479	/// Resets all votes and resizes the votes vectors corresponding to the number of validators
480	/// in the new session.
481	fn reinitialize_ballots(&mut self, n_validators: usize) {
482		let clear_and_resize = |v: &mut BitVec<_, _>| {
483			v.clear();
484			v.resize(n_validators, false);
485		};
486		clear_and_resize(&mut self.votes_accept);
487		clear_and_resize(&mut self.votes_reject);
488	}
489
490	/// Returns `Some(true)` if the validator at the given index has already cast their vote within
491	/// the ongoing session. Returns `None` in case the index is out of bounds.
492	fn has_vote(&self, validator_index: usize) -> Option<bool> {
493		let accept_vote = self.votes_accept.get(validator_index)?;
494		let reject_vote = self.votes_reject.get(validator_index)?;
495		Some(*accept_vote || *reject_vote)
496	}
497
498	/// Returns `None` if the quorum is not reached, or the direction of the decision.
499	fn quorum(&self, n_validators: usize) -> Option<PvfCheckOutcome> {
500		let accept_threshold = polkadot_primitives::supermajority_threshold(n_validators);
501		// At this threshold, a supermajority is no longer possible, so we reject.
502		let reject_threshold = n_validators - accept_threshold;
503
504		if self.votes_accept.count_ones() >= accept_threshold {
505			Some(PvfCheckOutcome::Accepted)
506		} else if self.votes_reject.count_ones() > reject_threshold {
507			Some(PvfCheckOutcome::Rejected)
508		} else {
509			None
510		}
511	}
512
513	#[cfg(test)]
514	pub(crate) fn causes(&self) -> &[PvfCheckCause<BlockNumber>] {
515		self.causes.as_slice()
516	}
517}
518
519/// Runtime hook for when a parachain head is updated.
520pub trait OnNewHead {
521	/// Called when a parachain head is updated.
522	/// Returns the weight consumed by this function.
523	fn on_new_head(id: ParaId, head: &HeadData) -> Weight;
524}
525
526#[impl_trait_for_tuples::impl_for_tuples(30)]
527impl OnNewHead for Tuple {
528	fn on_new_head(id: ParaId, head: &HeadData) -> Weight {
529		let mut weight: Weight = Default::default();
530		for_tuples!( #( weight.saturating_accrue(Tuple::on_new_head(id, head)); )* );
531		weight
532	}
533}
534
535/// Assign coretime to some parachain.
536///
537/// This assigns coretime to a parachain without using the coretime chain. Thus, this should only be
538/// used for testing purposes.
539pub trait AssignCoretime {
540	/// ONLY USE FOR TESTING OR GENESIS.
541	fn assign_coretime(id: ParaId) -> DispatchResult;
542}
543
544impl AssignCoretime for () {
545	fn assign_coretime(_: ParaId) -> DispatchResult {
546		Ok(())
547	}
548}
549
550pub trait WeightInfo {
551	fn force_set_current_code(c: u32) -> Weight;
552	fn force_set_current_head(s: u32) -> Weight;
553	fn force_set_most_recent_context() -> Weight;
554	fn force_schedule_code_upgrade(c: u32) -> Weight;
555	fn force_note_new_head(s: u32) -> Weight;
556	fn force_queue_action() -> Weight;
557	fn add_trusted_validation_code(c: u32) -> Weight;
558	fn poke_unused_validation_code() -> Weight;
559
560	fn include_pvf_check_statement_finalize_upgrade_accept() -> Weight;
561	fn include_pvf_check_statement_finalize_upgrade_reject() -> Weight;
562	fn include_pvf_check_statement_finalize_onboarding_accept() -> Weight;
563	fn include_pvf_check_statement_finalize_onboarding_reject() -> Weight;
564	fn include_pvf_check_statement() -> Weight;
565}
566
567pub struct TestWeightInfo;
568impl WeightInfo for TestWeightInfo {
569	fn force_set_current_code(_c: u32) -> Weight {
570		Weight::MAX
571	}
572	fn force_set_current_head(_s: u32) -> Weight {
573		Weight::MAX
574	}
575	fn force_set_most_recent_context() -> Weight {
576		Weight::MAX
577	}
578	fn force_schedule_code_upgrade(_c: u32) -> Weight {
579		Weight::MAX
580	}
581	fn force_note_new_head(_s: u32) -> Weight {
582		Weight::MAX
583	}
584	fn force_queue_action() -> Weight {
585		Weight::MAX
586	}
587	fn add_trusted_validation_code(_c: u32) -> Weight {
588		// Called during integration tests for para initialization.
589		Weight::zero()
590	}
591	fn poke_unused_validation_code() -> Weight {
592		Weight::MAX
593	}
594	fn include_pvf_check_statement_finalize_upgrade_accept() -> Weight {
595		Weight::MAX
596	}
597	fn include_pvf_check_statement_finalize_upgrade_reject() -> Weight {
598		Weight::MAX
599	}
600	fn include_pvf_check_statement_finalize_onboarding_accept() -> Weight {
601		Weight::MAX
602	}
603	fn include_pvf_check_statement_finalize_onboarding_reject() -> Weight {
604		Weight::MAX
605	}
606	fn include_pvf_check_statement() -> Weight {
607		// This special value is to distinguish from the finalizing variants above in tests.
608		Weight::MAX - Weight::from_parts(1, 1)
609	}
610}
611
612#[frame_support::pallet]
613pub mod pallet {
614	use super::*;
615	use sp_runtime::transaction_validity::{
616		InvalidTransaction, TransactionPriority, TransactionSource, TransactionValidity,
617		ValidTransaction,
618	};
619
620	#[pallet::pallet]
621	#[pallet::without_storage_info]
622	pub struct Pallet<T>(_);
623
624	#[pallet::config]
625	pub trait Config:
626		frame_system::Config
627		+ configuration::Config
628		+ shared::Config
629		+ frame_system::offchain::CreateInherent<Call<Self>>
630	{
631		type RuntimeEvent: From<Event> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
632
633		#[pallet::constant]
634		type UnsignedPriority: Get<TransactionPriority>;
635
636		type NextSessionRotation: EstimateNextSessionRotation<BlockNumberFor<Self>>;
637
638		/// Retrieve how many UMP messages are enqueued for this para-chain.
639		///
640		/// This is used to judge whether or not a para-chain can offboard. Per default this should
641		/// be set to the `ParaInclusion` pallet.
642		type QueueFootprinter: QueueFootprinter<Origin = UmpQueueId>;
643
644		/// Runtime hook for when a parachain head is updated.
645		type OnNewHead: OnNewHead;
646
647		/// Weight information for extrinsics in this pallet.
648		type WeightInfo: WeightInfo;
649
650		/// Runtime hook for assigning coretime for a given parachain.
651		///
652		/// This is only used at genesis or by root.
653		///
654		/// TODO: Remove once coretime is the standard across all chains.
655		type AssignCoretime: AssignCoretime;
656	}
657
658	#[pallet::event]
659	#[pallet::generate_deposit(pub(super) fn deposit_event)]
660	pub enum Event {
661		/// Current code has been updated for a Para. `para_id`
662		CurrentCodeUpdated(ParaId),
663		/// Current head has been updated for a Para. `para_id`
664		CurrentHeadUpdated(ParaId),
665		/// A code upgrade has been scheduled for a Para. `para_id`
666		CodeUpgradeScheduled(ParaId),
667		/// A new head has been noted for a Para. `para_id`
668		NewHeadNoted(ParaId),
669		/// A para has been queued to execute pending actions. `para_id`
670		ActionQueued(ParaId, SessionIndex),
671		/// The given para either initiated or subscribed to a PVF check for the given validation
672		/// code. `code_hash` `para_id`
673		PvfCheckStarted(ValidationCodeHash, ParaId),
674		/// The given validation code was accepted by the PVF pre-checking vote.
675		/// `code_hash` `para_id`
676		PvfCheckAccepted(ValidationCodeHash, ParaId),
677		/// The given validation code was rejected by the PVF pre-checking vote.
678		/// `code_hash` `para_id`
679		PvfCheckRejected(ValidationCodeHash, ParaId),
680	}
681
682	#[pallet::error]
683	pub enum Error<T> {
684		/// Para is not registered in our system.
685		NotRegistered,
686		/// Para cannot be onboarded because it is already tracked by our system.
687		CannotOnboard,
688		/// Para cannot be offboarded at this time.
689		CannotOffboard,
690		/// Para cannot be upgraded to a lease holding parachain.
691		CannotUpgrade,
692		/// Para cannot be downgraded to an on-demand parachain.
693		CannotDowngrade,
694		/// The statement for PVF pre-checking is stale.
695		PvfCheckStatementStale,
696		/// The statement for PVF pre-checking is for a future session.
697		PvfCheckStatementFuture,
698		/// Claimed validator index is out of bounds.
699		PvfCheckValidatorIndexOutOfBounds,
700		/// The signature for the PVF pre-checking is invalid.
701		PvfCheckInvalidSignature,
702		/// The given validator already has cast a vote.
703		PvfCheckDoubleVote,
704		/// The given PVF does not exist at the moment of process a vote.
705		PvfCheckSubjectInvalid,
706		/// Parachain cannot currently schedule a code upgrade.
707		CannotUpgradeCode,
708		/// Invalid validation code size.
709		InvalidCode,
710	}
711
712	/// All currently active PVF pre-checking votes.
713	///
714	/// Invariant:
715	/// - There are no PVF pre-checking votes that exists in list but not in the set and vice versa.
716	#[pallet::storage]
717	pub(super) type PvfActiveVoteMap<T: Config> = StorageMap<
718		_,
719		Twox64Concat,
720		ValidationCodeHash,
721		PvfCheckActiveVoteState<BlockNumberFor<T>>,
722		OptionQuery,
723	>;
724
725	/// The list of all currently active PVF votes. Auxiliary to `PvfActiveVoteMap`.
726	#[pallet::storage]
727	pub(super) type PvfActiveVoteList<T: Config> =
728		StorageValue<_, Vec<ValidationCodeHash>, ValueQuery>;
729
730	/// All lease holding parachains. Ordered ascending by `ParaId`. On demand parachains are not
731	/// included.
732	///
733	/// Consider using the [`ParachainsCache`] type of modifying.
734	#[pallet::storage]
735	pub type Parachains<T: Config> = StorageValue<_, Vec<ParaId>, ValueQuery>;
736
737	/// The current lifecycle of a all known Para IDs.
738	#[pallet::storage]
739	pub(super) type ParaLifecycles<T: Config> = StorageMap<_, Twox64Concat, ParaId, ParaLifecycle>;
740
741	/// The head-data of every registered para.
742	#[pallet::storage]
743	pub type Heads<T: Config> = StorageMap<_, Twox64Concat, ParaId, HeadData>;
744
745	/// The context (relay-chain block number) of the most recent parachain head.
746	#[pallet::storage]
747	pub type MostRecentContext<T: Config> = StorageMap<_, Twox64Concat, ParaId, BlockNumberFor<T>>;
748
749	/// The validation code hash of every live para.
750	///
751	/// Corresponding code can be retrieved with [`CodeByHash`].
752	#[pallet::storage]
753	pub type CurrentCodeHash<T: Config> = StorageMap<_, Twox64Concat, ParaId, ValidationCodeHash>;
754
755	/// Actual past code hash, indicated by the para id as well as the block number at which it
756	/// became outdated.
757	///
758	/// Corresponding code can be retrieved with [`CodeByHash`].
759	#[pallet::storage]
760	pub(super) type PastCodeHash<T: Config> =
761		StorageMap<_, Twox64Concat, (ParaId, BlockNumberFor<T>), ValidationCodeHash>;
762
763	/// Past code of parachains. The parachains themselves may not be registered anymore,
764	/// but we also keep their code on-chain for the same amount of time as outdated code
765	/// to keep it available for approval checkers.
766	#[pallet::storage]
767	pub type PastCodeMeta<T: Config> =
768		StorageMap<_, Twox64Concat, ParaId, ParaPastCodeMeta<BlockNumberFor<T>>, ValueQuery>;
769
770	/// Which paras have past code that needs pruning and the relay-chain block at which the code
771	/// was replaced. Note that this is the actual height of the included block, not the expected
772	/// height at which the code upgrade would be applied, although they may be equal.
773	/// This is to ensure the entire acceptance period is covered, not an offset acceptance period
774	/// starting from the time at which the parachain perceives a code upgrade as having occurred.
775	/// Multiple entries for a single para are permitted. Ordered ascending by block number.
776	#[pallet::storage]
777	pub(super) type PastCodePruning<T: Config> =
778		StorageValue<_, Vec<(ParaId, BlockNumberFor<T>)>, ValueQuery>;
779
780	/// The block number at which the planned code change is expected for a parachain.
781	///
782	/// The change will be applied after the first parablock for this ID included which executes
783	/// in the context of a relay chain block with a number >= `expected_at`.
784	#[pallet::storage]
785	pub type FutureCodeUpgrades<T: Config> = StorageMap<_, Twox64Concat, ParaId, BlockNumberFor<T>>;
786
787	/// The list of upcoming future code upgrades.
788	///
789	/// Each item is a pair of the parachain and the expected block at which the upgrade should be
790	/// applied. The upgrade will be applied at the given relay chain block. In contrast to
791	/// [`FutureCodeUpgrades`] this code upgrade will be applied regardless the parachain making any
792	/// progress or not.
793	///
794	/// Ordered ascending by block number.
795	#[pallet::storage]
796	pub(super) type FutureCodeUpgradesAt<T: Config> =
797		StorageValue<_, Vec<(ParaId, BlockNumberFor<T>)>, ValueQuery>;
798
799	/// The actual future code hash of a para.
800	///
801	/// Corresponding code can be retrieved with [`CodeByHash`].
802	#[pallet::storage]
803	pub type FutureCodeHash<T: Config> = StorageMap<_, Twox64Concat, ParaId, ValidationCodeHash>;
804
805	/// This is used by the relay-chain to communicate to a parachain a go-ahead with in the upgrade
806	/// procedure.
807	///
808	/// This value is absent when there are no upgrades scheduled or during the time the relay chain
809	/// performs the checks. It is set at the first relay-chain block when the corresponding
810	/// parachain can switch its upgrade function. As soon as the parachain's block is included, the
811	/// value gets reset to `None`.
812	///
813	/// NOTE that this field is used by parachains via merkle storage proofs, therefore changing
814	/// the format will require migration of parachains.
815	#[pallet::storage]
816	pub(super) type UpgradeGoAheadSignal<T: Config> =
817		StorageMap<_, Twox64Concat, ParaId, UpgradeGoAhead>;
818
819	/// This is used by the relay-chain to communicate that there are restrictions for performing
820	/// an upgrade for this parachain.
821	///
822	/// This may be a because the parachain waits for the upgrade cooldown to expire. Another
823	/// potential use case is when we want to perform some maintenance (such as storage migration)
824	/// we could restrict upgrades to make the process simpler.
825	///
826	/// NOTE that this field is used by parachains via merkle storage proofs, therefore changing
827	/// the format will require migration of parachains.
828	#[pallet::storage]
829	pub type UpgradeRestrictionSignal<T: Config> =
830		StorageMap<_, Twox64Concat, ParaId, UpgradeRestriction>;
831
832	/// The list of parachains that are awaiting for their upgrade restriction to cooldown.
833	///
834	/// Ordered ascending by block number.
835	#[pallet::storage]
836	pub(super) type UpgradeCooldowns<T: Config> =
837		StorageValue<_, Vec<(ParaId, BlockNumberFor<T>)>, ValueQuery>;
838
839	/// The list of upcoming code upgrades.
840	///
841	/// Each item is a pair of which para performs a code upgrade and at which relay-chain block it
842	/// is expected at.
843	///
844	/// Ordered ascending by block number.
845	#[pallet::storage]
846	pub(super) type UpcomingUpgrades<T: Config> =
847		StorageValue<_, Vec<(ParaId, BlockNumberFor<T>)>, ValueQuery>;
848
849	/// The actions to perform during the start of a specific session index.
850	#[pallet::storage]
851	pub type ActionsQueue<T: Config> =
852		StorageMap<_, Twox64Concat, SessionIndex, Vec<ParaId>, ValueQuery>;
853
854	/// Upcoming paras instantiation arguments.
855	///
856	/// NOTE that after PVF pre-checking is enabled the para genesis arg will have it's code set
857	/// to empty. Instead, the code will be saved into the storage right away via `CodeByHash`.
858	#[pallet::storage]
859	pub(super) type UpcomingParasGenesis<T: Config> =
860		StorageMap<_, Twox64Concat, ParaId, ParaGenesisArgs>;
861
862	/// The number of reference on the validation code in [`CodeByHash`] storage.
863	#[pallet::storage]
864	pub(super) type CodeByHashRefs<T: Config> =
865		StorageMap<_, Identity, ValidationCodeHash, u32, ValueQuery>;
866
867	/// Validation code stored by its hash.
868	///
869	/// This storage is consistent with [`FutureCodeHash`], [`CurrentCodeHash`] and
870	/// [`PastCodeHash`].
871	#[pallet::storage]
872	pub type CodeByHash<T: Config> = StorageMap<_, Identity, ValidationCodeHash, ValidationCode>;
873
874	#[pallet::genesis_config]
875	#[derive(DefaultNoBound)]
876	pub struct GenesisConfig<T: Config> {
877		#[serde(skip)]
878		pub _config: core::marker::PhantomData<T>,
879		pub paras: Vec<(ParaId, ParaGenesisArgs)>,
880	}
881
882	#[pallet::genesis_build]
883	impl<T: Config> BuildGenesisConfig for GenesisConfig<T> {
884		fn build(&self) {
885			let mut parachains = ParachainsCache::new();
886			for (id, genesis_args) in &self.paras {
887				if genesis_args.validation_code.0.is_empty() {
888					panic!("empty validation code is not allowed in genesis");
889				}
890				Pallet::<T>::initialize_para_now(&mut parachains, *id, genesis_args);
891				T::AssignCoretime::assign_coretime(*id)
892					.expect("Assigning coretime works at genesis; qed");
893			}
894			// parachains are flushed on drop
895		}
896	}
897
898	#[pallet::call]
899	impl<T: Config> Pallet<T> {
900		/// Set the storage for the parachain validation code immediately.
901		#[pallet::call_index(0)]
902		#[pallet::weight(<T as Config>::WeightInfo::force_set_current_code(new_code.0.len() as u32))]
903		pub fn force_set_current_code(
904			origin: OriginFor<T>,
905			para: ParaId,
906			new_code: ValidationCode,
907		) -> DispatchResult {
908			ensure_root(origin)?;
909			let new_code_hash = new_code.hash();
910			Self::increase_code_ref(&new_code_hash, &new_code);
911			Self::set_current_code(para, new_code_hash, frame_system::Pallet::<T>::block_number());
912			Self::deposit_event(Event::CurrentCodeUpdated(para));
913			Ok(())
914		}
915
916		/// Set the storage for the current parachain head data immediately.
917		#[pallet::call_index(1)]
918		#[pallet::weight(<T as Config>::WeightInfo::force_set_current_head(new_head.0.len() as u32))]
919		pub fn force_set_current_head(
920			origin: OriginFor<T>,
921			para: ParaId,
922			new_head: HeadData,
923		) -> DispatchResult {
924			ensure_root(origin)?;
925			Self::set_current_head(para, new_head);
926			Ok(())
927		}
928
929		/// Schedule an upgrade as if it was scheduled in the given relay parent block.
930		#[pallet::call_index(2)]
931		#[pallet::weight(<T as Config>::WeightInfo::force_schedule_code_upgrade(new_code.0.len() as u32))]
932		pub fn force_schedule_code_upgrade(
933			origin: OriginFor<T>,
934			para: ParaId,
935			new_code: ValidationCode,
936			relay_parent_number: BlockNumberFor<T>,
937		) -> DispatchResult {
938			ensure_root(origin)?;
939			let config = configuration::ActiveConfig::<T>::get();
940			Self::schedule_code_upgrade(
941				para,
942				new_code,
943				relay_parent_number,
944				&config,
945				UpgradeStrategy::ApplyAtExpectedBlock,
946			);
947			Self::deposit_event(Event::CodeUpgradeScheduled(para));
948			Ok(())
949		}
950
951		/// Note a new block head for para within the context of the current block.
952		#[pallet::call_index(3)]
953		#[pallet::weight(<T as Config>::WeightInfo::force_note_new_head(new_head.0.len() as u32))]
954		pub fn force_note_new_head(
955			origin: OriginFor<T>,
956			para: ParaId,
957			new_head: HeadData,
958		) -> DispatchResult {
959			ensure_root(origin)?;
960			let now = frame_system::Pallet::<T>::block_number();
961			Self::note_new_head(para, new_head, now);
962			Self::deposit_event(Event::NewHeadNoted(para));
963			Ok(())
964		}
965
966		/// Put a parachain directly into the next session's action queue.
967		/// We can't queue it any sooner than this without going into the
968		/// initializer...
969		#[pallet::call_index(4)]
970		#[pallet::weight(<T as Config>::WeightInfo::force_queue_action())]
971		pub fn force_queue_action(origin: OriginFor<T>, para: ParaId) -> DispatchResult {
972			ensure_root(origin)?;
973			let next_session = shared::CurrentSessionIndex::<T>::get().saturating_add(One::one());
974			ActionsQueue::<T>::mutate(next_session, |v| {
975				if let Err(i) = v.binary_search(&para) {
976					v.insert(i, para);
977				}
978			});
979			Self::deposit_event(Event::ActionQueued(para, next_session));
980			Ok(())
981		}
982
983		/// Adds the validation code to the storage.
984		///
985		/// The code will not be added if it is already present. Additionally, if PVF pre-checking
986		/// is running for that code, it will be instantly accepted.
987		///
988		/// Otherwise, the code will be added into the storage. Note that the code will be added
989		/// into storage with reference count 0. This is to account the fact that there are no users
990		/// for this code yet. The caller will have to make sure that this code eventually gets
991		/// used by some parachain or removed from the storage to avoid storage leaks. For the
992		/// latter prefer to use the `poke_unused_validation_code` dispatchable to raw storage
993		/// manipulation.
994		///
995		/// This function is mainly meant to be used for upgrading parachains that do not follow
996		/// the go-ahead signal while the PVF pre-checking feature is enabled.
997		#[pallet::call_index(5)]
998		#[pallet::weight(<T as Config>::WeightInfo::add_trusted_validation_code(validation_code.0.len() as u32))]
999		pub fn add_trusted_validation_code(
1000			origin: OriginFor<T>,
1001			validation_code: ValidationCode,
1002		) -> DispatchResult {
1003			ensure_root(origin)?;
1004			let code_hash = validation_code.hash();
1005
1006			if let Some(vote) = PvfActiveVoteMap::<T>::get(&code_hash) {
1007				// Remove the existing vote.
1008				PvfActiveVoteMap::<T>::remove(&code_hash);
1009				PvfActiveVoteList::<T>::mutate(|l| {
1010					if let Ok(i) = l.binary_search(&code_hash) {
1011						l.remove(i);
1012					}
1013				});
1014
1015				let cfg = configuration::ActiveConfig::<T>::get();
1016				Self::enact_pvf_accepted(
1017					frame_system::Pallet::<T>::block_number(),
1018					&code_hash,
1019					&vote.causes,
1020					vote.age,
1021					&cfg,
1022				);
1023				return Ok(())
1024			}
1025
1026			if CodeByHash::<T>::contains_key(&code_hash) {
1027				// There is no vote, but the code exists. Nothing to do here.
1028				return Ok(())
1029			}
1030
1031			// At this point the code is unknown and there is no PVF pre-checking vote for it, so we
1032			// can just add the code into the storage.
1033			//
1034			// NOTE That we do not use `increase_code_ref` here, because the code is not yet used
1035			// by any parachain.
1036			CodeByHash::<T>::insert(code_hash, &validation_code);
1037
1038			Ok(())
1039		}
1040
1041		/// Remove the validation code from the storage iff the reference count is 0.
1042		///
1043		/// This is better than removing the storage directly, because it will not remove the code
1044		/// that was suddenly got used by some parachain while this dispatchable was pending
1045		/// dispatching.
1046		#[pallet::call_index(6)]
1047		#[pallet::weight(<T as Config>::WeightInfo::poke_unused_validation_code())]
1048		pub fn poke_unused_validation_code(
1049			origin: OriginFor<T>,
1050			validation_code_hash: ValidationCodeHash,
1051		) -> DispatchResult {
1052			ensure_root(origin)?;
1053			if CodeByHashRefs::<T>::get(&validation_code_hash) == 0 {
1054				CodeByHash::<T>::remove(&validation_code_hash);
1055			}
1056			Ok(())
1057		}
1058
1059		/// Includes a statement for a PVF pre-checking vote. Potentially, finalizes the vote and
1060		/// enacts the results if that was the last vote before achieving the supermajority.
1061		#[pallet::call_index(7)]
1062		#[pallet::weight(
1063			<T as Config>::WeightInfo::include_pvf_check_statement_finalize_upgrade_accept()
1064				.max(<T as Config>::WeightInfo::include_pvf_check_statement_finalize_upgrade_reject())
1065				.max(<T as Config>::WeightInfo::include_pvf_check_statement_finalize_onboarding_accept()
1066					.max(<T as Config>::WeightInfo::include_pvf_check_statement_finalize_onboarding_reject())
1067				)
1068		)]
1069		pub fn include_pvf_check_statement(
1070			origin: OriginFor<T>,
1071			stmt: PvfCheckStatement,
1072			signature: ValidatorSignature,
1073		) -> DispatchResultWithPostInfo {
1074			ensure_none(origin)?;
1075
1076			let validators = shared::ActiveValidatorKeys::<T>::get();
1077			let current_session = shared::CurrentSessionIndex::<T>::get();
1078			if stmt.session_index < current_session {
1079				return Err(Error::<T>::PvfCheckStatementStale.into())
1080			} else if stmt.session_index > current_session {
1081				return Err(Error::<T>::PvfCheckStatementFuture.into())
1082			}
1083			let validator_index = stmt.validator_index.0 as usize;
1084			let validator_public = validators
1085				.get(validator_index)
1086				.ok_or(Error::<T>::PvfCheckValidatorIndexOutOfBounds)?;
1087
1088			let signing_payload = stmt.signing_payload();
1089			ensure!(
1090				signature.verify(&signing_payload[..], &validator_public),
1091				Error::<T>::PvfCheckInvalidSignature,
1092			);
1093
1094			let mut active_vote = PvfActiveVoteMap::<T>::get(&stmt.subject)
1095				.ok_or(Error::<T>::PvfCheckSubjectInvalid)?;
1096
1097			// Ensure that the validator submitting this statement hasn't voted already.
1098			ensure!(
1099				!active_vote
1100					.has_vote(validator_index)
1101					.ok_or(Error::<T>::PvfCheckValidatorIndexOutOfBounds)?,
1102				Error::<T>::PvfCheckDoubleVote,
1103			);
1104
1105			// Finally, cast the vote and persist.
1106			if stmt.accept {
1107				active_vote.votes_accept.set(validator_index, true);
1108			} else {
1109				active_vote.votes_reject.set(validator_index, true);
1110			}
1111
1112			if let Some(outcome) = active_vote.quorum(validators.len()) {
1113				// The quorum has been achieved.
1114				//
1115				// Remove the PVF vote from the active map and finalize the PVF checking according
1116				// to the outcome.
1117				PvfActiveVoteMap::<T>::remove(&stmt.subject);
1118				PvfActiveVoteList::<T>::mutate(|l| {
1119					if let Ok(i) = l.binary_search(&stmt.subject) {
1120						l.remove(i);
1121					}
1122				});
1123				match outcome {
1124					PvfCheckOutcome::Accepted => {
1125						let cfg = configuration::ActiveConfig::<T>::get();
1126						Self::enact_pvf_accepted(
1127							frame_system::Pallet::<T>::block_number(),
1128							&stmt.subject,
1129							&active_vote.causes,
1130							active_vote.age,
1131							&cfg,
1132						);
1133					},
1134					PvfCheckOutcome::Rejected => {
1135						Self::enact_pvf_rejected(&stmt.subject, active_vote.causes);
1136					},
1137				}
1138
1139				// No weight refund since this statement was the last one and lead to finalization.
1140				Ok(().into())
1141			} else {
1142				// No quorum has been achieved.
1143				//
1144				// - So just store the updated state back into the storage.
1145				// - Only charge weight for simple vote inclusion.
1146				PvfActiveVoteMap::<T>::insert(&stmt.subject, active_vote);
1147				Ok(Some(<T as Config>::WeightInfo::include_pvf_check_statement()).into())
1148			}
1149		}
1150
1151		/// Set the storage for the current parachain head data immediately.
1152		#[pallet::call_index(8)]
1153		#[pallet::weight(<T as Config>::WeightInfo::force_set_most_recent_context())]
1154		pub fn force_set_most_recent_context(
1155			origin: OriginFor<T>,
1156			para: ParaId,
1157			context: BlockNumberFor<T>,
1158		) -> DispatchResult {
1159			ensure_root(origin)?;
1160			MostRecentContext::<T>::insert(&para, context);
1161			Ok(())
1162		}
1163	}
1164
1165	#[pallet::validate_unsigned]
1166	impl<T: Config> ValidateUnsigned for Pallet<T> {
1167		type Call = Call<T>;
1168
1169		fn validate_unsigned(_source: TransactionSource, call: &Self::Call) -> TransactionValidity {
1170			let (stmt, signature) = match call {
1171				Call::include_pvf_check_statement { stmt, signature } => (stmt, signature),
1172				_ => return InvalidTransaction::Call.into(),
1173			};
1174
1175			let current_session = shared::CurrentSessionIndex::<T>::get();
1176			if stmt.session_index < current_session {
1177				return InvalidTransaction::Stale.into()
1178			} else if stmt.session_index > current_session {
1179				return InvalidTransaction::Future.into()
1180			}
1181
1182			let validator_index = stmt.validator_index.0 as usize;
1183			let validators = shared::ActiveValidatorKeys::<T>::get();
1184			let validator_public = match validators.get(validator_index) {
1185				Some(pk) => pk,
1186				None => return InvalidTransaction::Custom(INVALID_TX_BAD_VALIDATOR_IDX).into(),
1187			};
1188
1189			let signing_payload = stmt.signing_payload();
1190			if !signature.verify(&signing_payload[..], &validator_public) {
1191				return InvalidTransaction::BadProof.into()
1192			}
1193
1194			let active_vote = match PvfActiveVoteMap::<T>::get(&stmt.subject) {
1195				Some(v) => v,
1196				None => return InvalidTransaction::Custom(INVALID_TX_BAD_SUBJECT).into(),
1197			};
1198
1199			match active_vote.has_vote(validator_index) {
1200				Some(false) => (),
1201				Some(true) => return InvalidTransaction::Custom(INVALID_TX_DOUBLE_VOTE).into(),
1202				None => return InvalidTransaction::Custom(INVALID_TX_BAD_VALIDATOR_IDX).into(),
1203			}
1204
1205			ValidTransaction::with_tag_prefix("PvfPreCheckingVote")
1206				.priority(T::UnsignedPriority::get())
1207				.longevity(
1208					TryInto::<u64>::try_into(
1209						T::NextSessionRotation::average_session_length() / 2u32.into(),
1210					)
1211					.unwrap_or(64_u64),
1212				)
1213				.and_provides((stmt.session_index, stmt.validator_index, stmt.subject))
1214				.propagate(true)
1215				.build()
1216		}
1217
1218		fn pre_dispatch(_call: &Self::Call) -> Result<(), TransactionValidityError> {
1219			// Return `Ok` here meaning that as soon as the transaction got into the block, it will
1220			// always dispatched. This is OK, since the `include_pvf_check_statement` dispatchable
1221			// will perform the same checks anyway, so there is no point doing it here.
1222			//
1223			// On the other hand, if we did not provide the implementation, then the default
1224			// implementation would be used. The default implementation just delegates the
1225			// pre-dispatch validation to `validate_unsigned`.
1226			Ok(())
1227		}
1228	}
1229}
1230
1231// custom transaction error codes
1232const INVALID_TX_BAD_VALIDATOR_IDX: u8 = 1;
1233const INVALID_TX_BAD_SUBJECT: u8 = 2;
1234const INVALID_TX_DOUBLE_VOTE: u8 = 3;
1235
1236/// This is intermediate "fix" for this issue:
1237/// <https://github.com/paritytech/polkadot-sdk/issues/4737>
1238///
1239/// It does not actually fix it, but makes the worst case better. Without that limit someone
1240/// could completely DoS the relay chain by registering a ridiculously high amount of paras.
1241/// With this limit the same attack could lead to some parachains ceasing to being able to
1242/// communicate via offchain XCMP. Snowbridge will still work as it only cares about `BridgeHub`.
1243pub const MAX_PARA_HEADS: usize = 1024;
1244
1245impl<T: Config> Pallet<T> {
1246	/// This is a call to schedule code upgrades for parachains which is safe to be called
1247	/// outside of this module. That means this function does all checks necessary to ensure
1248	/// that some external code is allowed to trigger a code upgrade. We do not do auth checks,
1249	/// that should be handled by whomever calls this function.
1250	pub(crate) fn schedule_code_upgrade_external(
1251		id: ParaId,
1252		new_code: ValidationCode,
1253		upgrade_strategy: UpgradeStrategy,
1254	) -> DispatchResult {
1255		// Check that we can schedule an upgrade at all.
1256		ensure!(Self::can_upgrade_validation_code(id), Error::<T>::CannotUpgradeCode);
1257		let config = configuration::ActiveConfig::<T>::get();
1258		// Validation code sanity checks:
1259		ensure!(new_code.0.len() >= MIN_CODE_SIZE as usize, Error::<T>::InvalidCode);
1260		ensure!(new_code.0.len() <= config.max_code_size as usize, Error::<T>::InvalidCode);
1261
1262		let current_block = frame_system::Pallet::<T>::block_number();
1263		// Schedule the upgrade with a delay just like if a parachain triggered the upgrade.
1264		let upgrade_block = current_block.saturating_add(config.validation_upgrade_delay);
1265		Self::schedule_code_upgrade(id, new_code, upgrade_block, &config, upgrade_strategy);
1266		Self::deposit_event(Event::CodeUpgradeScheduled(id));
1267		Ok(())
1268	}
1269
1270	/// Set the current head of a parachain.
1271	pub(crate) fn set_current_head(para: ParaId, new_head: HeadData) {
1272		Heads::<T>::insert(&para, new_head);
1273		Self::deposit_event(Event::CurrentHeadUpdated(para));
1274	}
1275
1276	/// Called by the initializer to initialize the paras pallet.
1277	pub(crate) fn initializer_initialize(now: BlockNumberFor<T>) -> Weight {
1278		Self::prune_old_code(now) +
1279			Self::process_scheduled_upgrade_changes(now) +
1280			Self::process_future_code_upgrades_at(now)
1281	}
1282
1283	/// Called by the initializer to finalize the paras pallet.
1284	pub(crate) fn initializer_finalize(now: BlockNumberFor<T>) {
1285		Self::process_scheduled_upgrade_cooldowns(now);
1286	}
1287
1288	/// Called by the initializer to note that a new session has started.
1289	///
1290	/// Returns the list of outgoing paras from the actions queue.
1291	pub(crate) fn initializer_on_new_session(
1292		notification: &SessionChangeNotification<BlockNumberFor<T>>,
1293	) -> Vec<ParaId> {
1294		let outgoing_paras = Self::apply_actions_queue(notification.session_index);
1295		Self::groom_ongoing_pvf_votes(&notification.new_config, notification.validators.len());
1296		outgoing_paras
1297	}
1298
1299	/// The validation code of live para.
1300	pub(crate) fn current_code(para_id: &ParaId) -> Option<ValidationCode> {
1301		CurrentCodeHash::<T>::get(para_id).and_then(|code_hash| {
1302			let code = CodeByHash::<T>::get(&code_hash);
1303			if code.is_none() {
1304				log::error!(
1305					"Pallet paras storage is inconsistent, code not found for hash {}",
1306					code_hash,
1307				);
1308				debug_assert!(false, "inconsistent paras storages");
1309			}
1310			code
1311		})
1312	}
1313
1314	/// Get a list of the first [`MAX_PARA_HEADS`] para heads sorted by para_id.
1315	/// This method is likely to be removed in the future.
1316	pub fn sorted_para_heads() -> Vec<(u32, Vec<u8>)> {
1317		let mut heads: Vec<(u32, Vec<u8>)> =
1318			Heads::<T>::iter().map(|(id, head)| (id.into(), head.0)).collect();
1319		heads.sort_by_key(|(id, _)| *id);
1320		heads.truncate(MAX_PARA_HEADS);
1321		heads
1322	}
1323
1324	// Apply all para actions queued for the given session index.
1325	//
1326	// The actions to take are based on the lifecycle of of the paras.
1327	//
1328	// The final state of any para after the actions queue should be as a
1329	// lease holding parachain, on-demand parachain, or not registered. (stable states)
1330	//
1331	// Returns the list of outgoing paras from the actions queue.
1332	fn apply_actions_queue(session: SessionIndex) -> Vec<ParaId> {
1333		let actions = ActionsQueue::<T>::take(session);
1334		let mut parachains = ParachainsCache::new();
1335		let now = frame_system::Pallet::<T>::block_number();
1336		let mut outgoing = Vec::new();
1337
1338		for para in actions {
1339			let lifecycle = ParaLifecycles::<T>::get(&para);
1340			match lifecycle {
1341				None | Some(ParaLifecycle::Parathread) | Some(ParaLifecycle::Parachain) => { /* Nothing to do... */
1342				},
1343				Some(ParaLifecycle::Onboarding) => {
1344					if let Some(genesis_data) = UpcomingParasGenesis::<T>::take(&para) {
1345						Self::initialize_para_now(&mut parachains, para, &genesis_data);
1346					}
1347				},
1348				// Upgrade an on-demand parachain to a lease holding parachain
1349				Some(ParaLifecycle::UpgradingParathread) => {
1350					parachains.add(para);
1351					ParaLifecycles::<T>::insert(&para, ParaLifecycle::Parachain);
1352				},
1353				// Downgrade a lease holding parachain to an on-demand parachain
1354				Some(ParaLifecycle::DowngradingParachain) => {
1355					parachains.remove(para);
1356					ParaLifecycles::<T>::insert(&para, ParaLifecycle::Parathread);
1357				},
1358				// Offboard a lease holding or on-demand parachain from the system
1359				Some(ParaLifecycle::OffboardingParachain) |
1360				Some(ParaLifecycle::OffboardingParathread) => {
1361					parachains.remove(para);
1362
1363					Heads::<T>::remove(&para);
1364					MostRecentContext::<T>::remove(&para);
1365					FutureCodeUpgrades::<T>::remove(&para);
1366					UpgradeGoAheadSignal::<T>::remove(&para);
1367					UpgradeRestrictionSignal::<T>::remove(&para);
1368					ParaLifecycles::<T>::remove(&para);
1369					let removed_future_code_hash = FutureCodeHash::<T>::take(&para);
1370					if let Some(removed_future_code_hash) = removed_future_code_hash {
1371						Self::decrease_code_ref(&removed_future_code_hash);
1372					}
1373
1374					let removed_code_hash = CurrentCodeHash::<T>::take(&para);
1375					if let Some(removed_code_hash) = removed_code_hash {
1376						Self::note_past_code(para, now, now, removed_code_hash);
1377					}
1378
1379					outgoing.push(para);
1380				},
1381			}
1382		}
1383
1384		if !outgoing.is_empty() {
1385			// Filter offboarded parachains from the upcoming upgrades and upgrade cooldowns list.
1386			//
1387			// We do it after the offboarding to get away with only a single read/write per list.
1388			//
1389			// NOTE both of those iterates over the list and the outgoing. We do not expect either
1390			//      of these to be large. Thus should be fine.
1391			UpcomingUpgrades::<T>::mutate(|upcoming_upgrades| {
1392				upcoming_upgrades.retain(|(para, _)| !outgoing.contains(para));
1393			});
1394			UpgradeCooldowns::<T>::mutate(|upgrade_cooldowns| {
1395				upgrade_cooldowns.retain(|(para, _)| !outgoing.contains(para));
1396			});
1397			FutureCodeUpgradesAt::<T>::mutate(|future_upgrades| {
1398				future_upgrades.retain(|(para, _)| !outgoing.contains(para));
1399			});
1400		}
1401
1402		// Persist parachains into the storage explicitly.
1403		drop(parachains);
1404
1405		outgoing
1406	}
1407
1408	// note replacement of the code of para with given `id`, which occurred in the
1409	// context of the given relay-chain block number. provide the replaced code.
1410	//
1411	// `at` for para-triggered replacement is the block number of the relay-chain
1412	// block in whose context the parablock was executed
1413	// (i.e. number of `relay_parent` in the receipt)
1414	fn note_past_code(
1415		id: ParaId,
1416		at: BlockNumberFor<T>,
1417		now: BlockNumberFor<T>,
1418		old_code_hash: ValidationCodeHash,
1419	) -> Weight {
1420		PastCodeMeta::<T>::mutate(&id, |past_meta| {
1421			past_meta.note_replacement(at, now);
1422		});
1423
1424		PastCodeHash::<T>::insert(&(id, at), old_code_hash);
1425
1426		// Schedule pruning for this past-code to be removed as soon as it
1427		// exits the slashing window.
1428		PastCodePruning::<T>::mutate(|pruning| {
1429			let insert_idx =
1430				pruning.binary_search_by_key(&now, |&(_, b)| b).unwrap_or_else(|idx| idx);
1431			pruning.insert(insert_idx, (id, now));
1432		});
1433
1434		T::DbWeight::get().reads_writes(2, 3)
1435	}
1436
1437	// looks at old code metadata, compares them to the current acceptance window, and prunes those
1438	// that are too old.
1439	fn prune_old_code(now: BlockNumberFor<T>) -> Weight {
1440		let config = configuration::ActiveConfig::<T>::get();
1441		let code_retention_period = config.code_retention_period;
1442		if now <= code_retention_period {
1443			let weight = T::DbWeight::get().reads_writes(1, 0);
1444			return weight
1445		}
1446
1447		// The height of any changes we no longer should keep around.
1448		let pruning_height = now - (code_retention_period + One::one());
1449
1450		let pruning_tasks_done =
1451			PastCodePruning::<T>::mutate(|pruning_tasks: &mut Vec<(_, BlockNumberFor<T>)>| {
1452				let (pruning_tasks_done, pruning_tasks_to_do) = {
1453					// find all past code that has just exited the pruning window.
1454					let up_to_idx =
1455						pruning_tasks.iter().take_while(|&(_, at)| at <= &pruning_height).count();
1456					(up_to_idx, pruning_tasks.drain(..up_to_idx))
1457				};
1458
1459				for (para_id, _) in pruning_tasks_to_do {
1460					let full_deactivate = PastCodeMeta::<T>::mutate(&para_id, |meta| {
1461						for pruned_repl_at in meta.prune_up_to(pruning_height) {
1462							let removed_code_hash =
1463								PastCodeHash::<T>::take(&(para_id, pruned_repl_at));
1464
1465							if let Some(removed_code_hash) = removed_code_hash {
1466								Self::decrease_code_ref(&removed_code_hash);
1467							} else {
1468								log::warn!(
1469									target: LOG_TARGET,
1470									"Missing code for removed hash {:?}",
1471									removed_code_hash,
1472								);
1473							}
1474						}
1475
1476						meta.is_empty() && Heads::<T>::get(&para_id).is_none()
1477					});
1478
1479					// This parachain has been removed and now the vestigial code
1480					// has been removed from the state. clean up meta as well.
1481					if full_deactivate {
1482						PastCodeMeta::<T>::remove(&para_id);
1483					}
1484				}
1485
1486				pruning_tasks_done as u64
1487			});
1488
1489		// 1 read for the meta for each pruning task, 1 read for the config
1490		// 2 writes: updating the meta and pruning the code
1491		T::DbWeight::get().reads_writes(1 + pruning_tasks_done, 2 * pruning_tasks_done)
1492	}
1493
1494	/// Process the future code upgrades that should be applied directly.
1495	///
1496	/// Upgrades that should not be applied directly are being processed in
1497	/// [`Self::process_scheduled_upgrade_changes`].
1498	fn process_future_code_upgrades_at(now: BlockNumberFor<T>) -> Weight {
1499		// account weight for `FutureCodeUpgradeAt::mutate`.
1500		let mut weight = T::DbWeight::get().reads_writes(1, 1);
1501		FutureCodeUpgradesAt::<T>::mutate(
1502			|upcoming_upgrades: &mut Vec<(ParaId, BlockNumberFor<T>)>| {
1503				let num = upcoming_upgrades.iter().take_while(|&(_, at)| at <= &now).count();
1504				for (id, expected_at) in upcoming_upgrades.drain(..num) {
1505					weight += T::DbWeight::get().reads_writes(1, 1);
1506
1507					// Both should always be `Some` in this case, since a code upgrade is scheduled.
1508					let new_code_hash = if let Some(new_code_hash) = FutureCodeHash::<T>::take(&id)
1509					{
1510						new_code_hash
1511					} else {
1512						log::error!(target: LOG_TARGET, "Missing future code hash for {:?}", &id);
1513						continue
1514					};
1515
1516					weight += Self::set_current_code(id, new_code_hash, expected_at);
1517				}
1518				num
1519			},
1520		);
1521
1522		weight
1523	}
1524
1525	/// Process the timers related to upgrades. Specifically, the upgrade go ahead signals toggle
1526	/// and the upgrade cooldown restrictions. However, this function does not actually unset
1527	/// the upgrade restriction, that will happen in the `initializer_finalize` function. However,
1528	/// this function does count the number of cooldown timers expired so that we can reserve weight
1529	/// for the `initializer_finalize` function.
1530	fn process_scheduled_upgrade_changes(now: BlockNumberFor<T>) -> Weight {
1531		// account weight for `UpcomingUpgrades::mutate`.
1532		let mut weight = T::DbWeight::get().reads_writes(1, 1);
1533		let upgrades_signaled = UpcomingUpgrades::<T>::mutate(
1534			|upcoming_upgrades: &mut Vec<(ParaId, BlockNumberFor<T>)>| {
1535				let num = upcoming_upgrades.iter().take_while(|&(_, at)| at <= &now).count();
1536				for (para, _) in upcoming_upgrades.drain(..num) {
1537					UpgradeGoAheadSignal::<T>::insert(&para, UpgradeGoAhead::GoAhead);
1538				}
1539				num
1540			},
1541		);
1542		weight += T::DbWeight::get().writes(upgrades_signaled as u64);
1543
1544		// account weight for `UpgradeCooldowns::get`.
1545		weight += T::DbWeight::get().reads(1);
1546		let cooldowns_expired =
1547			UpgradeCooldowns::<T>::get().iter().take_while(|&(_, at)| at <= &now).count();
1548
1549		// reserve weight for `initializer_finalize`:
1550		// - 1 read and 1 write for `UpgradeCooldowns::mutate`.
1551		// - 1 write per expired cooldown.
1552		weight += T::DbWeight::get().reads_writes(1, 1);
1553		weight += T::DbWeight::get().reads(cooldowns_expired as u64);
1554
1555		weight
1556	}
1557
1558	/// Actually perform unsetting the expired upgrade restrictions.
1559	///
1560	/// See `process_scheduled_upgrade_changes` for more details.
1561	fn process_scheduled_upgrade_cooldowns(now: BlockNumberFor<T>) {
1562		UpgradeCooldowns::<T>::mutate(
1563			|upgrade_cooldowns: &mut Vec<(ParaId, BlockNumberFor<T>)>| {
1564				// Remove all expired signals and also prune the cooldowns.
1565				upgrade_cooldowns.retain(|(para, at)| {
1566					if at <= &now {
1567						UpgradeRestrictionSignal::<T>::remove(&para);
1568						false
1569					} else {
1570						true
1571					}
1572				});
1573			},
1574		);
1575	}
1576
1577	/// Goes over all PVF votes in progress, reinitializes ballots, increments ages and prunes the
1578	/// active votes that reached their time-to-live.
1579	fn groom_ongoing_pvf_votes(
1580		cfg: &configuration::HostConfiguration<BlockNumberFor<T>>,
1581		new_n_validators: usize,
1582	) -> Weight {
1583		let mut weight = T::DbWeight::get().reads(1);
1584
1585		let potentially_active_votes = PvfActiveVoteList::<T>::get();
1586
1587		// Initially empty list which contains all the PVF active votes that made it through this
1588		// session change.
1589		//
1590		// **Ordered** as well as `PvfActiveVoteList`.
1591		let mut actually_active_votes = Vec::with_capacity(potentially_active_votes.len());
1592
1593		for vote_subject in potentially_active_votes {
1594			let mut vote_state = match PvfActiveVoteMap::<T>::take(&vote_subject) {
1595				Some(v) => v,
1596				None => {
1597					// This branch should never be reached. This is due to the fact that the set of
1598					// `PvfActiveVoteMap`'s keys is always equal to the set of items found in
1599					// `PvfActiveVoteList`.
1600					log::warn!(
1601						target: LOG_TARGET,
1602						"The PvfActiveVoteMap is out of sync with PvfActiveVoteList!",
1603					);
1604					debug_assert!(false);
1605					continue
1606				},
1607			};
1608
1609			vote_state.age += 1;
1610			if vote_state.age < cfg.pvf_voting_ttl {
1611				weight += T::DbWeight::get().writes(1);
1612				vote_state.reinitialize_ballots(new_n_validators);
1613				PvfActiveVoteMap::<T>::insert(&vote_subject, vote_state);
1614
1615				// push maintaining the original order.
1616				actually_active_votes.push(vote_subject);
1617			} else {
1618				// TTL is reached. Reject.
1619				weight += Self::enact_pvf_rejected(&vote_subject, vote_state.causes);
1620			}
1621		}
1622
1623		weight += T::DbWeight::get().writes(1);
1624		PvfActiveVoteList::<T>::put(actually_active_votes);
1625
1626		weight
1627	}
1628
1629	fn enact_pvf_accepted(
1630		now: BlockNumberFor<T>,
1631		code_hash: &ValidationCodeHash,
1632		causes: &[PvfCheckCause<BlockNumberFor<T>>],
1633		sessions_observed: SessionIndex,
1634		cfg: &configuration::HostConfiguration<BlockNumberFor<T>>,
1635	) -> Weight {
1636		let mut weight = Weight::zero();
1637		for cause in causes {
1638			weight += T::DbWeight::get().reads_writes(3, 2);
1639			Self::deposit_event(Event::PvfCheckAccepted(*code_hash, cause.para_id()));
1640
1641			match cause {
1642				PvfCheckCause::Onboarding(id) => {
1643					weight += Self::proceed_with_onboarding(*id, sessions_observed);
1644				},
1645				PvfCheckCause::Upgrade { id, included_at, upgrade_strategy } => {
1646					weight += Self::proceed_with_upgrade(
1647						*id,
1648						code_hash,
1649						now,
1650						*included_at,
1651						cfg,
1652						*upgrade_strategy,
1653					);
1654				},
1655			}
1656		}
1657		weight
1658	}
1659
1660	fn proceed_with_onboarding(id: ParaId, sessions_observed: SessionIndex) -> Weight {
1661		let weight = T::DbWeight::get().reads_writes(2, 1);
1662
1663		// we should onboard only after `SESSION_DELAY` sessions but we should take
1664		// into account the number of sessions the PVF pre-checking occupied.
1665		//
1666		// we cannot onboard at the current session, so it must be at least one
1667		// session ahead.
1668		let onboard_at: SessionIndex = shared::CurrentSessionIndex::<T>::get() +
1669			cmp::max(shared::SESSION_DELAY.saturating_sub(sessions_observed), 1);
1670
1671		ActionsQueue::<T>::mutate(onboard_at, |v| {
1672			if let Err(i) = v.binary_search(&id) {
1673				v.insert(i, id);
1674			}
1675		});
1676
1677		weight
1678	}
1679
1680	fn proceed_with_upgrade(
1681		id: ParaId,
1682		code_hash: &ValidationCodeHash,
1683		now: BlockNumberFor<T>,
1684		relay_parent_number: BlockNumberFor<T>,
1685		cfg: &configuration::HostConfiguration<BlockNumberFor<T>>,
1686		upgrade_strategy: UpgradeStrategy,
1687	) -> Weight {
1688		let mut weight = Weight::zero();
1689
1690		// Compute the relay-chain block number starting at which the code upgrade is ready to
1691		// be applied.
1692		//
1693		// The first parablock that has a relay-parent higher or at the same height of
1694		// `expected_at` will trigger the code upgrade. The parablock that comes after that will
1695		// be validated against the new validation code.
1696		//
1697		// Here we are trying to choose the block number that will have
1698		// `validation_upgrade_delay` blocks from the relay-parent of inclusion of the the block
1699		// that scheduled code upgrade but no less than `minimum_validation_upgrade_delay`. We
1700		// want this delay out of caution so that when the last vote for pre-checking comes the
1701		// parachain will have some time until the upgrade finally takes place.
1702		let expected_at = cmp::max(
1703			relay_parent_number + cfg.validation_upgrade_delay,
1704			now + cfg.minimum_validation_upgrade_delay,
1705		);
1706
1707		match upgrade_strategy {
1708			UpgradeStrategy::ApplyAtExpectedBlock => {
1709				FutureCodeUpgradesAt::<T>::mutate(|future_upgrades| {
1710					let insert_idx = future_upgrades
1711						.binary_search_by_key(&expected_at, |&(_, b)| b)
1712						.unwrap_or_else(|idx| idx);
1713					future_upgrades.insert(insert_idx, (id, expected_at));
1714				});
1715
1716				weight += T::DbWeight::get().reads_writes(0, 2);
1717			},
1718			UpgradeStrategy::SetGoAheadSignal => {
1719				FutureCodeUpgrades::<T>::insert(&id, expected_at);
1720
1721				UpcomingUpgrades::<T>::mutate(|upcoming_upgrades| {
1722					let insert_idx = upcoming_upgrades
1723						.binary_search_by_key(&expected_at, |&(_, b)| b)
1724						.unwrap_or_else(|idx| idx);
1725					upcoming_upgrades.insert(insert_idx, (id, expected_at));
1726				});
1727
1728				weight += T::DbWeight::get().reads_writes(1, 3);
1729			},
1730		}
1731
1732		let expected_at = expected_at.saturated_into();
1733		let log = ConsensusLog::ParaScheduleUpgradeCode(id, *code_hash, expected_at);
1734		frame_system::Pallet::<T>::deposit_log(log.into());
1735
1736		weight
1737	}
1738
1739	fn enact_pvf_rejected(
1740		code_hash: &ValidationCodeHash,
1741		causes: Vec<PvfCheckCause<BlockNumberFor<T>>>,
1742	) -> Weight {
1743		let mut weight = Weight::zero();
1744
1745		for cause in causes {
1746			// Whenever PVF pre-checking is started or a new cause is added to it, the RC is bumped.
1747			// Now we need to unbump it.
1748			weight += Self::decrease_code_ref(code_hash);
1749
1750			weight += T::DbWeight::get().reads_writes(3, 2);
1751			Self::deposit_event(Event::PvfCheckRejected(*code_hash, cause.para_id()));
1752
1753			match cause {
1754				PvfCheckCause::Onboarding(id) => {
1755					// Here we need to undo everything that was done during
1756					// `schedule_para_initialize`. Essentially, the logic is similar to offboarding,
1757					// with exception that before actual onboarding the parachain did not have a
1758					// chance to reach to upgrades. Therefore we can skip all the upgrade related
1759					// storage items here.
1760					weight += T::DbWeight::get().writes(3);
1761					UpcomingParasGenesis::<T>::remove(&id);
1762					CurrentCodeHash::<T>::remove(&id);
1763					ParaLifecycles::<T>::remove(&id);
1764				},
1765				PvfCheckCause::Upgrade { id, .. } => {
1766					weight += T::DbWeight::get().writes(2);
1767					UpgradeGoAheadSignal::<T>::insert(&id, UpgradeGoAhead::Abort);
1768					FutureCodeHash::<T>::remove(&id);
1769				},
1770			}
1771		}
1772
1773		weight
1774	}
1775
1776	/// Verify that `schedule_para_initialize` can be called successfully.
1777	///
1778	/// Returns false if para is already registered in the system.
1779	pub fn can_schedule_para_initialize(id: &ParaId) -> bool {
1780		ParaLifecycles::<T>::get(id).is_none()
1781	}
1782
1783	/// Schedule a para to be initialized. If the validation code is not already stored in the
1784	/// code storage, then a PVF pre-checking process will be initiated.
1785	///
1786	/// Only after the PVF pre-checking succeeds can the para be onboarded. Note, that calling this
1787	/// does not guarantee that the parachain will eventually be onboarded. This can happen in case
1788	/// the PVF does not pass PVF pre-checking.
1789	///
1790	/// The Para ID should be not activated in this pallet. The validation code supplied in
1791	/// `genesis_data` should not be empty. If those conditions are not met, then the para cannot
1792	/// be onboarded.
1793	pub(crate) fn schedule_para_initialize(
1794		id: ParaId,
1795		mut genesis_data: ParaGenesisArgs,
1796	) -> DispatchResult {
1797		// Make sure parachain isn't already in our system and that the onboarding parameters are
1798		// valid.
1799		ensure!(Self::can_schedule_para_initialize(&id), Error::<T>::CannotOnboard);
1800		ensure!(!genesis_data.validation_code.0.is_empty(), Error::<T>::CannotOnboard);
1801		ParaLifecycles::<T>::insert(&id, ParaLifecycle::Onboarding);
1802
1803		// HACK: here we are doing something nasty.
1804		//
1805		// In order to fix the [soaking issue] we insert the code eagerly here. When the onboarding
1806		// is finally enacted, we do not need to insert the code anymore. Therefore, there is no
1807		// reason for the validation code to be copied into the `ParaGenesisArgs`. We also do not
1808		// want to risk it by copying the validation code needlessly to not risk adding more
1809		// memory pressure.
1810		//
1811		// That said, we also want to preserve `ParaGenesisArgs` as it is, for now. There are two
1812		// reasons:
1813		//
1814		// - Doing it within the context of the PR that introduces this change is undesirable, since
1815		//   it is already a big change, and that change would require a migration. Moreover, if we
1816		//   run the new version of the runtime, there will be less things to worry about during the
1817		//   eventual proper migration.
1818		//
1819		// - This data type already is used for generating genesis, and changing it will probably
1820		//   introduce some unnecessary burden.
1821		//
1822		// So instead of going through it right now, we will do something sneaky. Specifically:
1823		//
1824		// - Insert the `CurrentCodeHash` now, instead during the onboarding. That would allow to
1825		//   get rid of hashing of the validation code when onboarding.
1826		//
1827		// - Replace `validation_code` with a sentinel value: an empty vector. This should be fine
1828		//   as long we do not allow registering parachains with empty code. At the moment of
1829		//   writing this should already be the case.
1830		//
1831		// - Empty value is treated as the current code is already inserted during the onboarding.
1832		//
1833		// This is only an intermediate solution and should be fixed in foreseeable future.
1834		//
1835		// [soaking issue]: https://github.com/paritytech/polkadot/issues/3918
1836		let validation_code =
1837			mem::replace(&mut genesis_data.validation_code, ValidationCode(Vec::new()));
1838		UpcomingParasGenesis::<T>::insert(&id, genesis_data);
1839		let validation_code_hash = validation_code.hash();
1840		CurrentCodeHash::<T>::insert(&id, validation_code_hash);
1841
1842		let cfg = configuration::ActiveConfig::<T>::get();
1843		Self::kick_off_pvf_check(
1844			PvfCheckCause::Onboarding(id),
1845			validation_code_hash,
1846			validation_code,
1847			&cfg,
1848		);
1849
1850		Ok(())
1851	}
1852
1853	/// Schedule a para to be cleaned up at the start of the next session.
1854	///
1855	/// Will return error if either is true:
1856	///
1857	/// - para is not a stable parachain (i.e. [`ParaLifecycle::is_stable`] is `false`)
1858	/// - para has a pending upgrade.
1859	/// - para has unprocessed messages in its UMP queue.
1860	///
1861	/// No-op if para is not registered at all.
1862	pub(crate) fn schedule_para_cleanup(id: ParaId) -> DispatchResult {
1863		// Disallow offboarding in case there is a PVF pre-checking in progress.
1864		//
1865		// This is not a fundamental limitation but rather simplification: it allows us to get
1866		// away without introducing additional logic for pruning and, more importantly, enacting
1867		// ongoing PVF pre-checking votes. It also removes some nasty edge cases.
1868		//
1869		// However, an upcoming upgrade on its own imposes no restrictions. An upgrade is enacted
1870		// with a new para head, so if a para never progresses we still should be able to offboard
1871		// it.
1872		//
1873		// This implicitly assumes that the given para exists, i.e. it's lifecycle != None.
1874		if let Some(future_code_hash) = FutureCodeHash::<T>::get(&id) {
1875			let active_prechecking = PvfActiveVoteList::<T>::get();
1876			if active_prechecking.contains(&future_code_hash) {
1877				return Err(Error::<T>::CannotOffboard.into())
1878			}
1879		}
1880
1881		let lifecycle = ParaLifecycles::<T>::get(&id);
1882		match lifecycle {
1883			// If para is not registered, nothing to do!
1884			None => return Ok(()),
1885			Some(ParaLifecycle::Parathread) => {
1886				ParaLifecycles::<T>::insert(&id, ParaLifecycle::OffboardingParathread);
1887			},
1888			Some(ParaLifecycle::Parachain) => {
1889				ParaLifecycles::<T>::insert(&id, ParaLifecycle::OffboardingParachain);
1890			},
1891			_ => return Err(Error::<T>::CannotOffboard.into()),
1892		}
1893
1894		let scheduled_session = Self::scheduled_session();
1895		ActionsQueue::<T>::mutate(scheduled_session, |v| {
1896			if let Err(i) = v.binary_search(&id) {
1897				v.insert(i, id);
1898			}
1899		});
1900
1901		if <T as Config>::QueueFootprinter::message_count(UmpQueueId::Para(id)) != 0 {
1902			return Err(Error::<T>::CannotOffboard.into())
1903		}
1904
1905		Ok(())
1906	}
1907
1908	/// Schedule a parathread (on-demand parachain) to be upgraded to a lease holding parachain.
1909	///
1910	/// Will return error if `ParaLifecycle` is not `Parathread`.
1911	pub(crate) fn schedule_parathread_upgrade(id: ParaId) -> DispatchResult {
1912		let scheduled_session = Self::scheduled_session();
1913		let lifecycle = ParaLifecycles::<T>::get(&id).ok_or(Error::<T>::NotRegistered)?;
1914
1915		ensure!(lifecycle == ParaLifecycle::Parathread, Error::<T>::CannotUpgrade);
1916
1917		ParaLifecycles::<T>::insert(&id, ParaLifecycle::UpgradingParathread);
1918		ActionsQueue::<T>::mutate(scheduled_session, |v| {
1919			if let Err(i) = v.binary_search(&id) {
1920				v.insert(i, id);
1921			}
1922		});
1923
1924		Ok(())
1925	}
1926
1927	/// Schedule a lease holding parachain to be downgraded to an on-demand parachain.
1928	///
1929	/// Noop if `ParaLifecycle` is not `Parachain`.
1930	pub(crate) fn schedule_parachain_downgrade(id: ParaId) -> DispatchResult {
1931		let scheduled_session = Self::scheduled_session();
1932		let lifecycle = ParaLifecycles::<T>::get(&id).ok_or(Error::<T>::NotRegistered)?;
1933
1934		ensure!(lifecycle == ParaLifecycle::Parachain, Error::<T>::CannotDowngrade);
1935
1936		ParaLifecycles::<T>::insert(&id, ParaLifecycle::DowngradingParachain);
1937		ActionsQueue::<T>::mutate(scheduled_session, |v| {
1938			if let Err(i) = v.binary_search(&id) {
1939				v.insert(i, id);
1940			}
1941		});
1942
1943		Ok(())
1944	}
1945
1946	/// Schedule a future code upgrade of the given parachain.
1947	///
1948	/// If the new code is not known, then the PVF pre-checking will be started for that validation
1949	/// code. In case the validation code does not pass the PVF pre-checking process, the
1950	/// upgrade will be aborted.
1951	///
1952	/// Only after the code is approved by the process, the upgrade can be scheduled. Specifically,
1953	/// the relay-chain block number will be determined at which the upgrade will take place. We
1954	/// call that block `expected_at`.
1955	///
1956	/// Once the candidate with the relay-parent >= `expected_at` is enacted, the new validation
1957	/// code will be applied. Therefore, the new code will be used to validate the next candidate.
1958	///
1959	/// The new code should not be equal to the current one, otherwise the upgrade will be aborted.
1960	/// If there is already a scheduled code upgrade for the para, this is a no-op.
1961	///
1962	/// Inclusion block number specifies relay parent which enacted candidate initiating the
1963	/// upgrade.
1964	pub(crate) fn schedule_code_upgrade(
1965		id: ParaId,
1966		new_code: ValidationCode,
1967		inclusion_block_number: BlockNumberFor<T>,
1968		cfg: &configuration::HostConfiguration<BlockNumberFor<T>>,
1969		upgrade_strategy: UpgradeStrategy,
1970	) {
1971		// Should be prevented by checks in `schedule_code_upgrade_external`
1972		let new_code_len = new_code.0.len();
1973		if new_code_len < MIN_CODE_SIZE as usize || new_code_len > cfg.max_code_size as usize {
1974			log::warn!(target: LOG_TARGET, "attempted to schedule an upgrade with invalid new validation code",);
1975			return
1976		}
1977
1978		// Enacting this should be prevented by the `can_upgrade_validation_code`
1979		if FutureCodeHash::<T>::contains_key(&id) {
1980			// This branch should never be reached. Signalling an upgrade is disallowed for a para
1981			// that already has one upgrade scheduled.
1982			//
1983			// Any candidate that attempts to do that should be rejected by
1984			// `can_upgrade_validation_code`.
1985			//
1986			// NOTE: we cannot set `UpgradeGoAheadSignal` signal here since this will be reset by
1987			//       the following call `note_new_head`
1988			log::warn!(target: LOG_TARGET, "ended up scheduling an upgrade while one is pending",);
1989			return
1990		}
1991
1992		let code_hash = new_code.hash();
1993
1994		// para signals an update to the same code? This does not make a lot of sense, so abort the
1995		// process right away.
1996		//
1997		// We do not want to allow this since it will mess with the code reference counting.
1998		if CurrentCodeHash::<T>::get(&id) == Some(code_hash) {
1999			// NOTE: we cannot set `UpgradeGoAheadSignal` signal here since this will be reset by
2000			//       the following call `note_new_head`
2001			log::warn!(
2002				target: LOG_TARGET,
2003				"para tried to upgrade to the same code. Abort the upgrade",
2004			);
2005			return
2006		}
2007
2008		// This is the start of the upgrade process. Prevent any further attempts at upgrading.
2009		FutureCodeHash::<T>::insert(&id, &code_hash);
2010		UpgradeRestrictionSignal::<T>::insert(&id, UpgradeRestriction::Present);
2011
2012		let next_possible_upgrade_at = inclusion_block_number + cfg.validation_upgrade_cooldown;
2013		UpgradeCooldowns::<T>::mutate(|upgrade_cooldowns| {
2014			let insert_idx = upgrade_cooldowns
2015				.binary_search_by_key(&next_possible_upgrade_at, |&(_, b)| b)
2016				.unwrap_or_else(|idx| idx);
2017			upgrade_cooldowns.insert(insert_idx, (id, next_possible_upgrade_at));
2018		});
2019
2020		Self::kick_off_pvf_check(
2021			PvfCheckCause::Upgrade { id, included_at: inclusion_block_number, upgrade_strategy },
2022			code_hash,
2023			new_code,
2024			cfg,
2025		);
2026	}
2027
2028	/// Makes sure that the given code hash has passed pre-checking.
2029	///
2030	/// If the given code hash has already passed pre-checking, then the approval happens
2031	/// immediately.
2032	///
2033	/// If the code is unknown, but the pre-checking for that PVF is already running then we perform
2034	/// "coalescing". We save the cause for this PVF pre-check request and just add it to the
2035	/// existing active PVF vote.
2036	///
2037	/// And finally, if the code is unknown and pre-checking is not running, we start the
2038	/// pre-checking process anew.
2039	///
2040	/// Unconditionally increases the reference count for the passed `code`.
2041	fn kick_off_pvf_check(
2042		cause: PvfCheckCause<BlockNumberFor<T>>,
2043		code_hash: ValidationCodeHash,
2044		code: ValidationCode,
2045		cfg: &configuration::HostConfiguration<BlockNumberFor<T>>,
2046	) -> Weight {
2047		let mut weight = Weight::zero();
2048
2049		weight += T::DbWeight::get().reads_writes(3, 2);
2050		Self::deposit_event(Event::PvfCheckStarted(code_hash, cause.para_id()));
2051
2052		weight += T::DbWeight::get().reads(1);
2053		match PvfActiveVoteMap::<T>::get(&code_hash) {
2054			None => {
2055				// We deliberately are using `CodeByHash` here instead of the `CodeByHashRefs`. This
2056				// is because the code may have been added by `add_trusted_validation_code`.
2057				let known_code = CodeByHash::<T>::contains_key(&code_hash);
2058				weight += T::DbWeight::get().reads(1);
2059
2060				if known_code {
2061					// The code is known and there is no active PVF vote for it meaning it is
2062					// already checked -- fast track the PVF checking into the accepted state.
2063					weight += T::DbWeight::get().reads(1);
2064					let now = frame_system::Pallet::<T>::block_number();
2065					weight += Self::enact_pvf_accepted(now, &code_hash, &[cause], 0, cfg);
2066				} else {
2067					// PVF is not being pre-checked and it is not known. Start a new pre-checking
2068					// process.
2069					weight += T::DbWeight::get().reads_writes(3, 2);
2070					let now = frame_system::Pallet::<T>::block_number();
2071					let n_validators = shared::ActiveValidatorKeys::<T>::get().len();
2072					PvfActiveVoteMap::<T>::insert(
2073						&code_hash,
2074						PvfCheckActiveVoteState::new(now, n_validators, cause),
2075					);
2076					PvfActiveVoteList::<T>::mutate(|l| {
2077						if let Err(idx) = l.binary_search(&code_hash) {
2078							l.insert(idx, code_hash);
2079						}
2080					});
2081				}
2082			},
2083			Some(mut vote_state) => {
2084				// Coalescing: the PVF is already being pre-checked so we just need to piggy back
2085				// on it.
2086				weight += T::DbWeight::get().writes(1);
2087				vote_state.causes.push(cause);
2088				PvfActiveVoteMap::<T>::insert(&code_hash, vote_state);
2089			},
2090		}
2091
2092		// We increase the code RC here in any case. Intuitively the parachain that requested this
2093		// action is now a user of that PVF.
2094		//
2095		// If the result of the pre-checking is reject, then we would decrease the RC for each
2096		// cause, including the current.
2097		//
2098		// If the result of the pre-checking is accept, then we do nothing to the RC because the PVF
2099		// will continue be used by the same users.
2100		//
2101		// If the PVF was fast-tracked (i.e. there is already non zero RC) and there is no
2102		// pre-checking, we also do not change the RC then.
2103		weight += Self::increase_code_ref(&code_hash, &code);
2104
2105		weight
2106	}
2107
2108	/// Note that a para has progressed to a new head, where the new head was executed in the
2109	/// context of a relay-chain block with given number. This will apply pending code upgrades
2110	/// based on the relay-parent block number provided.
2111	pub(crate) fn note_new_head(
2112		id: ParaId,
2113		new_head: HeadData,
2114		execution_context: BlockNumberFor<T>,
2115	) {
2116		Heads::<T>::insert(&id, &new_head);
2117		MostRecentContext::<T>::insert(&id, execution_context);
2118
2119		if let Some(expected_at) = FutureCodeUpgrades::<T>::get(&id) {
2120			if expected_at <= execution_context {
2121				FutureCodeUpgrades::<T>::remove(&id);
2122				UpgradeGoAheadSignal::<T>::remove(&id);
2123
2124				// Both should always be `Some` in this case, since a code upgrade is scheduled.
2125				let new_code_hash = if let Some(new_code_hash) = FutureCodeHash::<T>::take(&id) {
2126					new_code_hash
2127				} else {
2128					log::error!(target: LOG_TARGET, "Missing future code hash for {:?}", &id);
2129					return
2130				};
2131
2132				Self::set_current_code(id, new_code_hash, expected_at);
2133			}
2134		} else {
2135			// This means there is no upgrade scheduled.
2136			//
2137			// In case the upgrade was aborted by the relay-chain we should reset
2138			// the `Abort` signal.
2139			UpgradeGoAheadSignal::<T>::remove(&id);
2140		};
2141
2142		T::OnNewHead::on_new_head(id, &new_head);
2143	}
2144
2145	/// Set the current code for the given parachain.
2146	// `at` for para-triggered replacement is the block number of the relay-chain
2147	// block in whose context the parablock was executed
2148	// (i.e. number of `relay_parent` in the receipt)
2149	pub(crate) fn set_current_code(
2150		id: ParaId,
2151		new_code_hash: ValidationCodeHash,
2152		at: BlockNumberFor<T>,
2153	) -> Weight {
2154		let maybe_prior_code_hash = CurrentCodeHash::<T>::get(&id);
2155		CurrentCodeHash::<T>::insert(&id, &new_code_hash);
2156
2157		let log = ConsensusLog::ParaUpgradeCode(id, new_code_hash);
2158		<frame_system::Pallet<T>>::deposit_log(log.into());
2159
2160		// `now` is only used for registering pruning as part of `fn note_past_code`
2161		let now = <frame_system::Pallet<T>>::block_number();
2162
2163		let weight = if let Some(prior_code_hash) = maybe_prior_code_hash {
2164			Self::note_past_code(id, at, now, prior_code_hash)
2165		} else {
2166			log::error!(target: LOG_TARGET, "Missing prior code hash for para {:?}", &id);
2167			Weight::zero()
2168		};
2169
2170		weight + T::DbWeight::get().writes(1)
2171	}
2172
2173	/// Returns the list of PVFs (aka validation code) that require casting a vote by a validator in
2174	/// the active validator set.
2175	pub(crate) fn pvfs_require_precheck() -> Vec<ValidationCodeHash> {
2176		PvfActiveVoteList::<T>::get()
2177	}
2178
2179	/// Submits a given PVF check statement with corresponding signature as an unsigned transaction
2180	/// into the memory pool. Ultimately, that disseminates the transaction across the network.
2181	///
2182	/// This function expects an offchain context and cannot be callable from the on-chain logic.
2183	///
2184	/// The signature assumed to pertain to `stmt`.
2185	pub(crate) fn submit_pvf_check_statement(
2186		stmt: PvfCheckStatement,
2187		signature: ValidatorSignature,
2188	) {
2189		use frame_system::offchain::SubmitTransaction;
2190
2191		let xt = T::create_inherent(Call::include_pvf_check_statement { stmt, signature }.into());
2192		if let Err(e) = SubmitTransaction::<T, Call<T>>::submit_transaction(xt) {
2193			log::error!(target: LOG_TARGET, "Error submitting pvf check statement: {:?}", e,);
2194		}
2195	}
2196
2197	/// Returns the current lifecycle state of the para.
2198	pub fn lifecycle(id: ParaId) -> Option<ParaLifecycle> {
2199		ParaLifecycles::<T>::get(&id)
2200	}
2201
2202	/// Returns whether the given ID refers to a valid para.
2203	///
2204	/// Paras that are onboarding or offboarding are not included.
2205	pub fn is_valid_para(id: ParaId) -> bool {
2206		if let Some(state) = ParaLifecycles::<T>::get(&id) {
2207			!state.is_onboarding() && !state.is_offboarding()
2208		} else {
2209			false
2210		}
2211	}
2212
2213	/// Returns whether the given ID refers to a para that is offboarding.
2214	///
2215	/// An invalid or non-offboarding para ID will return `false`.
2216	pub fn is_offboarding(id: ParaId) -> bool {
2217		ParaLifecycles::<T>::get(&id).map_or(false, |state| state.is_offboarding())
2218	}
2219
2220	/// Whether a para ID corresponds to any live lease holding parachain.
2221	///
2222	/// Includes lease holding parachains which will downgrade to a on-demand parachains in the
2223	/// future.
2224	pub fn is_parachain(id: ParaId) -> bool {
2225		if let Some(state) = ParaLifecycles::<T>::get(&id) {
2226			state.is_parachain()
2227		} else {
2228			false
2229		}
2230	}
2231
2232	/// Whether a para ID corresponds to any live parathread (on-demand parachain).
2233	///
2234	/// Includes on-demand parachains which will upgrade to lease holding parachains in the future.
2235	pub fn is_parathread(id: ParaId) -> bool {
2236		if let Some(state) = ParaLifecycles::<T>::get(&id) {
2237			state.is_parathread()
2238		} else {
2239			false
2240		}
2241	}
2242
2243	/// If a candidate from the specified parachain were submitted at the current block, this
2244	/// function returns if that candidate passes the acceptance criteria.
2245	pub(crate) fn can_upgrade_validation_code(id: ParaId) -> bool {
2246		FutureCodeHash::<T>::get(&id).is_none() && UpgradeRestrictionSignal::<T>::get(&id).is_none()
2247	}
2248
2249	/// Return the session index that should be used for any future scheduled changes.
2250	fn scheduled_session() -> SessionIndex {
2251		shared::Pallet::<T>::scheduled_session()
2252	}
2253
2254	/// Store the validation code if not already stored, and increase the number of reference.
2255	///
2256	/// Returns the weight consumed.
2257	fn increase_code_ref(code_hash: &ValidationCodeHash, code: &ValidationCode) -> Weight {
2258		let mut weight = T::DbWeight::get().reads_writes(1, 1);
2259		CodeByHashRefs::<T>::mutate(code_hash, |refs| {
2260			if *refs == 0 {
2261				weight += T::DbWeight::get().writes(1);
2262				CodeByHash::<T>::insert(code_hash, code);
2263			}
2264			*refs += 1;
2265		});
2266		weight
2267	}
2268
2269	/// Decrease the number of reference of the validation code and remove it from storage if zero
2270	/// is reached.
2271	///
2272	/// Returns the weight consumed.
2273	fn decrease_code_ref(code_hash: &ValidationCodeHash) -> Weight {
2274		let mut weight = T::DbWeight::get().reads(1);
2275		let refs = CodeByHashRefs::<T>::get(code_hash);
2276		if refs == 0 {
2277			log::error!(target: LOG_TARGET, "Code refs is already zero for {:?}", code_hash);
2278			return weight
2279		}
2280		if refs <= 1 {
2281			weight += T::DbWeight::get().writes(2);
2282			CodeByHash::<T>::remove(code_hash);
2283			CodeByHashRefs::<T>::remove(code_hash);
2284		} else {
2285			weight += T::DbWeight::get().writes(1);
2286			CodeByHashRefs::<T>::insert(code_hash, refs - 1);
2287		}
2288		weight
2289	}
2290
2291	/// Test function for triggering a new session in this pallet.
2292	#[cfg(any(feature = "std", feature = "runtime-benchmarks", test))]
2293	pub fn test_on_new_session() {
2294		Self::initializer_on_new_session(&SessionChangeNotification {
2295			session_index: shared::CurrentSessionIndex::<T>::get(),
2296			..Default::default()
2297		});
2298	}
2299
2300	#[cfg(any(feature = "runtime-benchmarks", test))]
2301	pub fn heads_insert(para_id: &ParaId, head_data: HeadData) {
2302		Heads::<T>::insert(para_id, head_data);
2303	}
2304
2305	/// A low-level function to eagerly initialize a given para.
2306	pub(crate) fn initialize_para_now(
2307		parachains: &mut ParachainsCache<T>,
2308		id: ParaId,
2309		genesis_data: &ParaGenesisArgs,
2310	) {
2311		match genesis_data.para_kind {
2312			ParaKind::Parachain => {
2313				parachains.add(id);
2314				ParaLifecycles::<T>::insert(&id, ParaLifecycle::Parachain);
2315			},
2316			ParaKind::Parathread => ParaLifecycles::<T>::insert(&id, ParaLifecycle::Parathread),
2317		}
2318
2319		// HACK: see the notice in `schedule_para_initialize`.
2320		//
2321		// Apparently, this is left over from a prior version of the runtime.
2322		// To handle this we just insert the code and link the current code hash
2323		// to it.
2324		if !genesis_data.validation_code.0.is_empty() {
2325			let code_hash = genesis_data.validation_code.hash();
2326			Self::increase_code_ref(&code_hash, &genesis_data.validation_code);
2327			CurrentCodeHash::<T>::insert(&id, code_hash);
2328		}
2329
2330		Heads::<T>::insert(&id, &genesis_data.genesis_head);
2331		MostRecentContext::<T>::insert(&id, BlockNumberFor::<T>::from(0u32));
2332	}
2333
2334	#[cfg(test)]
2335	pub(crate) fn active_vote_state(
2336		code_hash: &ValidationCodeHash,
2337	) -> Option<PvfCheckActiveVoteState<BlockNumberFor<T>>> {
2338		PvfActiveVoteMap::<T>::get(code_hash)
2339	}
2340}
2341
2342/// An overlay over the `Parachains` storage entry that provides a convenient interface for adding
2343/// or removing parachains in bulk.
2344pub(crate) struct ParachainsCache<T: Config> {
2345	// `None` here means the parachains list has not been accessed yet, nevermind modified.
2346	parachains: Option<BTreeSet<ParaId>>,
2347	_config: PhantomData<T>,
2348}
2349
2350impl<T: Config> ParachainsCache<T> {
2351	pub fn new() -> Self {
2352		Self { parachains: None, _config: PhantomData }
2353	}
2354
2355	fn ensure_initialized(&mut self) -> &mut BTreeSet<ParaId> {
2356		self.parachains
2357			.get_or_insert_with(|| Parachains::<T>::get().into_iter().collect())
2358	}
2359
2360	/// Adds the given para id to the list.
2361	pub fn add(&mut self, id: ParaId) {
2362		let parachains = self.ensure_initialized();
2363		parachains.insert(id);
2364	}
2365
2366	/// Removes the given para id from the list of parachains. Does nothing if the id is not in the
2367	/// list.
2368	pub fn remove(&mut self, id: ParaId) {
2369		let parachains = self.ensure_initialized();
2370		parachains.remove(&id);
2371	}
2372}
2373
2374impl<T: Config> Drop for ParachainsCache<T> {
2375	fn drop(&mut self) {
2376		if let Some(parachains) = self.parachains.take() {
2377			Parachains::<T>::put(parachains.into_iter().collect::<Vec<ParaId>>());
2378		}
2379	}
2380}