referrerpolicy=no-referrer-when-downgrade

polkadot_runtime_parachains/inclusion/
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 inclusion pallet is responsible for inclusion and availability of scheduled parachains.
18//!
19//! It is responsible for carrying candidates from being backable to being backed, and then from
20//! backed to included.
21
22use crate::{
23	configuration::{self, HostConfiguration},
24	disputes, dmp, hrmp,
25	paras::{self, UpgradeStrategy},
26	scheduler,
27	shared::{self, AllowedRelayParentsTracker},
28	util::make_persisted_validation_data_with_parent,
29};
30use alloc::{
31	collections::{btree_map::BTreeMap, btree_set::BTreeSet, vec_deque::VecDeque},
32	vec,
33	vec::Vec,
34};
35use bitvec::{order::Lsb0 as BitOrderLsb0, vec::BitVec};
36use codec::{Decode, DecodeWithMemTracking, Encode};
37use core::fmt;
38use frame_support::{
39	defensive,
40	pallet_prelude::*,
41	traits::{EnqueueMessage, Footprint, QueueFootprint, QueueFootprintQuery},
42	BoundedSlice,
43};
44use frame_system::pallet_prelude::*;
45use pallet_message_queue::OnQueueChanged;
46use polkadot_primitives::{
47	effective_minimum_backing_votes, skip_ump_signals, supermajority_threshold, well_known_keys,
48	BackedCandidate, CandidateCommitments, CandidateDescriptorV2 as CandidateDescriptor,
49	CandidateHash, CandidateReceiptV2 as CandidateReceipt,
50	CommittedCandidateReceiptV2 as CommittedCandidateReceipt, CoreIndex, GroupIndex, HeadData,
51	Id as ParaId, SignedAvailabilityBitfields, SigningContext, UpwardMessage, ValidatorId,
52	ValidatorIndex, ValidityAttestation,
53};
54use scale_info::TypeInfo;
55use sp_runtime::{traits::One, DispatchError, SaturatedConversion, Saturating};
56
57pub use pallet::*;
58
59#[cfg(test)]
60pub(crate) mod tests;
61
62#[cfg(feature = "runtime-benchmarks")]
63mod benchmarking;
64
65pub mod migration;
66
67pub trait WeightInfo {
68	/// Weight for `enact_candidate` extrinsic given the number of sent messages
69	/// (ump, hrmp) and whether there is a new code for a runtime upgrade.
70	///
71	/// NOTE: due to a shortcoming of the current benchmarking framework,
72	/// we use `u32` for the code upgrade, even though it is a `bool`.
73	fn enact_candidate(u: u32, h: u32, c: u32) -> Weight;
74}
75
76pub struct TestWeightInfo;
77impl WeightInfo for TestWeightInfo {
78	fn enact_candidate(_u: u32, _h: u32, _c: u32) -> Weight {
79		Weight::zero()
80	}
81}
82
83impl WeightInfo for () {
84	fn enact_candidate(_u: u32, _h: u32, _c: u32) -> Weight {
85		Weight::zero()
86	}
87}
88
89/// Maximum value that `config.max_upward_message_size` can be set to.
90///
91/// This is used for benchmarking sanely bounding relevant storage items. It is expected from the
92/// `configuration` pallet to check these values before setting.
93pub const MAX_UPWARD_MESSAGE_SIZE_BOUND: u32 = 128 * 1024;
94
95/// A backed candidate pending availability.
96#[derive(Encode, Decode, PartialEq, TypeInfo, Clone)]
97#[cfg_attr(test, derive(Debug))]
98pub struct CandidatePendingAvailability<H, N> {
99	/// The availability core this is assigned to.
100	core: CoreIndex,
101	/// The candidate hash.
102	hash: CandidateHash,
103	/// The candidate descriptor.
104	descriptor: CandidateDescriptor<H>,
105	/// The candidate commitments.
106	commitments: CandidateCommitments,
107	/// The received availability votes. One bit per validator.
108	availability_votes: BitVec<u8, BitOrderLsb0>,
109	/// The backers of the candidate pending availability.
110	backers: BitVec<u8, BitOrderLsb0>,
111	/// The block number of the relay-parent of the receipt.
112	relay_parent_number: N,
113	/// The block number of the relay-chain block this was backed in.
114	backed_in_number: N,
115	/// The group index backing this block.
116	backing_group: GroupIndex,
117}
118
119impl<H, N> CandidatePendingAvailability<H, N> {
120	/// Get the availability votes on the candidate.
121	pub(crate) fn availability_votes(&self) -> &BitVec<u8, BitOrderLsb0> {
122		&self.availability_votes
123	}
124
125	/// Get the relay-chain block number this was backed in.
126	pub(crate) fn backed_in_number(&self) -> N
127	where
128		N: Clone,
129	{
130		self.backed_in_number.clone()
131	}
132
133	/// Get the core index.
134	pub(crate) fn core_occupied(&self) -> CoreIndex {
135		self.core
136	}
137
138	/// Get the candidate hash.
139	pub(crate) fn candidate_hash(&self) -> CandidateHash {
140		self.hash
141	}
142
143	/// Get the candidate descriptor.
144	pub(crate) fn candidate_descriptor(&self) -> &CandidateDescriptor<H> {
145		&self.descriptor
146	}
147
148	/// Get the candidate commitments.
149	pub(crate) fn candidate_commitments(&self) -> &CandidateCommitments {
150		&self.commitments
151	}
152
153	/// Get the candidate's relay parent's number.
154	pub(crate) fn relay_parent_number(&self) -> N
155	where
156		N: Clone,
157	{
158		self.relay_parent_number.clone()
159	}
160
161	#[cfg(any(feature = "runtime-benchmarks", test))]
162	pub(crate) fn new(
163		core: CoreIndex,
164		hash: CandidateHash,
165		descriptor: CandidateDescriptor<H>,
166		commitments: CandidateCommitments,
167		availability_votes: BitVec<u8, BitOrderLsb0>,
168		backers: BitVec<u8, BitOrderLsb0>,
169		relay_parent_number: N,
170		backed_in_number: N,
171		backing_group: GroupIndex,
172	) -> Self {
173		Self {
174			core,
175			hash,
176			descriptor,
177			commitments,
178			availability_votes,
179			backers,
180			relay_parent_number,
181			backed_in_number,
182			backing_group,
183		}
184	}
185}
186
187/// A hook for applying validator rewards
188pub trait RewardValidators {
189	// Reward the validators with the given indices for issuing backing statements.
190	fn reward_backing(validators: impl IntoIterator<Item = ValidatorIndex>);
191	// Reward the validators with the given indices for issuing availability bitfields.
192	// Validators are sent to this hook when they have contributed to the availability
193	// of a candidate by setting a bit in their bitfield.
194	fn reward_bitfields(validators: impl IntoIterator<Item = ValidatorIndex>);
195}
196
197impl RewardValidators for () {
198	fn reward_backing(_: impl IntoIterator<Item = ValidatorIndex>) {}
199	fn reward_bitfields(_: impl IntoIterator<Item = ValidatorIndex>) {}
200}
201
202/// Reads the footprint of queues for a specific origin type.
203pub trait QueueFootprinter {
204	type Origin;
205
206	fn message_count(origin: Self::Origin) -> u64;
207}
208
209impl QueueFootprinter for () {
210	type Origin = UmpQueueId;
211
212	fn message_count(_: Self::Origin) -> u64 {
213		0
214	}
215}
216
217/// Aggregate message origin for the `MessageQueue` pallet.
218///
219/// Can be extended to serve further use-cases besides just UMP. Is stored in storage, so any change
220/// to existing values will require a migration.
221#[derive(
222	Encode,
223	Decode,
224	DecodeWithMemTracking,
225	Clone,
226	MaxEncodedLen,
227	Eq,
228	PartialEq,
229	RuntimeDebug,
230	TypeInfo,
231)]
232pub enum AggregateMessageOrigin {
233	/// Inbound upward message.
234	#[codec(index = 0)]
235	Ump(UmpQueueId),
236}
237
238/// Identifies a UMP queue inside the `MessageQueue` pallet.
239///
240/// It is written in verbose form since future variants like `Here` and `Bridged` are already
241/// foreseeable.
242#[derive(
243	Encode,
244	Decode,
245	DecodeWithMemTracking,
246	Clone,
247	MaxEncodedLen,
248	Eq,
249	PartialEq,
250	RuntimeDebug,
251	TypeInfo,
252)]
253pub enum UmpQueueId {
254	/// The message originated from this parachain.
255	#[codec(index = 0)]
256	Para(ParaId),
257}
258
259#[cfg(feature = "runtime-benchmarks")]
260impl From<u32> for AggregateMessageOrigin {
261	fn from(n: u32) -> Self {
262		// Some dummy for the benchmarks.
263		Self::Ump(UmpQueueId::Para(n.into()))
264	}
265}
266
267/// The maximal length of a UMP message.
268pub type MaxUmpMessageLenOf<T> =
269	<<T as Config>::MessageQueue as EnqueueMessage<AggregateMessageOrigin>>::MaxMessageLen;
270
271#[frame_support::pallet]
272pub mod pallet {
273	use super::*;
274
275	const STORAGE_VERSION: StorageVersion = StorageVersion::new(1);
276	#[pallet::pallet]
277	#[pallet::without_storage_info]
278	#[pallet::storage_version(STORAGE_VERSION)]
279	pub struct Pallet<T>(_);
280
281	#[pallet::config]
282	pub trait Config:
283		frame_system::Config
284		+ shared::Config
285		+ paras::Config
286		+ dmp::Config
287		+ hrmp::Config
288		+ configuration::Config
289		+ scheduler::Config
290	{
291		#[allow(deprecated)]
292		type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
293		type DisputesHandler: disputes::DisputesHandler<BlockNumberFor<Self>>;
294		type RewardValidators: RewardValidators;
295
296		/// The system message queue.
297		///
298		/// The message queue provides general queueing and processing functionality. Currently it
299		/// replaces the old `UMP` dispatch queue. Other use-cases can be implemented as well by
300		/// adding new variants to `AggregateMessageOrigin`.
301		type MessageQueue: EnqueueMessage<AggregateMessageOrigin>
302			+ QueueFootprintQuery<AggregateMessageOrigin, MaxMessageLen = MaxUmpMessageLenOf<Self>>;
303
304		/// Weight info for the calls of this pallet.
305		type WeightInfo: WeightInfo;
306	}
307
308	#[pallet::event]
309	#[pallet::generate_deposit(pub(super) fn deposit_event)]
310	pub enum Event<T: Config> {
311		/// A candidate was backed. `[candidate, head_data]`
312		CandidateBacked(CandidateReceipt<T::Hash>, HeadData, CoreIndex, GroupIndex),
313		/// A candidate was included. `[candidate, head_data]`
314		CandidateIncluded(CandidateReceipt<T::Hash>, HeadData, CoreIndex, GroupIndex),
315		/// A candidate timed out. `[candidate, head_data]`
316		CandidateTimedOut(CandidateReceipt<T::Hash>, HeadData, CoreIndex),
317		/// Some upward messages have been received and will be processed.
318		UpwardMessagesReceived { from: ParaId, count: u32 },
319	}
320
321	#[pallet::error]
322	pub enum Error<T> {
323		/// Validator index out of bounds.
324		ValidatorIndexOutOfBounds,
325		/// Candidate submitted but para not scheduled.
326		UnscheduledCandidate,
327		/// Head data exceeds the configured maximum.
328		HeadDataTooLarge,
329		/// Code upgrade prematurely.
330		PrematureCodeUpgrade,
331		/// Output code is too large
332		NewCodeTooLarge,
333		/// The candidate's relay-parent was not allowed. Either it was
334		/// not recent enough or it didn't advance based on the last parachain block.
335		DisallowedRelayParent,
336		/// Failed to compute group index for the core: either it's out of bounds
337		/// or the relay parent doesn't belong to the current session.
338		InvalidAssignment,
339		/// Invalid group index in core assignment.
340		InvalidGroupIndex,
341		/// Insufficient (non-majority) backing.
342		InsufficientBacking,
343		/// Invalid (bad signature, unknown validator, etc.) backing.
344		InvalidBacking,
345		/// The validation data hash does not match expected.
346		ValidationDataHashMismatch,
347		/// The downward message queue is not processed correctly.
348		IncorrectDownwardMessageHandling,
349		/// At least one upward message sent does not pass the acceptance criteria.
350		InvalidUpwardMessages,
351		/// The candidate didn't follow the rules of HRMP watermark advancement.
352		HrmpWatermarkMishandling,
353		/// The HRMP messages sent by the candidate is not valid.
354		InvalidOutboundHrmp,
355		/// The validation code hash of the candidate is not valid.
356		InvalidValidationCodeHash,
357		/// The `para_head` hash in the candidate descriptor doesn't match the hash of the actual
358		/// para head in the commitments.
359		ParaHeadMismatch,
360	}
361
362	/// Candidates pending availability by `ParaId`. They form a chain starting from the latest
363	/// included head of the para.
364	/// Use a different prefix post-migration to v1, since the v0 `PendingAvailability` storage
365	/// would otherwise have the exact same prefix which could cause undefined behaviour when doing
366	/// the migration.
367	#[pallet::storage]
368	#[pallet::storage_prefix = "V1"]
369	pub(crate) type PendingAvailability<T: Config> = StorageMap<
370		_,
371		Twox64Concat,
372		ParaId,
373		VecDeque<CandidatePendingAvailability<T::Hash, BlockNumberFor<T>>>,
374	>;
375
376	#[pallet::call]
377	impl<T: Config> Pallet<T> {}
378}
379
380const LOG_TARGET: &str = "runtime::inclusion";
381
382/// The reason that a candidate's outputs were rejected for.
383#[derive(Debug)]
384enum AcceptanceCheckErr {
385	HeadDataTooLarge,
386	/// Code upgrades are not permitted at the current time.
387	PrematureCodeUpgrade,
388	/// The new runtime blob is too large.
389	NewCodeTooLarge,
390	/// The candidate violated this DMP acceptance criteria.
391	ProcessedDownwardMessages,
392	/// The candidate violated this UMP acceptance criteria.
393	UpwardMessages,
394	/// The candidate violated this HRMP watermark acceptance criteria.
395	HrmpWatermark,
396	/// The candidate violated this outbound HRMP acceptance criteria.
397	OutboundHrmp,
398}
399
400impl From<dmp::ProcessedDownwardMessagesAcceptanceErr> for AcceptanceCheckErr {
401	fn from(_: dmp::ProcessedDownwardMessagesAcceptanceErr) -> Self {
402		Self::ProcessedDownwardMessages
403	}
404}
405
406impl From<UmpAcceptanceCheckErr> for AcceptanceCheckErr {
407	fn from(_: UmpAcceptanceCheckErr) -> Self {
408		Self::UpwardMessages
409	}
410}
411
412impl<BlockNumber> From<hrmp::HrmpWatermarkAcceptanceErr<BlockNumber>> for AcceptanceCheckErr {
413	fn from(_: hrmp::HrmpWatermarkAcceptanceErr<BlockNumber>) -> Self {
414		Self::HrmpWatermark
415	}
416}
417
418impl From<hrmp::OutboundHrmpAcceptanceErr> for AcceptanceCheckErr {
419	fn from(_: hrmp::OutboundHrmpAcceptanceErr) -> Self {
420		Self::OutboundHrmp
421	}
422}
423
424/// An error returned by [`Pallet::check_upward_messages`] that indicates a violation of one of
425/// acceptance criteria rules.
426#[cfg_attr(test, derive(PartialEq))]
427#[allow(dead_code)]
428pub(crate) enum UmpAcceptanceCheckErr {
429	/// The maximal number of messages that can be submitted in one batch was exceeded.
430	MoreMessagesThanPermitted { sent: u32, permitted: u32 },
431	/// The maximal size of a single message was exceeded.
432	MessageSize { idx: u32, msg_size: u32, max_size: u32 },
433	/// The allowed number of messages in the queue was exceeded.
434	CapacityExceeded { count: u64, limit: u64 },
435	/// The allowed combined message size in the queue was exceeded.
436	TotalSizeExceeded { total_size: u64, limit: u64 },
437	/// A para-chain cannot send UMP messages while it is offboarding.
438	IsOffboarding,
439}
440
441impl fmt::Debug for UmpAcceptanceCheckErr {
442	fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
443		match *self {
444			UmpAcceptanceCheckErr::MoreMessagesThanPermitted { sent, permitted } => write!(
445				fmt,
446				"more upward messages than permitted by config ({} > {})",
447				sent, permitted,
448			),
449			UmpAcceptanceCheckErr::MessageSize { idx, msg_size, max_size } => write!(
450				fmt,
451				"upward message idx {} larger than permitted by config ({} > {})",
452				idx, msg_size, max_size,
453			),
454			UmpAcceptanceCheckErr::CapacityExceeded { count, limit } => write!(
455				fmt,
456				"the ump queue would have more items than permitted by config ({} > {})",
457				count, limit,
458			),
459			UmpAcceptanceCheckErr::TotalSizeExceeded { total_size, limit } => write!(
460				fmt,
461				"the ump queue would have grown past the max size permitted by config ({} > {})",
462				total_size, limit,
463			),
464			UmpAcceptanceCheckErr::IsOffboarding => {
465				write!(fmt, "upward message rejected because the para is off-boarding")
466			},
467		}
468	}
469}
470
471impl<T: Config> Pallet<T> {
472	/// Block initialization logic, called by initializer.
473	pub(crate) fn initializer_initialize(_now: BlockNumberFor<T>) -> Weight {
474		Weight::zero()
475	}
476
477	/// Block finalization logic, called by initializer.
478	pub(crate) fn initializer_finalize() {}
479
480	/// Handle an incoming session change.
481	pub(crate) fn initializer_on_new_session(
482		_notification: &crate::initializer::SessionChangeNotification<BlockNumberFor<T>>,
483		outgoing_paras: &[ParaId],
484	) {
485		// unlike most drain methods, drained elements are not cleared on `Drop` of the iterator
486		// and require consumption.
487		for _ in PendingAvailability::<T>::drain() {}
488
489		Self::cleanup_outgoing_ump_dispatch_queues(outgoing_paras);
490	}
491
492	pub(crate) fn cleanup_outgoing_ump_dispatch_queues(outgoing: &[ParaId]) {
493		for outgoing_para in outgoing {
494			Self::cleanup_outgoing_ump_dispatch_queue(*outgoing_para);
495		}
496	}
497
498	pub(crate) fn cleanup_outgoing_ump_dispatch_queue(para: ParaId) {
499		T::MessageQueue::sweep_queue(AggregateMessageOrigin::Ump(UmpQueueId::Para(para)));
500	}
501
502	pub(crate) fn get_occupied_cores(
503	) -> impl Iterator<Item = (CoreIndex, CandidatePendingAvailability<T::Hash, BlockNumberFor<T>>)>
504	{
505		PendingAvailability::<T>::iter_values().flat_map(|pending_candidates| {
506			pending_candidates.into_iter().map(|c| (c.core, c.clone()))
507		})
508	}
509
510	/// Extract the freed cores based on cores that became available.
511	///
512	/// Bitfields are expected to have been sanitized already. E.g. via `sanitize_bitfields`!
513	///
514	/// Updates storage items `PendingAvailability`.
515	///
516	/// Returns a `Vec` of `CandidateHash`es and their respective `AvailabilityCore`s that became
517	/// available, and cores free.
518	pub(crate) fn update_pending_availability_and_get_freed_cores(
519		validators: &[ValidatorId],
520		signed_bitfields: SignedAvailabilityBitfields,
521	) -> (Weight, Vec<(CoreIndex, CandidateHash)>) {
522		let threshold = availability_threshold(validators.len());
523
524		let mut votes_per_core: BTreeMap<CoreIndex, BTreeSet<ValidatorIndex>> = BTreeMap::new();
525
526		for (checked_bitfield, validator_index) in
527			signed_bitfields.into_iter().map(|signed_bitfield| {
528				let validator_idx = signed_bitfield.validator_index();
529				let checked_bitfield = signed_bitfield.into_payload();
530				(checked_bitfield, validator_idx)
531			}) {
532			for (bit_idx, _) in checked_bitfield.0.iter().enumerate().filter(|(_, is_av)| **is_av) {
533				let core_index = CoreIndex(bit_idx as u32);
534				votes_per_core
535					.entry(core_index)
536					.or_insert_with(|| BTreeSet::new())
537					.insert(validator_index);
538			}
539		}
540
541		let mut freed_cores = vec![];
542		let mut weight = Weight::zero();
543
544		let pending_paraids: Vec<_> = PendingAvailability::<T>::iter_keys().collect();
545		for paraid in pending_paraids {
546			PendingAvailability::<T>::mutate(paraid, |candidates| {
547				if let Some(candidates) = candidates {
548					let mut last_enacted_index: Option<usize> = None;
549
550					for (candidate_index, candidate) in candidates.iter_mut().enumerate() {
551						if let Some(validator_indices) = votes_per_core.remove(&candidate.core) {
552							for validator_index in validator_indices.iter() {
553								// defensive check - this is constructed by loading the
554								// availability bitfield record, which is always `Some` if
555								// the core is occupied - that's why we're here.
556								if let Some(mut bit) =
557									candidate.availability_votes.get_mut(validator_index.0 as usize)
558								{
559									*bit = true;
560								}
561							}
562						}
563
564						// We check for the candidate's availability even if we didn't get any new
565						// bitfields for its core, as it may have already been available at a
566						// previous block but wasn't enacted due to its predecessors not being
567						// available.
568						if candidate.availability_votes.count_ones() >= threshold {
569							// We can only enact a candidate if we've enacted all of its
570							// predecessors already.
571							let can_enact = if candidate_index == 0 {
572								last_enacted_index == None
573							} else {
574								let prev_candidate_index = usize::try_from(candidate_index - 1)
575									.expect("Previous `if` would have caught a 0 candidate index.");
576								matches!(last_enacted_index, Some(old_index) if old_index == prev_candidate_index)
577							};
578
579							if can_enact {
580								last_enacted_index = Some(candidate_index);
581							}
582						}
583					}
584
585					// Trim the pending availability candidates storage and enact candidates of this
586					// para now.
587					if let Some(last_enacted_index) = last_enacted_index {
588						let evicted_candidates = candidates.drain(0..=last_enacted_index);
589						for candidate in evicted_candidates {
590							freed_cores.push((candidate.core, candidate.hash));
591
592							let receipt = CommittedCandidateReceipt {
593								descriptor: candidate.descriptor,
594								commitments: candidate.commitments,
595							};
596
597							let has_runtime_upgrade =
598								receipt.commitments.new_validation_code.as_ref().map_or(0, |_| 1);
599							let u = receipt.commitments.upward_messages.len() as u32;
600							let h = receipt.commitments.horizontal_messages.len() as u32;
601							let enact_weight = <T as Config>::WeightInfo::enact_candidate(
602								u,
603								h,
604								has_runtime_upgrade,
605							);
606							Self::enact_candidate(
607								candidate.relay_parent_number,
608								receipt,
609								candidate.backers,
610								candidate.availability_votes,
611								candidate.core,
612								candidate.backing_group,
613							);
614							weight.saturating_accrue(enact_weight);
615						}
616					}
617				}
618			});
619		}
620		// For relay chain blocks, we're (ab)using the proof size
621		// to limit the raw transaction size of `ParaInherent` and
622		// there's no state proof (aka PoV) associated with it.
623		// Since we already accounted for bitfields size, we should
624		// not include `enact_candidate` PoV impact here.
625		(weight.set_proof_size(0), freed_cores)
626	}
627
628	/// Process candidates that have been backed. Provide a set of
629	/// candidates along with their scheduled cores.
630	///
631	/// Candidates of the same paraid should be sorted according to their dependency order (they
632	/// should form a chain). If this condition is not met, this function will return an error.
633	/// (This really should not happen here, if the candidates were properly sanitised in
634	/// paras_inherent).
635	pub(crate) fn process_candidates<GV>(
636		allowed_relay_parents: &AllowedRelayParentsTracker<T::Hash, BlockNumberFor<T>>,
637		candidates: &BTreeMap<ParaId, Vec<(BackedCandidate<T::Hash>, CoreIndex)>>,
638		group_validators: GV,
639	) -> Result<
640		Vec<(CandidateReceipt<T::Hash>, Vec<(ValidatorIndex, ValidityAttestation)>)>,
641		DispatchError,
642	>
643	where
644		GV: Fn(GroupIndex) -> Option<Vec<ValidatorIndex>>,
645	{
646		if candidates.is_empty() {
647			return Ok(Default::default())
648		}
649
650		let now = frame_system::Pallet::<T>::block_number();
651		let validators = shared::ActiveValidatorKeys::<T>::get();
652
653		// Collect candidate receipts with backers.
654		let mut candidate_receipt_with_backing_validator_indices =
655			Vec::with_capacity(candidates.len());
656
657		for (para_id, para_candidates) in candidates {
658			let mut latest_head_data = match Self::para_latest_head_data(para_id) {
659				None => {
660					defensive!("Latest included head data for paraid {:?} is None", para_id);
661					continue
662				},
663				Some(latest_head_data) => latest_head_data,
664			};
665
666			for (candidate, core) in para_candidates.iter() {
667				let candidate_hash = candidate.candidate().hash();
668
669				// The previous context is None, as it's already checked during candidate
670				// sanitization.
671				let check_ctx = CandidateCheckContext::<T>::new(None);
672				let relay_parent_number = check_ctx.verify_backed_candidate(
673					&allowed_relay_parents,
674					candidate.candidate(),
675					latest_head_data.clone(),
676				)?;
677
678				// The candidate based upon relay parent `N` should be backed by a
679				// group assigned to core at block `N + 1`. Thus,
680				// `relay_parent_number + 1` will always land in the current
681				// session.
682				let group_idx = scheduler::Pallet::<T>::group_assigned_to_core(
683					*core,
684					relay_parent_number + One::one(),
685				)
686				.ok_or_else(|| {
687					log::warn!(
688						target: LOG_TARGET,
689						"Failed to compute group index for candidate {:?}",
690						candidate_hash
691					);
692					Error::<T>::InvalidAssignment
693				})?;
694				let group_vals =
695					group_validators(group_idx).ok_or_else(|| Error::<T>::InvalidGroupIndex)?;
696
697				// Check backing vote count and validity.
698				let (backers, backer_idx_and_attestation) =
699					Self::check_backing_votes(candidate, &validators, group_vals)?;
700
701				// Found a valid candidate.
702				latest_head_data = candidate.candidate().commitments.head_data.clone();
703				candidate_receipt_with_backing_validator_indices
704					.push((candidate.receipt(), backer_idx_and_attestation));
705
706				// Update storage now
707				PendingAvailability::<T>::mutate(&para_id, |pending_availability| {
708					let new_candidate = CandidatePendingAvailability {
709						core: *core,
710						hash: candidate_hash,
711						descriptor: candidate.candidate().descriptor.clone(),
712						commitments: candidate.candidate().commitments.clone(),
713						// initialize all availability votes to 0.
714						availability_votes: bitvec::bitvec![u8, BitOrderLsb0; 0; validators.len()],
715						relay_parent_number,
716						backers: backers.to_bitvec(),
717						backed_in_number: now,
718						backing_group: group_idx,
719					};
720
721					if let Some(pending_availability) = pending_availability {
722						pending_availability.push_back(new_candidate);
723					} else {
724						*pending_availability =
725							Some([new_candidate].into_iter().collect::<VecDeque<_>>())
726					}
727				});
728
729				// Deposit backed event.
730				Self::deposit_event(Event::<T>::CandidateBacked(
731					candidate.candidate().to_plain(),
732					candidate.candidate().commitments.head_data.clone(),
733					*core,
734					group_idx,
735				));
736			}
737		}
738
739		Ok(candidate_receipt_with_backing_validator_indices)
740	}
741
742	// Get the latest backed output head data of this para (including pending availability).
743	pub(crate) fn para_latest_head_data(para_id: &ParaId) -> Option<HeadData> {
744		match PendingAvailability::<T>::get(para_id).and_then(|pending_candidates| {
745			pending_candidates.back().map(|x| x.commitments.head_data.clone())
746		}) {
747			Some(head_data) => Some(head_data),
748			None => paras::Heads::<T>::get(para_id),
749		}
750	}
751
752	// Get the relay parent number of the most recent candidate (including pending availability).
753	pub(crate) fn para_most_recent_context(para_id: &ParaId) -> Option<BlockNumberFor<T>> {
754		match PendingAvailability::<T>::get(para_id)
755			.and_then(|pending_candidates| pending_candidates.back().map(|x| x.relay_parent_number))
756		{
757			Some(relay_parent_number) => Some(relay_parent_number),
758			None => paras::MostRecentContext::<T>::get(para_id),
759		}
760	}
761
762	fn check_backing_votes(
763		backed_candidate: &BackedCandidate<T::Hash>,
764		validators: &[ValidatorId],
765		group_vals: Vec<ValidatorIndex>,
766	) -> Result<(BitVec<u8, BitOrderLsb0>, Vec<(ValidatorIndex, ValidityAttestation)>), Error<T>> {
767		let minimum_backing_votes = configuration::ActiveConfig::<T>::get().minimum_backing_votes;
768
769		let mut backers = bitvec::bitvec![u8, BitOrderLsb0; 0; validators.len()];
770		let signing_context = SigningContext {
771			parent_hash: backed_candidate.descriptor().relay_parent(),
772			session_index: shared::CurrentSessionIndex::<T>::get(),
773		};
774
775		let (validator_indices, _) = backed_candidate.validator_indices_and_core_index();
776
777		// check the signatures in the backing and that it is a majority.
778		let maybe_amount_validated = polkadot_primitives::check_candidate_backing(
779			backed_candidate.candidate().hash(),
780			backed_candidate.validity_votes(),
781			validator_indices,
782			&signing_context,
783			group_vals.len(),
784			|intra_group_vi| {
785				group_vals
786					.get(intra_group_vi)
787					.and_then(|vi| validators.get(vi.0 as usize))
788					.map(|v| v.clone())
789			},
790		);
791
792		match maybe_amount_validated {
793			Ok(amount_validated) => ensure!(
794				amount_validated >=
795					effective_minimum_backing_votes(group_vals.len(), minimum_backing_votes),
796				Error::<T>::InsufficientBacking,
797			),
798			Err(()) => {
799				Err(Error::<T>::InvalidBacking)?;
800			},
801		}
802
803		let mut backer_idx_and_attestation =
804			Vec::<(ValidatorIndex, ValidityAttestation)>::with_capacity(
805				validator_indices.count_ones(),
806			);
807
808		for ((bit_idx, _), attestation) in validator_indices
809			.iter()
810			.enumerate()
811			.filter(|(_, signed)| **signed)
812			.zip(backed_candidate.validity_votes().iter().cloned())
813		{
814			let val_idx = group_vals.get(bit_idx).expect("this query succeeded above; qed");
815			backer_idx_and_attestation.push((*val_idx, attestation));
816
817			backers.set(val_idx.0 as _, true);
818		}
819
820		Ok((backers, backer_idx_and_attestation))
821	}
822
823	/// Run the acceptance criteria checks on the given candidate commitments.
824	pub(crate) fn check_validation_outputs_for_runtime_api(
825		para_id: ParaId,
826		relay_parent_number: BlockNumberFor<T>,
827		validation_outputs: polkadot_primitives::CandidateCommitments,
828	) -> bool {
829		let prev_context = Self::para_most_recent_context(&para_id);
830		let check_ctx = CandidateCheckContext::<T>::new(prev_context);
831
832		if let Err(err) = check_ctx.check_validation_outputs(
833			para_id,
834			relay_parent_number,
835			&validation_outputs.head_data,
836			&validation_outputs.new_validation_code,
837			validation_outputs.processed_downward_messages,
838			&validation_outputs.upward_messages,
839			BlockNumberFor::<T>::from(validation_outputs.hrmp_watermark),
840			&validation_outputs.horizontal_messages,
841		) {
842			log::debug!(
843				target: LOG_TARGET,
844				"Validation outputs checking for parachain `{}` failed, error: {:?}",
845				u32::from(para_id), err
846			);
847			false
848		} else {
849			true
850		}
851	}
852
853	fn enact_candidate(
854		relay_parent_number: BlockNumberFor<T>,
855		receipt: CommittedCandidateReceipt<T::Hash>,
856		backers: BitVec<u8, BitOrderLsb0>,
857		availability_votes: BitVec<u8, BitOrderLsb0>,
858		core_index: CoreIndex,
859		backing_group: GroupIndex,
860	) {
861		let plain = receipt.to_plain();
862		let commitments = receipt.commitments;
863		let config = configuration::ActiveConfig::<T>::get();
864
865		T::RewardValidators::reward_backing(
866			backers
867				.iter()
868				.enumerate()
869				.filter(|(_, backed)| **backed)
870				.map(|(i, _)| ValidatorIndex(i as _)),
871		);
872
873		T::RewardValidators::reward_bitfields(
874			availability_votes
875				.iter()
876				.enumerate()
877				.filter(|(_, voted)| **voted)
878				.map(|(i, _)| ValidatorIndex(i as _)),
879		);
880
881		if let Some(new_code) = commitments.new_validation_code {
882			// Block number of candidate's inclusion.
883			let now = frame_system::Pallet::<T>::block_number();
884
885			paras::Pallet::<T>::schedule_code_upgrade(
886				receipt.descriptor.para_id(),
887				new_code,
888				now,
889				&config,
890				UpgradeStrategy::SetGoAheadSignal,
891			);
892		}
893
894		// enact the messaging facet of the candidate.
895		dmp::Pallet::<T>::prune_dmq(
896			receipt.descriptor.para_id(),
897			commitments.processed_downward_messages,
898		);
899		Self::receive_upward_messages(
900			receipt.descriptor.para_id(),
901			commitments.upward_messages.as_slice(),
902		);
903		hrmp::Pallet::<T>::prune_hrmp(
904			receipt.descriptor.para_id(),
905			BlockNumberFor::<T>::from(commitments.hrmp_watermark),
906		);
907		hrmp::Pallet::<T>::queue_outbound_hrmp(
908			receipt.descriptor.para_id(),
909			commitments.horizontal_messages,
910		);
911
912		Self::deposit_event(Event::<T>::CandidateIncluded(
913			plain,
914			commitments.head_data.clone(),
915			core_index,
916			backing_group,
917		));
918
919		paras::Pallet::<T>::note_new_head(
920			receipt.descriptor.para_id(),
921			commitments.head_data,
922			relay_parent_number,
923		);
924	}
925
926	pub(crate) fn relay_dispatch_queue_size(para_id: ParaId) -> (u32, u32) {
927		let fp = T::MessageQueue::footprint(AggregateMessageOrigin::Ump(UmpQueueId::Para(para_id)));
928		(fp.storage.count as u32, fp.storage.size as u32)
929	}
930
931	/// Check that all the upward messages sent by a candidate pass the acceptance criteria.
932	pub(crate) fn check_upward_messages(
933		config: &HostConfiguration<BlockNumberFor<T>>,
934		para: ParaId,
935		upward_messages: &[UpwardMessage],
936	) -> Result<(), UmpAcceptanceCheckErr> {
937		// Filter any pending UMP signals and the separator.
938		let upward_messages = skip_ump_signals(upward_messages.iter()).collect::<Vec<_>>();
939
940		// Cannot send UMP messages while off-boarding.
941		if paras::Pallet::<T>::is_offboarding(para) {
942			ensure!(upward_messages.is_empty(), UmpAcceptanceCheckErr::IsOffboarding);
943		}
944
945		let additional_msgs = upward_messages.len() as u32;
946		if additional_msgs > config.max_upward_message_num_per_candidate {
947			return Err(UmpAcceptanceCheckErr::MoreMessagesThanPermitted {
948				sent: additional_msgs,
949				permitted: config.max_upward_message_num_per_candidate,
950			})
951		}
952
953		let (para_queue_count, mut para_queue_size) = Self::relay_dispatch_queue_size(para);
954
955		if para_queue_count.saturating_add(additional_msgs) > config.max_upward_queue_count {
956			return Err(UmpAcceptanceCheckErr::CapacityExceeded {
957				count: para_queue_count.saturating_add(additional_msgs).into(),
958				limit: config.max_upward_queue_count.into(),
959			})
960		}
961
962		for (idx, msg) in upward_messages.into_iter().enumerate() {
963			let msg_size = msg.len() as u32;
964			if msg_size > config.max_upward_message_size {
965				return Err(UmpAcceptanceCheckErr::MessageSize {
966					idx: idx as u32,
967					msg_size,
968					max_size: config.max_upward_message_size,
969				})
970			}
971			// make sure that the queue is not overfilled.
972			// we do it here only once since returning false invalidates the whole relay-chain
973			// block.
974			if para_queue_size.saturating_add(msg_size) > config.max_upward_queue_size {
975				return Err(UmpAcceptanceCheckErr::TotalSizeExceeded {
976					total_size: para_queue_size.saturating_add(msg_size).into(),
977					limit: config.max_upward_queue_size.into(),
978				})
979			}
980			para_queue_size.saturating_accrue(msg_size);
981		}
982
983		Ok(())
984	}
985
986	/// Enqueues `upward_messages` from a `para`'s accepted candidate block.
987	///
988	/// This function is infallible since the candidate was already accepted and we therefore need
989	/// to deal with the messages as given. Messages that are too long will be ignored since such
990	/// candidates should have already been rejected in [`Self::check_upward_messages`].
991	pub(crate) fn receive_upward_messages(para: ParaId, upward_messages: &[Vec<u8>]) {
992		let bounded = skip_ump_signals(upward_messages.iter())
993			.filter_map(|d| {
994				BoundedSlice::try_from(&d[..])
995					.inspect_err(|_| {
996						defensive!("Accepted candidate contains too long msg, len=", d.len());
997					})
998					.ok()
999			})
1000			.collect();
1001		Self::receive_bounded_upward_messages(para, bounded)
1002	}
1003
1004	/// Enqueues storage-bounded `upward_messages` from a `para`'s accepted candidate block.
1005	pub(crate) fn receive_bounded_upward_messages(
1006		para: ParaId,
1007		messages: Vec<BoundedSlice<'_, u8, MaxUmpMessageLenOf<T>>>,
1008	) {
1009		let count = messages.len() as u32;
1010		if count == 0 {
1011			return
1012		}
1013
1014		T::MessageQueue::enqueue_messages(
1015			messages.into_iter(),
1016			AggregateMessageOrigin::Ump(UmpQueueId::Para(para)),
1017		);
1018		Self::deposit_event(Event::UpwardMessagesReceived { from: para, count });
1019	}
1020
1021	/// Cleans up all timed out candidates as well as their descendant candidates.
1022	///
1023	/// Returns a vector of cleaned-up core IDs.
1024	pub(crate) fn free_timedout() -> Vec<CoreIndex> {
1025		let timeout_pred = scheduler::Pallet::<T>::availability_timeout_predicate();
1026
1027		let timed_out: Vec<_> = Self::free_failed_cores(
1028			|candidate| timeout_pred(candidate.backed_in_number).timed_out,
1029			None,
1030		)
1031		.collect();
1032
1033		let mut timed_out_cores = Vec::with_capacity(timed_out.len());
1034		for candidate in timed_out.iter() {
1035			timed_out_cores.push(candidate.core);
1036
1037			let receipt = CandidateReceipt {
1038				descriptor: candidate.descriptor.clone(),
1039				commitments_hash: candidate.commitments.hash(),
1040			};
1041
1042			Self::deposit_event(Event::<T>::CandidateTimedOut(
1043				receipt,
1044				candidate.commitments.head_data.clone(),
1045				candidate.core,
1046			));
1047		}
1048
1049		timed_out_cores
1050	}
1051
1052	/// Cleans up all cores pending availability occupied by one of the disputed candidates or which
1053	/// are descendants of a disputed candidate.
1054	///
1055	/// Returns a vector of cleaned-up core IDs, along with the evicted candidate hashes.
1056	pub(crate) fn free_disputed(
1057		disputed: &BTreeSet<CandidateHash>,
1058	) -> Vec<(CoreIndex, CandidateHash)> {
1059		Self::free_failed_cores(
1060			|candidate| disputed.contains(&candidate.hash),
1061			Some(disputed.len()),
1062		)
1063		.map(|candidate| (candidate.core, candidate.hash))
1064		.collect()
1065	}
1066
1067	// Clean up cores whose candidates are deemed as failed by the predicate. `pred` returns true if
1068	// a candidate is considered failed.
1069	// A failed candidate also frees all subsequent cores which hold descendants of said candidate.
1070	fn free_failed_cores<
1071		P: Fn(&CandidatePendingAvailability<T::Hash, BlockNumberFor<T>>) -> bool,
1072	>(
1073		pred: P,
1074		capacity_hint: Option<usize>,
1075	) -> impl Iterator<Item = CandidatePendingAvailability<T::Hash, BlockNumberFor<T>>> {
1076		let mut earliest_dropped_indices: BTreeMap<ParaId, usize> = BTreeMap::new();
1077
1078		for (para_id, pending_candidates) in PendingAvailability::<T>::iter() {
1079			// We assume that pending candidates are stored in dependency order. So we need to store
1080			// the earliest dropped candidate. All others that follow will get freed as well.
1081			let mut earliest_dropped_idx = None;
1082			for (index, candidate) in pending_candidates.iter().enumerate() {
1083				if pred(candidate) {
1084					earliest_dropped_idx = Some(index);
1085					// Since we're looping the candidates in dependency order, we've found the
1086					// earliest failed index for this paraid.
1087					break;
1088				}
1089			}
1090
1091			if let Some(earliest_dropped_idx) = earliest_dropped_idx {
1092				earliest_dropped_indices.insert(para_id, earliest_dropped_idx);
1093			}
1094		}
1095
1096		let mut cleaned_up_cores =
1097			if let Some(capacity) = capacity_hint { Vec::with_capacity(capacity) } else { vec![] };
1098
1099		for (para_id, earliest_dropped_idx) in earliest_dropped_indices {
1100			// Do cleanups and record the cleaned up cores
1101			PendingAvailability::<T>::mutate(&para_id, |record| {
1102				if let Some(record) = record {
1103					let cleaned_up = record.drain(earliest_dropped_idx..);
1104					cleaned_up_cores.extend(cleaned_up);
1105				}
1106			});
1107		}
1108
1109		cleaned_up_cores.into_iter()
1110	}
1111
1112	/// Forcibly enact the pending candidates of the given paraid as though they had been deemed
1113	/// available by bitfields.
1114	///
1115	/// Is a no-op if there is no candidate pending availability for this para-id.
1116	/// If there are multiple candidates pending availability for this para-id, it will enact all of
1117	/// them. This should generally not be used but it is useful during execution of Runtime APIs,
1118	/// where the changes to the state are expected to be discarded directly after.
1119	pub(crate) fn force_enact(para: ParaId) {
1120		PendingAvailability::<T>::mutate(&para, |candidates| {
1121			if let Some(candidates) = candidates {
1122				for candidate in candidates.drain(..) {
1123					let receipt = CommittedCandidateReceipt {
1124						descriptor: candidate.descriptor,
1125						commitments: candidate.commitments,
1126					};
1127
1128					Self::enact_candidate(
1129						candidate.relay_parent_number,
1130						receipt,
1131						candidate.backers,
1132						candidate.availability_votes,
1133						candidate.core,
1134						candidate.backing_group,
1135					);
1136				}
1137			}
1138		});
1139	}
1140
1141	/// Returns the first `CommittedCandidateReceipt` pending availability for the para provided, if
1142	/// any.
1143	/// A para_id could have more than one candidates pending availability, if it's using elastic
1144	/// scaling. These candidates form a chain. This function returns the first in the chain.
1145	pub(crate) fn first_candidate_pending_availability(
1146		para: ParaId,
1147	) -> Option<CommittedCandidateReceipt<T::Hash>> {
1148		PendingAvailability::<T>::get(&para).and_then(|p| {
1149			p.get(0).map(|p| CommittedCandidateReceipt {
1150				descriptor: p.descriptor.clone(),
1151				commitments: p.commitments.clone(),
1152			})
1153		})
1154	}
1155
1156	/// Returns all the `CommittedCandidateReceipt` pending availability for the para provided, if
1157	/// any.
1158	pub(crate) fn candidates_pending_availability(
1159		para: ParaId,
1160	) -> Vec<CommittedCandidateReceipt<T::Hash>> {
1161		<PendingAvailability<T>>::get(&para)
1162			.map(|candidates| {
1163				candidates
1164					.into_iter()
1165					.map(|candidate| CommittedCandidateReceipt {
1166						descriptor: candidate.descriptor.clone(),
1167						commitments: candidate.commitments.clone(),
1168					})
1169					.collect()
1170			})
1171			.unwrap_or_default()
1172	}
1173}
1174
1175const fn availability_threshold(n_validators: usize) -> usize {
1176	supermajority_threshold(n_validators)
1177}
1178
1179impl AcceptanceCheckErr {
1180	/// Returns the same error so that it can be threaded through a needle of `DispatchError` and
1181	/// ultimately returned from a `Dispatchable`.
1182	fn strip_into_dispatch_err<T: Config>(self) -> Error<T> {
1183		use AcceptanceCheckErr::*;
1184		match self {
1185			HeadDataTooLarge => Error::<T>::HeadDataTooLarge,
1186			PrematureCodeUpgrade => Error::<T>::PrematureCodeUpgrade,
1187			NewCodeTooLarge => Error::<T>::NewCodeTooLarge,
1188			ProcessedDownwardMessages => Error::<T>::IncorrectDownwardMessageHandling,
1189			UpwardMessages => Error::<T>::InvalidUpwardMessages,
1190			HrmpWatermark => Error::<T>::HrmpWatermarkMishandling,
1191			OutboundHrmp => Error::<T>::InvalidOutboundHrmp,
1192		}
1193	}
1194}
1195
1196impl<T: Config> OnQueueChanged<AggregateMessageOrigin> for Pallet<T> {
1197	// Write back the remaining queue capacity into `relay_dispatch_queue_remaining_capacity`.
1198	fn on_queue_changed(origin: AggregateMessageOrigin, fp: QueueFootprint) {
1199		let para = match origin {
1200			AggregateMessageOrigin::Ump(UmpQueueId::Para(p)) => p,
1201		};
1202		let QueueFootprint { storage: Footprint { count, size }, .. } = fp;
1203		let (count, size) = (count.saturated_into(), size.saturated_into());
1204		// TODO paritytech/polkadot#6283: Remove all usages of `relay_dispatch_queue_size`
1205		#[allow(deprecated)]
1206		well_known_keys::relay_dispatch_queue_size_typed(para).set((count, size));
1207
1208		let config = configuration::ActiveConfig::<T>::get();
1209		let remaining_count = config.max_upward_queue_count.saturating_sub(count);
1210		let remaining_size = config.max_upward_queue_size.saturating_sub(size);
1211		well_known_keys::relay_dispatch_queue_remaining_capacity(para)
1212			.set((remaining_count, remaining_size));
1213	}
1214}
1215
1216/// A collection of data required for checking a candidate.
1217pub(crate) struct CandidateCheckContext<T: Config> {
1218	config: configuration::HostConfiguration<BlockNumberFor<T>>,
1219	prev_context: Option<BlockNumberFor<T>>,
1220}
1221
1222impl<T: Config> CandidateCheckContext<T> {
1223	pub(crate) fn new(prev_context: Option<BlockNumberFor<T>>) -> Self {
1224		Self { config: configuration::ActiveConfig::<T>::get(), prev_context }
1225	}
1226
1227	/// Execute verification of the candidate.
1228	///
1229	/// Assures:
1230	///  * relay-parent in-bounds
1231	///  * code hash of commitments matches current code hash
1232	///  * para head in the descriptor and commitments match
1233	///
1234	/// Returns the relay-parent block number.
1235	pub(crate) fn verify_backed_candidate(
1236		&self,
1237		allowed_relay_parents: &AllowedRelayParentsTracker<T::Hash, BlockNumberFor<T>>,
1238		backed_candidate_receipt: &CommittedCandidateReceipt<<T as frame_system::Config>::Hash>,
1239		parent_head_data: HeadData,
1240	) -> Result<BlockNumberFor<T>, Error<T>> {
1241		let para_id = backed_candidate_receipt.descriptor.para_id();
1242		let relay_parent = backed_candidate_receipt.descriptor.relay_parent();
1243
1244		// Check that the relay-parent is one of the allowed relay-parents.
1245		let (state_root, relay_parent_number) = {
1246			match allowed_relay_parents.acquire_info(relay_parent, self.prev_context) {
1247				None => return Err(Error::<T>::DisallowedRelayParent),
1248				Some((info, relay_parent_number)) => (info.state_root, relay_parent_number),
1249			}
1250		};
1251
1252		{
1253			let persisted_validation_data = make_persisted_validation_data_with_parent::<T>(
1254				relay_parent_number,
1255				state_root,
1256				parent_head_data,
1257			);
1258
1259			let expected = persisted_validation_data.hash();
1260
1261			ensure!(
1262				expected == backed_candidate_receipt.descriptor.persisted_validation_data_hash(),
1263				Error::<T>::ValidationDataHashMismatch,
1264			);
1265		}
1266
1267		let validation_code_hash = paras::CurrentCodeHash::<T>::get(para_id)
1268			// A candidate for a parachain without current validation code is not scheduled.
1269			.ok_or_else(|| Error::<T>::UnscheduledCandidate)?;
1270		ensure!(
1271			backed_candidate_receipt.descriptor.validation_code_hash() == validation_code_hash,
1272			Error::<T>::InvalidValidationCodeHash,
1273		);
1274
1275		ensure!(
1276			backed_candidate_receipt.descriptor.para_head() ==
1277				backed_candidate_receipt.commitments.head_data.hash(),
1278			Error::<T>::ParaHeadMismatch,
1279		);
1280
1281		if let Err(err) = self.check_validation_outputs(
1282			para_id,
1283			relay_parent_number,
1284			&backed_candidate_receipt.commitments.head_data,
1285			&backed_candidate_receipt.commitments.new_validation_code,
1286			backed_candidate_receipt.commitments.processed_downward_messages,
1287			&backed_candidate_receipt.commitments.upward_messages,
1288			BlockNumberFor::<T>::from(backed_candidate_receipt.commitments.hrmp_watermark),
1289			&backed_candidate_receipt.commitments.horizontal_messages,
1290		) {
1291			log::debug!(
1292				target: LOG_TARGET,
1293				"Validation outputs checking during inclusion of a candidate {:?} for parachain `{}` failed, error: {:?}",
1294				backed_candidate_receipt.hash(),
1295				u32::from(para_id),
1296				err
1297			);
1298			Err(err.strip_into_dispatch_err::<T>())?;
1299		};
1300		Ok(relay_parent_number)
1301	}
1302
1303	/// Check the given outputs after candidate validation on whether it passes the acceptance
1304	/// criteria.
1305	///
1306	/// The things that are checked can be roughly divided into limits and minimums.
1307	///
1308	/// Limits are things like max message queue sizes and max head data size.
1309	///
1310	/// Minimums are things like the minimum amount of messages that must be processed
1311	/// by the parachain block.
1312	///
1313	/// Limits are checked against the current state. The parachain block must be acceptable
1314	/// by the current relay-chain state regardless of whether it was acceptable at some relay-chain
1315	/// state in the past.
1316	///
1317	/// Minimums are checked against the current state but modulated by
1318	/// considering the information available at the relay-parent of the parachain block.
1319	fn check_validation_outputs(
1320		&self,
1321		para_id: ParaId,
1322		relay_parent_number: BlockNumberFor<T>,
1323		head_data: &HeadData,
1324		new_validation_code: &Option<polkadot_primitives::ValidationCode>,
1325		processed_downward_messages: u32,
1326		upward_messages: &[polkadot_primitives::UpwardMessage],
1327		hrmp_watermark: BlockNumberFor<T>,
1328		horizontal_messages: &[polkadot_primitives::OutboundHrmpMessage<ParaId>],
1329	) -> Result<(), AcceptanceCheckErr> {
1330		// Safe convertions when `self.config.max_head_data_size` is in bounds of `usize` type.
1331		let max_head_data_size = usize::try_from(self.config.max_head_data_size)
1332			.map_err(|_| AcceptanceCheckErr::HeadDataTooLarge)?;
1333		ensure!(head_data.0.len() <= max_head_data_size, AcceptanceCheckErr::HeadDataTooLarge);
1334
1335		// if any, the code upgrade attempt is allowed.
1336		if let Some(new_validation_code) = new_validation_code {
1337			// Safe convertions when `self.config.max_code_size` is in bounds of `usize` type.
1338			let max_code_size = usize::try_from(self.config.max_code_size)
1339				.map_err(|_| AcceptanceCheckErr::NewCodeTooLarge)?;
1340
1341			ensure!(
1342				paras::Pallet::<T>::can_upgrade_validation_code(para_id),
1343				AcceptanceCheckErr::PrematureCodeUpgrade,
1344			);
1345			ensure!(
1346				new_validation_code.0.len() <= max_code_size,
1347				AcceptanceCheckErr::NewCodeTooLarge,
1348			);
1349		}
1350
1351		// check if the candidate passes the messaging acceptance criteria
1352		dmp::Pallet::<T>::check_processed_downward_messages(
1353			para_id,
1354			relay_parent_number,
1355			processed_downward_messages,
1356		)
1357		.map_err(|e| {
1358			log::debug!(
1359				target: LOG_TARGET,
1360				"Check processed downward messages for parachain `{}` on relay parent number `{:?}` failed, error: {:?}",
1361				u32::from(para_id),
1362				relay_parent_number,
1363				e
1364			);
1365			e
1366		})?;
1367		Pallet::<T>::check_upward_messages(&self.config, para_id, upward_messages).map_err(
1368			|e| {
1369				log::debug!(
1370					target: LOG_TARGET,
1371					"Check upward messages for parachain `{}` failed, error: {:?}",
1372					u32::from(para_id),
1373					e
1374				);
1375				e
1376			},
1377		)?;
1378		hrmp::Pallet::<T>::check_hrmp_watermark(para_id, relay_parent_number, hrmp_watermark)
1379			.map_err(|e| {
1380				log::debug!(
1381					target: LOG_TARGET,
1382					"Check hrmp watermark for parachain `{}` on relay parent number `{:?}` failed, error: {:?}",
1383					u32::from(para_id),
1384					relay_parent_number,
1385					e
1386				);
1387				e
1388			})?;
1389		hrmp::Pallet::<T>::check_outbound_hrmp(&self.config, para_id, horizontal_messages)
1390			.map_err(|e| {
1391				log::debug!(
1392					target: LOG_TARGET,
1393					"Check outbound hrmp for parachain `{}` failed, error: {:?}",
1394					u32::from(para_id),
1395					e
1396				);
1397				e
1398			})?;
1399
1400		Ok(())
1401	}
1402}
1403
1404impl<T: Config> QueueFootprinter for Pallet<T> {
1405	type Origin = UmpQueueId;
1406
1407	fn message_count(origin: Self::Origin) -> u64 {
1408		T::MessageQueue::footprint(AggregateMessageOrigin::Ump(origin)).storage.count
1409	}
1410}