referrerpolicy=no-referrer-when-downgrade

cumulus_primitives_parachain_inherent/
lib.rs

1// Copyright (C) Parity Technologies (UK) Ltd.
2// This file is part of Cumulus.
3// SPDX-License-Identifier: Apache-2.0
4
5// Licensed under the Apache License, Version 2.0 (the "License");
6// you may not use this file except in compliance with the License.
7// You may obtain a copy of the License at
8//
9// 	http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing, software
12// distributed under the License is distributed on an "AS IS" BASIS,
13// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14// See the License for the specific language governing permissions and
15// limitations under the License.
16
17//! Cumulus parachain inherent
18//!
19//! The [`ParachainInherentData`] is the data that is passed by the collator to the parachain
20//! runtime. The runtime will use this data to execute messages from other parachains/the relay
21//! chain or to read data from the relay chain state. When the parachain is validated by a parachain
22//! validator on the relay chain, this data is checked for correctness. If the data passed by the
23//! collator to the runtime isn't correct, the parachain candidate is considered invalid.
24//!
25//! To create a [`ParachainInherentData`] for a specific relay chain block, there exists the
26//! `ParachainInherentDataExt` trait in `cumulus-client-parachain-inherent` that helps with this.
27
28#![cfg_attr(not(feature = "std"), no_std)]
29
30extern crate alloc;
31
32use alloc::{collections::btree_map::BTreeMap, vec::Vec};
33use cumulus_primitives_core::{
34	relay_chain::{
35		ApprovedPeerId, BlakeTwo256, BlockNumber as RelayChainBlockNumber, Hash as RelayHash,
36		HashT as _, Header as RelayHeader,
37	},
38	InboundDownwardMessage, InboundHrmpMessage, ParaId, PersistedValidationData,
39};
40use scale_info::TypeInfo;
41use sp_inherents::InherentIdentifier;
42
43/// The identifier for the parachain inherent.
44pub const PARACHAIN_INHERENT_IDENTIFIER_V0: InherentIdentifier = *b"sysi1337";
45pub const INHERENT_IDENTIFIER: InherentIdentifier = *b"sysi1338";
46
47/// Legacy ParachainInherentData that is kept around for backward compatibility.
48/// Can be removed once we can safely assume that parachain nodes provide the
49/// `relay_parent_descendants` and `collator_peer_id` fields.
50pub mod v0 {
51	use alloc::{collections::BTreeMap, vec::Vec};
52	use cumulus_primitives_core::{
53		InboundDownwardMessage, InboundHrmpMessage, ParaId, PersistedValidationData,
54	};
55	use scale_info::TypeInfo;
56
57	/// The inherent data that is passed by the collator to the parachain runtime.
58	#[derive(
59		codec::Encode,
60		codec::Decode,
61		codec::DecodeWithMemTracking,
62		sp_core::RuntimeDebug,
63		Clone,
64		PartialEq,
65		TypeInfo,
66	)]
67	pub struct ParachainInherentData {
68		pub validation_data: PersistedValidationData,
69		/// A storage proof of a predefined set of keys from the relay-chain.
70		///
71		/// Specifically this witness contains the data for:
72		///
73		/// - the current slot number at the given relay parent
74		/// - active host configuration as per the relay parent,
75		/// - the relay dispatch queue sizes
76		/// - the list of egress HRMP channels (in the list of recipients form)
77		/// - the metadata for the egress HRMP channels
78		pub relay_chain_state: sp_trie::StorageProof,
79		/// Downward messages in the order they were sent.
80		pub downward_messages: Vec<InboundDownwardMessage>,
81		/// HRMP messages grouped by channels. The messages in the inner vec must be in order they
82		/// were sent. In combination with the rule of no more than one message in a channel per
83		/// block, this means `sent_at` is **strictly** greater than the previous one (if any).
84		pub horizontal_messages: BTreeMap<ParaId, Vec<InboundHrmpMessage>>,
85	}
86}
87
88/// The inherent data that is passed by the collator to the parachain runtime.
89#[derive(
90	codec::Encode,
91	codec::Decode,
92	codec::DecodeWithMemTracking,
93	sp_core::RuntimeDebug,
94	Clone,
95	PartialEq,
96	TypeInfo,
97)]
98pub struct ParachainInherentData {
99	pub validation_data: PersistedValidationData,
100	/// A storage proof of a predefined set of keys from the relay-chain.
101	///
102	/// Specifically this witness contains the data for:
103	///
104	/// - the current slot number at the given relay parent
105	/// - active host configuration as per the relay parent,
106	/// - the relay dispatch queue sizes
107	/// - the list of egress HRMP channels (in the list of recipients form)
108	/// - the metadata for the egress HRMP channels
109	pub relay_chain_state: sp_trie::StorageProof,
110	/// Downward messages in the order they were sent.
111	pub downward_messages: Vec<InboundDownwardMessage>,
112	/// HRMP messages grouped by channels. The messages in the inner vec must be in order they
113	/// were sent. In combination with the rule of no more than one message in a channel per block,
114	/// this means `sent_at` is **strictly** greater than the previous one (if any).
115	pub horizontal_messages: BTreeMap<ParaId, Vec<InboundHrmpMessage>>,
116	/// Contains the relay parent header and its descendants.
117	/// This information is used to ensure that a parachain node builds blocks
118	/// at a specified offset from the chain tip rather than directly at the tip.
119	pub relay_parent_descendants: Vec<RelayHeader>,
120	/// Contains the collator peer ID, which is later sent by the parachain to the
121	/// relay chain via a UMP signal to promote the reputation of the given peer ID.
122	pub collator_peer_id: Option<ApprovedPeerId>,
123}
124
125// Upgrades the ParachainInherentData v0 to the newest format.
126impl Into<ParachainInherentData> for v0::ParachainInherentData {
127	fn into(self) -> ParachainInherentData {
128		ParachainInherentData {
129			validation_data: self.validation_data,
130			relay_chain_state: self.relay_chain_state,
131			downward_messages: self.downward_messages,
132			horizontal_messages: self.horizontal_messages,
133			relay_parent_descendants: Vec::new(),
134			collator_peer_id: None,
135		}
136	}
137}
138
139#[cfg(feature = "std")]
140impl ParachainInherentData {
141	/// Transforms [`ParachainInherentData`] into [`v0::ParachainInherentData`]. Can be used
142	/// to create inherent data compatible with old runtimes.
143	fn as_v0(&self) -> v0::ParachainInherentData {
144		v0::ParachainInherentData {
145			validation_data: self.validation_data.clone(),
146			relay_chain_state: self.relay_chain_state.clone(),
147			downward_messages: self.downward_messages.clone(),
148			horizontal_messages: self.horizontal_messages.clone(),
149		}
150	}
151}
152
153#[cfg(feature = "std")]
154#[async_trait::async_trait]
155impl sp_inherents::InherentDataProvider for ParachainInherentData {
156	async fn provide_inherent_data(
157		&self,
158		inherent_data: &mut sp_inherents::InherentData,
159	) -> Result<(), sp_inherents::Error> {
160		inherent_data.put_data(PARACHAIN_INHERENT_IDENTIFIER_V0, &self.as_v0())?;
161		inherent_data.put_data(INHERENT_IDENTIFIER, &self)
162	}
163
164	async fn try_handle_error(
165		&self,
166		_: &sp_inherents::InherentIdentifier,
167		_: &[u8],
168	) -> Option<Result<(), sp_inherents::Error>> {
169		None
170	}
171}
172
173/// An inbound message whose content was hashed.
174#[derive(
175	codec::Encode,
176	codec::Decode,
177	codec::DecodeWithMemTracking,
178	sp_core::RuntimeDebug,
179	Clone,
180	PartialEq,
181	TypeInfo,
182)]
183pub struct HashedMessage {
184	pub sent_at: RelayChainBlockNumber,
185	pub msg_hash: sp_core::H256,
186}
187
188impl From<&InboundDownwardMessage<RelayChainBlockNumber>> for HashedMessage {
189	fn from(msg: &InboundDownwardMessage<RelayChainBlockNumber>) -> Self {
190		Self { sent_at: msg.sent_at, msg_hash: MessageQueueChain::hash_msg_data(&msg.msg) }
191	}
192}
193
194impl From<&InboundHrmpMessage> for HashedMessage {
195	fn from(msg: &InboundHrmpMessage) -> Self {
196		Self { sent_at: msg.sent_at, msg_hash: MessageQueueChain::hash_msg_data(&msg.data) }
197	}
198}
199
200/// This struct provides ability to extend a message queue chain (MQC) and compute a new head.
201///
202/// MQC is an instance of a [hash chain] applied to a message queue. Using a hash chain it's
203/// possible to represent a sequence of messages using only a single hash.
204///
205/// A head for an empty chain is agreed to be a zero hash.
206///
207/// An instance is used to track either DMP from the relay chain or HRMP across a channel.
208/// But a given instance is never used to track both. Therefore, you should call either
209/// `extend_downward` or `extend_hrmp`, but not both methods on a single instance.
210///
211/// [hash chain]: https://en.wikipedia.org/wiki/Hash_chain
212#[derive(Default, Clone, codec::Encode, codec::Decode, scale_info::TypeInfo)]
213pub struct MessageQueueChain(RelayHash);
214
215impl MessageQueueChain {
216	/// Create a new instance initialized to `hash`.
217	pub fn new(hash: RelayHash) -> Self {
218		Self(hash)
219	}
220
221	/// Hash the provided message data.
222	fn hash_msg_data(msg: &Vec<u8>) -> sp_core::H256 {
223		BlakeTwo256::hash_of(msg)
224	}
225
226	/// Extend the hash chain with a `HashedMessage`.
227	pub fn extend_with_hashed_msg(&mut self, hashed_msg: &HashedMessage) -> &mut Self {
228		let prev_head = self.0;
229		self.0 = BlakeTwo256::hash_of(&(prev_head, hashed_msg.sent_at, &hashed_msg.msg_hash));
230		self
231	}
232
233	/// Extend the hash chain with an HRMP message. This method should be used only when
234	/// this chain is tracking HRMP.
235	pub fn extend_hrmp(&mut self, horizontal_message: &InboundHrmpMessage) -> &mut Self {
236		self.extend_with_hashed_msg(&horizontal_message.into())
237	}
238
239	/// Extend the hash chain with a downward message. This method should be used only when
240	/// this chain is tracking DMP.
241	pub fn extend_downward(&mut self, downward_message: &InboundDownwardMessage) -> &mut Self {
242		self.extend_with_hashed_msg(&downward_message.into())
243	}
244
245	/// Return the current head of the message queue chain.
246	/// This is agreed to be the zero hash for an empty chain.
247	pub fn head(&self) -> RelayHash {
248		self.0
249	}
250}