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