cumulus_primitives_parachain_inherent/lib.rs
1// Copyright (C) Parity Technologies (UK) Ltd.
2// This file is part of Cumulus.
3
4// Cumulus 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// Cumulus 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 Cumulus. If not, see <http://www.gnu.org/licenses/>.
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 cumulus_primitives_core::{
33 relay_chain::{BlakeTwo256, Hash as RelayHash, HashT as _},
34 InboundDownwardMessage, InboundHrmpMessage, ParaId, PersistedValidationData,
35};
36
37use alloc::{collections::btree_map::BTreeMap, vec::Vec};
38use scale_info::TypeInfo;
39use sp_inherents::InherentIdentifier;
40
41/// The identifier for the parachain inherent.
42pub const INHERENT_IDENTIFIER: InherentIdentifier = *b"sysi1337";
43
44/// The inherent data that is passed by the collator to the parachain runtime.
45#[derive(codec::Encode, codec::Decode, sp_core::RuntimeDebug, Clone, PartialEq, TypeInfo)]
46pub struct ParachainInherentData {
47 pub validation_data: PersistedValidationData,
48 /// A storage proof of a predefined set of keys from the relay-chain.
49 ///
50 /// Specifically this witness contains the data for:
51 ///
52 /// - the current slot number at the given relay parent
53 /// - active host configuration as per the relay parent,
54 /// - the relay dispatch queue sizes
55 /// - the list of egress HRMP channels (in the list of recipients form)
56 /// - the metadata for the egress HRMP channels
57 pub relay_chain_state: sp_trie::StorageProof,
58 /// Downward messages in the order they were sent.
59 pub downward_messages: Vec<InboundDownwardMessage>,
60 /// HRMP messages grouped by channels. The messages in the inner vec must be in order they
61 /// were sent. In combination with the rule of no more than one message in a channel per block,
62 /// this means `sent_at` is **strictly** greater than the previous one (if any).
63 pub horizontal_messages: BTreeMap<ParaId, Vec<InboundHrmpMessage>>,
64}
65
66#[cfg(feature = "std")]
67#[async_trait::async_trait]
68impl sp_inherents::InherentDataProvider for ParachainInherentData {
69 async fn provide_inherent_data(
70 &self,
71 inherent_data: &mut sp_inherents::InherentData,
72 ) -> Result<(), sp_inherents::Error> {
73 inherent_data.put_data(INHERENT_IDENTIFIER, &self)
74 }
75
76 async fn try_handle_error(
77 &self,
78 _: &sp_inherents::InherentIdentifier,
79 _: &[u8],
80 ) -> Option<Result<(), sp_inherents::Error>> {
81 None
82 }
83}
84
85/// This struct provides ability to extend a message queue chain (MQC) and compute a new head.
86///
87/// MQC is an instance of a [hash chain] applied to a message queue. Using a hash chain it's
88/// possible to represent a sequence of messages using only a single hash.
89///
90/// A head for an empty chain is agreed to be a zero hash.
91///
92/// An instance is used to track either DMP from the relay chain or HRMP across a channel.
93/// But a given instance is never used to track both. Therefore, you should call either
94/// `extend_downward` or `extend_hrmp`, but not both methods on a single instance.
95///
96/// [hash chain]: https://en.wikipedia.org/wiki/Hash_chain
97#[derive(Default, Clone, codec::Encode, codec::Decode, scale_info::TypeInfo)]
98pub struct MessageQueueChain(RelayHash);
99
100impl MessageQueueChain {
101 /// Create a new instance initialized to `hash`.
102 pub fn new(hash: RelayHash) -> Self {
103 Self(hash)
104 }
105
106 /// Extend the hash chain with an HRMP message. This method should be used only when
107 /// this chain is tracking HRMP.
108 pub fn extend_hrmp(&mut self, horizontal_message: &InboundHrmpMessage) -> &mut Self {
109 let prev_head = self.0;
110 self.0 = BlakeTwo256::hash_of(&(
111 prev_head,
112 horizontal_message.sent_at,
113 BlakeTwo256::hash_of(&horizontal_message.data),
114 ));
115 self
116 }
117
118 /// Extend the hash chain with a downward message. This method should be used only when
119 /// this chain is tracking DMP.
120 pub fn extend_downward(&mut self, downward_message: &InboundDownwardMessage) -> &mut Self {
121 let prev_head = self.0;
122 self.0 = BlakeTwo256::hash_of(&(
123 prev_head,
124 downward_message.sent_at,
125 BlakeTwo256::hash_of(&downward_message.msg),
126 ));
127 self
128 }
129
130 /// Return the current mead of the message queue hash chain.
131 /// This is agreed to be the zero hash for an empty chain.
132 pub fn head(&self) -> RelayHash {
133 self.0
134 }
135}