referrerpolicy=no-referrer-when-downgrade

polkadot_parachain_primitives/
primitives.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//! Primitive types which are strictly necessary from a parachain-execution point
18//! of view.
19
20use alloc::vec::Vec;
21
22use bounded_collections::{BoundedVec, ConstU32};
23use codec::{CompactAs, Decode, DecodeWithMemTracking, Encode, MaxEncodedLen};
24use scale_info::TypeInfo;
25use serde::{Deserialize, Serialize};
26use sp_core::{bytes, TypeId};
27use sp_runtime::traits::Hash as _;
28use sp_weights::Weight;
29
30use polkadot_core_primitives::{Hash, OutboundHrmpMessage};
31
32/// Block number type used by the relay chain.
33pub use polkadot_core_primitives::BlockNumber as RelayChainBlockNumber;
34
35/// Parachain head data included in the chain.
36#[derive(
37	PartialEq,
38	Eq,
39	Clone,
40	PartialOrd,
41	Ord,
42	Encode,
43	Decode,
44	DecodeWithMemTracking,
45	derive_more::From,
46	TypeInfo,
47	Serialize,
48	Deserialize,
49)]
50#[cfg_attr(feature = "std", derive(Hash, Default))]
51pub struct HeadData(#[serde(with = "bytes")] pub Vec<u8>);
52
53impl core::fmt::Debug for HeadData {
54	fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
55		write!(f, "HeadData({})", array_bytes::bytes2hex("0x", &self.0))
56	}
57}
58
59impl HeadData {
60	/// Returns the hash of this head data.
61	pub fn hash(&self) -> Hash {
62		sp_runtime::traits::BlakeTwo256::hash(&self.0)
63	}
64}
65
66impl codec::EncodeLike<HeadData> for alloc::vec::Vec<u8> {}
67
68/// Parachain validation code.
69#[derive(
70	PartialEq,
71	Eq,
72	Clone,
73	Encode,
74	Decode,
75	DecodeWithMemTracking,
76	derive_more::From,
77	TypeInfo,
78	Serialize,
79	Deserialize,
80)]
81#[cfg_attr(feature = "std", derive(Hash))]
82pub struct ValidationCode(#[serde(with = "bytes")] pub Vec<u8>);
83
84impl core::fmt::Debug for ValidationCode {
85	fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
86		write!(f, "ValidationCode({})", array_bytes::bytes2hex("0x", &self.0))
87	}
88}
89
90impl ValidationCode {
91	/// Get the blake2-256 hash of the validation code bytes.
92	pub fn hash(&self) -> ValidationCodeHash {
93		ValidationCodeHash(sp_runtime::traits::BlakeTwo256::hash(&self.0[..]))
94	}
95}
96
97/// Unit type wrapper around [`type@Hash`] that represents the blake2-256 hash
98/// of validation code in particular.
99///
100/// This type is produced by [`ValidationCode::hash`].
101///
102/// This type makes it easy to enforce that a hash is a validation code hash on the type level.
103#[derive(
104	Clone,
105	Copy,
106	Encode,
107	Decode,
108	DecodeWithMemTracking,
109	Hash,
110	Eq,
111	PartialEq,
112	PartialOrd,
113	Ord,
114	TypeInfo,
115)]
116pub struct ValidationCodeHash(Hash);
117
118impl core::fmt::Display for ValidationCodeHash {
119	fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
120		self.0.fmt(f)
121	}
122}
123
124impl core::fmt::Debug for ValidationCodeHash {
125	fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
126		write!(f, "{:?}", self.0)
127	}
128}
129
130impl AsRef<[u8]> for ValidationCodeHash {
131	fn as_ref(&self) -> &[u8] {
132		self.0.as_ref()
133	}
134}
135
136impl From<Hash> for ValidationCodeHash {
137	fn from(hash: Hash) -> ValidationCodeHash {
138		ValidationCodeHash(hash)
139	}
140}
141
142impl From<[u8; 32]> for ValidationCodeHash {
143	fn from(hash: [u8; 32]) -> ValidationCodeHash {
144		ValidationCodeHash(hash.into())
145	}
146}
147
148impl core::fmt::LowerHex for ValidationCodeHash {
149	fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
150		core::fmt::LowerHex::fmt(&self.0, f)
151	}
152}
153
154/// Parachain block data.
155///
156/// Contains everything required to validate para-block, may contain block and witness data.
157#[derive(PartialEq, Eq, Clone, Encode, Decode, derive_more::From, TypeInfo, Debug)]
158#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
159pub struct BlockData(#[cfg_attr(feature = "std", serde(with = "bytes"))] pub Vec<u8>);
160
161/// Unique identifier of a parachain.
162#[derive(
163	Clone,
164	CompactAs,
165	Copy,
166	Decode,
167	DecodeWithMemTracking,
168	Default,
169	Encode,
170	Eq,
171	Hash,
172	MaxEncodedLen,
173	Ord,
174	PartialEq,
175	PartialOrd,
176	serde::Serialize,
177	serde::Deserialize,
178	TypeInfo,
179)]
180#[cfg_attr(feature = "std", derive(derive_more::Display))]
181pub struct Id(u32);
182
183impl core::fmt::Debug for Id {
184	fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
185		self.0.fmt(f)
186	}
187}
188
189impl codec::EncodeLike<u32> for Id {}
190impl codec::EncodeLike<Id> for u32 {}
191
192impl TypeId for Id {
193	const TYPE_ID: [u8; 4] = *b"para";
194}
195
196impl From<Id> for u32 {
197	fn from(x: Id) -> Self {
198		x.0
199	}
200}
201
202impl From<u32> for Id {
203	fn from(x: u32) -> Self {
204		Id(x)
205	}
206}
207
208#[cfg(any(feature = "std", feature = "runtime-benchmarks"))]
209impl From<usize> for Id {
210	fn from(x: usize) -> Self {
211		// can't panic, so need to truncate
212		let x = x.try_into().unwrap_or(u32::MAX);
213		Id(x)
214	}
215}
216
217// When we added a second From impl for Id, type inference could no longer
218// determine which impl should apply for things like `5.into()`. It therefore
219// raised a bunch of errors in our test code, scattered throughout the
220// various modules' tests, that there is no impl of `From<i32>` (`i32` being
221// the default numeric type).
222//
223// We can't use `cfg(test)` here, because that configuration directive does not
224// propagate between crates, which would fail to fix tests in crates other than
225// this one.
226//
227// Instead, let's take advantage of the observation that what really matters for a
228// ParaId within a test context is that it is unique and constant. I believe that
229// there is no case where someone does `(-1).into()` anyway, but if they do, it
230// never matters whether the actual contained ID is `-1` or `4294967295`. Nobody
231// does arithmetic on a `ParaId`; doing so would be a bug.
232impl From<i32> for Id {
233	fn from(x: i32) -> Self {
234		Id(x as u32)
235	}
236}
237
238// System parachain ID is considered `< 2000`.
239const SYSTEM_INDEX_END: u32 = 1999;
240const PUBLIC_INDEX_START: u32 = 2000;
241
242/// The ID of the first publicly registrable parachain.
243pub const LOWEST_PUBLIC_ID: Id = Id(PUBLIC_INDEX_START);
244
245impl Id {
246	/// Create an `Id`.
247	pub const fn new(id: u32) -> Self {
248		Self(id)
249	}
250}
251
252/// Determine if a parachain is a system parachain or not.
253pub trait IsSystem {
254	/// Returns `true` if a parachain is a system parachain, `false` otherwise.
255	fn is_system(&self) -> bool;
256}
257
258impl IsSystem for Id {
259	fn is_system(&self) -> bool {
260		self.0 <= SYSTEM_INDEX_END
261	}
262}
263
264impl core::ops::Add<u32> for Id {
265	type Output = Self;
266
267	fn add(self, other: u32) -> Self {
268		Self(self.0 + other)
269	}
270}
271
272impl core::ops::Sub<u32> for Id {
273	type Output = Self;
274
275	fn sub(self, other: u32) -> Self {
276		Self(self.0 - other)
277	}
278}
279
280#[derive(Clone, Copy, Default, Encode, Decode, Eq, PartialEq, Ord, PartialOrd, Debug, TypeInfo)]
281pub struct Sibling(pub Id);
282
283impl From<Id> for Sibling {
284	fn from(i: Id) -> Self {
285		Self(i)
286	}
287}
288
289impl From<Sibling> for Id {
290	fn from(i: Sibling) -> Self {
291		i.0
292	}
293}
294
295impl AsRef<Id> for Sibling {
296	fn as_ref(&self) -> &Id {
297		&self.0
298	}
299}
300
301impl TypeId for Sibling {
302	const TYPE_ID: [u8; 4] = *b"sibl";
303}
304
305impl From<Sibling> for u32 {
306	fn from(x: Sibling) -> Self {
307		x.0.into()
308	}
309}
310
311impl From<u32> for Sibling {
312	fn from(x: u32) -> Self {
313		Sibling(x.into())
314	}
315}
316
317impl IsSystem for Sibling {
318	fn is_system(&self) -> bool {
319		IsSystem::is_system(&self.0)
320	}
321}
322
323/// A type that uniquely identifies an HRMP channel. An HRMP channel is established between two
324/// paras. In text, we use the notation `(A, B)` to specify a channel between A and B. The channels
325/// are unidirectional, meaning that `(A, B)` and `(B, A)` refer to different channels. The
326/// convention is that we use the first item tuple for the sender and the second for the recipient.
327/// Only one channel is allowed between two participants in one direction, i.e. there cannot be 2
328/// different channels identified by `(A, B)`. A channel with the same para id in sender and
329/// recipient is invalid. That is, however, not enforced.
330#[derive(
331	Clone, PartialEq, Eq, PartialOrd, Ord, Encode, Decode, DecodeWithMemTracking, Debug, TypeInfo,
332)]
333#[cfg_attr(feature = "std", derive(Hash))]
334pub struct HrmpChannelId {
335	/// The para that acts as the sender in this channel.
336	pub sender: Id,
337	/// The para that acts as the recipient in this channel.
338	pub recipient: Id,
339}
340
341impl HrmpChannelId {
342	/// Returns true if the given id corresponds to either the sender or the recipient.
343	pub fn is_participant(&self, id: Id) -> bool {
344		id == self.sender || id == self.recipient
345	}
346}
347
348/// A message from a parachain to its Relay Chain.
349pub type UpwardMessage = Vec<u8>;
350
351/// Something that should be called when a downward message is received.
352pub trait DmpMessageHandler {
353	/// Handle some incoming DMP messages (note these are individual XCM messages).
354	///
355	/// Also, process messages up to some `max_weight`.
356	fn handle_dmp_messages(
357		iter: impl Iterator<Item = (RelayChainBlockNumber, Vec<u8>)>,
358		max_weight: Weight,
359	) -> Weight;
360}
361impl DmpMessageHandler for () {
362	fn handle_dmp_messages(
363		iter: impl Iterator<Item = (RelayChainBlockNumber, Vec<u8>)>,
364		_max_weight: Weight,
365	) -> Weight {
366		iter.for_each(drop);
367		Weight::zero()
368	}
369}
370
371/// The aggregate XCMP message format.
372#[derive(
373	Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, TypeInfo, Debug, MaxEncodedLen,
374)]
375pub enum XcmpMessageFormat {
376	/// Encoded `VersionedXcm` messages, all concatenated.
377	ConcatenatedVersionedXcm,
378	/// Encoded `Vec<u8>` messages, all concatenated.
379	ConcatenatedEncodedBlob,
380	/// One or more channel control signals; these should be interpreted immediately upon receipt
381	/// from the relay-chain.
382	Signals,
383	/// Double encoded `VersionedXcm` messages, all concatenated.
384	ConcatenatedOpaqueVersionedXcm,
385}
386
387/// Something that should be called for each batch of messages received over XCMP.
388pub trait XcmpMessageHandler {
389	/// Handle some incoming XCMP messages (note these are the big one-per-block aggregate
390	/// messages).
391	///
392	/// Also, process messages up to some `max_weight`.
393	fn handle_xcmp_messages<'a, I: Iterator<Item = (Id, RelayChainBlockNumber, &'a [u8])>>(
394		iter: I,
395		max_weight: Weight,
396	) -> Weight;
397}
398impl XcmpMessageHandler for () {
399	fn handle_xcmp_messages<'a, I: Iterator<Item = (Id, RelayChainBlockNumber, &'a [u8])>>(
400		iter: I,
401		_max_weight: Weight,
402	) -> Weight {
403		for _ in iter {}
404		Weight::zero()
405	}
406}
407
408/// Extension to ValidationParams for V3+ candidates.
409/// Versioned enum where the variant index serves as the version number.
410///
411/// When introducing a new candidate descriptor version, add a new variant here.
412/// PVFs that don't understand the new variant will fail to decode, which is
413/// expected - parachains must upgrade their PVF to use new features.
414#[derive(Clone, Encode, Decode)]
415#[cfg_attr(feature = "std", derive(Debug))]
416pub enum ValidationParamsExtension {
417	/// V3 extension - contains relay_parent and scheduling_parent hashes.
418	#[codec(index = 3)]
419	V3 {
420		/// The relay parent block hash.
421		relay_parent: Hash,
422		/// The scheduling parent block hash (may differ from relay_parent in V3).
423		scheduling_parent: Hash,
424	},
425	// Future versions would add new variants:
426	// #[codec(index = 4)]
427	// V4 {
428	//     relay_parent: Hash,
429	//     scheduling_parent: Hash,
430	//     new_field: SomeType,
431	// },
432}
433
434/// A wrapper that decodes `T` if bytes remain after prior fields, or returns
435/// `None` if at EOF. Unlike `Option<T>`, this does NOT expect a 0x00/0x01
436/// discriminant byte - it simply checks whether there is remaining input.
437///
438/// This is used to guarantee no breakage for existing chains with v1/v2
439/// descriptors. For v1/v2, no extension bytes are sent at all, and
440/// TrailingOption gracefully returns None instead of failing to decode.
441///
442/// # ⚠️ DANGER - Do Not Use This as a General-Purpose Utility! ⚠️
443///
444/// **CRITICAL ASSUMPTIONS:**
445/// - The type containing `TrailingOption<T>` MUST be the final/top-level struct being decoded
446/// - There MUST NOT be any fields after the `TrailingOption<T>` field
447/// - There MUST NOT be any legitimate trailing data except `T`
448///
449/// **Why this is dangerous:**
450/// `TrailingOption` greedily consumes ALL remaining bytes and attempts to decode them as `T`.
451/// If your struct is embedded in a larger message, or if you add fields after it,
452/// `TrailingOption` will incorrectly steal bytes belonging to those fields.
453///
454/// **Current safe usage:**
455/// - `ValidationParams` is encoded as a complete standalone message
456/// - `ValidationParamsExtension` is manually appended as trailing bytes
457/// - The PVF receives this as the entire input (no wrapper struct)
458///
459/// If you're considering using this elsewhere, you probably want `Option<T>` instead.
460#[derive(Clone)]
461#[cfg_attr(feature = "std", derive(Debug))]
462pub struct TrailingOption<T>(pub Option<T>);
463
464impl<T: Decode> Decode for TrailingOption<T> {
465	fn decode<I: codec::Input>(input: &mut I) -> Result<Self, codec::Error> {
466		// Check if input is exhausted - return None instead of failing
467		if input.remaining_len()? == Some(0) {
468			return Ok(TrailingOption(None));
469		}
470		// Bytes remain - decode T (the ValidationParamsExtension enum)
471		Ok(TrailingOption(Some(T::decode(input)?)))
472	}
473}
474
475impl<T: Encode> Encode for TrailingOption<T> {
476	fn encode(&self) -> Vec<u8> {
477		match &self.0 {
478			Some(inner) => inner.encode(),
479			None => Vec::new(), // Encode nothing for None
480		}
481	}
482}
483
484impl<T> TrailingOption<T> {
485	/// Extract the inner `Option<T>`.
486	pub fn into_inner(self) -> Option<T> {
487		self.0
488	}
489}
490
491/// Validation parameters for evaluating the parachain validity function.
492// TODO: balance downloads (https://github.com/paritytech/polkadot/issues/220)
493#[derive(PartialEq, Eq, Decode, Clone)]
494#[cfg_attr(feature = "std", derive(Debug, Encode))]
495pub struct ValidationParams {
496	/// Previous head-data.
497	pub parent_head: HeadData,
498	/// The collation body.
499	pub block_data: BlockData,
500	/// The current relay-chain block number.
501	pub relay_parent_number: RelayChainBlockNumber,
502	/// The relay-chain block's storage root.
503	pub relay_parent_storage_root: Hash,
504}
505
506/// Maximum number of HRMP messages allowed per candidate.
507///
508/// We also use this as a generous limit, which still prevents possible memory exhaustion, from
509/// malicious parachains that may otherwise return a huge amount of messages in `ValidationResult`.
510pub const MAX_HORIZONTAL_MESSAGE_NUM: u32 = 16 * 1024;
511/// Maximum number of UMP messages allowed per candidate.
512///
513/// We also use this as a generous limit, which still prevents possible memory exhaustion, from
514/// malicious parachains that may otherwise return a huge amount of messages in `ValidationResult`.
515pub const MAX_UPWARD_MESSAGE_NUM: u32 = 16 * 1024;
516
517pub type UpwardMessages = BoundedVec<UpwardMessage, ConstU32<MAX_UPWARD_MESSAGE_NUM>>;
518
519pub type HorizontalMessages =
520	BoundedVec<OutboundHrmpMessage<Id>, ConstU32<MAX_HORIZONTAL_MESSAGE_NUM>>;
521
522/// The result of parachain validation.
523// TODO: balance uploads (https://github.com/paritytech/polkadot/issues/220)
524#[derive(PartialEq, Eq, Clone, Encode)]
525#[cfg_attr(feature = "std", derive(Debug, Decode))]
526pub struct ValidationResult {
527	/// New head data that should be included in the relay chain state.
528	pub head_data: HeadData,
529	/// An update to the validation code that should be scheduled in the relay chain.
530	pub new_validation_code: Option<ValidationCode>,
531	/// Upward messages send by the Parachain.
532	pub upward_messages: UpwardMessages,
533	/// Outbound horizontal messages sent by the parachain.
534	pub horizontal_messages: HorizontalMessages,
535	/// Number of downward messages that were processed by the Parachain.
536	///
537	/// It is expected that the Parachain processes them from first to last.
538	pub processed_downward_messages: u32,
539	/// The mark which specifies the block number up to which all inbound HRMP messages are
540	/// processed.
541	pub hrmp_watermark: RelayChainBlockNumber,
542}
543
544#[cfg(test)]
545mod tests {
546	use super::*;
547
548	#[test]
549	fn para_id_debug() {
550		let id = Id::new(42);
551		assert_eq!(format!("{:?}", id), "42");
552	}
553}