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}