referrerpolicy=no-referrer-when-downgrade

bp_parachains/
lib.rs

1// Copyright (C) Parity Technologies (UK) Ltd.
2// This file is part of Parity Bridges Common.
3
4// Parity Bridges Common 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// Parity Bridges Common 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 Parity Bridges Common.  If not, see <http://www.gnu.org/licenses/>.
16
17//! Primitives of parachains module.
18
19#![warn(missing_docs)]
20#![cfg_attr(not(feature = "std"), no_std)]
21
22pub use bp_header_chain::StoredHeaderData;
23pub use call_info::{BridgeParachainCall, SubmitParachainHeadsInfo};
24
25use bp_polkadot_core::parachains::{ParaHash, ParaHead, ParaId};
26use bp_runtime::{
27	BlockNumberOf, Chain, HashOf, HeaderOf, Parachain, StorageDoubleMapKeyProvider,
28	StorageMapKeyProvider,
29};
30use codec::{Decode, Encode, MaxEncodedLen};
31use frame_support::{weights::Weight, Blake2_128Concat, Twox64Concat};
32use scale_info::TypeInfo;
33use sp_core::storage::StorageKey;
34use sp_runtime::{traits::Header as HeaderT, RuntimeDebug};
35use sp_std::{marker::PhantomData, prelude::*};
36
37/// Block hash of the bridged relay chain.
38pub type RelayBlockHash = bp_polkadot_core::Hash;
39/// Block number of the bridged relay chain.
40pub type RelayBlockNumber = bp_polkadot_core::BlockNumber;
41/// Hasher of the bridged relay chain.
42pub type RelayBlockHasher = bp_polkadot_core::Hasher;
43
44mod call_info;
45
46/// Best known parachain head hash.
47#[derive(Clone, Decode, Encode, MaxEncodedLen, PartialEq, RuntimeDebug, TypeInfo)]
48pub struct BestParaHeadHash {
49	/// Number of relay block where this head has been read.
50	///
51	/// Parachain head is opaque to relay chain. So we can't simply decode it as a header of
52	/// parachains and call `block_number()` on it. Instead, we're using the fact that parachain
53	/// head is always built on top of previous head (because it is blockchain) and relay chain
54	/// always imports parachain heads in order. What it means for us is that at any given
55	/// **finalized** relay block `B`, head of parachain will be ancestor (or the same) of all
56	/// parachain heads available at descendants of `B`.
57	pub at_relay_block_number: RelayBlockNumber,
58	/// Hash of parachain head.
59	pub head_hash: ParaHash,
60}
61
62/// Best known parachain head as it is stored in the runtime storage.
63#[derive(Decode, Encode, MaxEncodedLen, PartialEq, RuntimeDebug, TypeInfo)]
64pub struct ParaInfo {
65	/// Best known parachain head hash.
66	pub best_head_hash: BestParaHeadHash,
67	/// Current ring buffer position for this parachain.
68	pub next_imported_hash_position: u32,
69}
70
71/// Returns runtime storage key of given parachain head at the source chain.
72///
73/// The head is stored by the `paras` pallet in the `Heads` map.
74pub fn parachain_head_storage_key_at_source(
75	paras_pallet_name: &str,
76	para_id: ParaId,
77) -> StorageKey {
78	bp_runtime::storage_map_final_key::<Twox64Concat>(paras_pallet_name, "Heads", &para_id.encode())
79}
80
81/// Can be use to access the runtime storage key of the parachains info at the target chain.
82///
83/// The info is stored by the `pallet-bridge-parachains` pallet in the `ParasInfo` map.
84pub struct ParasInfoKeyProvider;
85impl StorageMapKeyProvider for ParasInfoKeyProvider {
86	const MAP_NAME: &'static str = "ParasInfo";
87
88	type Hasher = Blake2_128Concat;
89	type Key = ParaId;
90	type Value = ParaInfo;
91}
92
93/// Can be use to access the runtime storage key of the parachain head at the target chain.
94///
95/// The head is stored by the `pallet-bridge-parachains` pallet in the `ImportedParaHeads` map.
96pub struct ImportedParaHeadsKeyProvider;
97impl StorageDoubleMapKeyProvider for ImportedParaHeadsKeyProvider {
98	const MAP_NAME: &'static str = "ImportedParaHeads";
99
100	type Hasher1 = Blake2_128Concat;
101	type Key1 = ParaId;
102	type Hasher2 = Blake2_128Concat;
103	type Key2 = ParaHash;
104	type Value = ParaStoredHeaderData;
105}
106
107/// Stored data of the parachain head. It is encoded version of the
108/// `bp_runtime::StoredHeaderData` structure.
109///
110/// We do not know exact structure of the parachain head, so we always store encoded version
111/// of the `bp_runtime::StoredHeaderData`. It is only decoded when we talk about specific parachain.
112#[derive(Clone, Decode, Encode, PartialEq, RuntimeDebug, TypeInfo)]
113pub struct ParaStoredHeaderData(pub Vec<u8>);
114
115impl ParaStoredHeaderData {
116	/// Decode stored parachain head data.
117	pub fn decode_parachain_head_data<C: Chain>(
118		&self,
119	) -> Result<StoredHeaderData<BlockNumberOf<C>, HashOf<C>>, codec::Error> {
120		StoredHeaderData::<BlockNumberOf<C>, HashOf<C>>::decode(&mut &self.0[..])
121	}
122}
123
124/// Stored parachain head data builder.
125pub trait ParaStoredHeaderDataBuilder {
126	/// Maximal parachain head size that we may accept for free. All heads above
127	/// this limit are submitted for a regular fee.
128	fn max_free_head_size() -> u32;
129
130	/// Return number of parachains that are supported by this builder.
131	fn supported_parachains() -> u32;
132
133	/// Try to build head data from encoded head of parachain with given id.
134	fn try_build(para_id: ParaId, para_head: &ParaHead) -> Option<ParaStoredHeaderData>;
135}
136
137/// Helper for using single parachain as `ParaStoredHeaderDataBuilder`.
138pub struct SingleParaStoredHeaderDataBuilder<C: Parachain>(PhantomData<C>);
139
140impl<C: Parachain> ParaStoredHeaderDataBuilder for SingleParaStoredHeaderDataBuilder<C> {
141	fn max_free_head_size() -> u32 {
142		C::MAX_HEADER_SIZE
143	}
144
145	fn supported_parachains() -> u32 {
146		1
147	}
148
149	fn try_build(para_id: ParaId, para_head: &ParaHead) -> Option<ParaStoredHeaderData> {
150		if para_id == ParaId(C::PARACHAIN_ID) {
151			let header = HeaderOf::<C>::decode(&mut &para_head.0[..]).ok()?;
152			return Some(ParaStoredHeaderData(
153				StoredHeaderData { number: *header.number(), state_root: *header.state_root() }
154					.encode(),
155			))
156		}
157		None
158	}
159}
160
161// Tries to build header data from each tuple member, short-circuiting on first successful one.
162#[impl_trait_for_tuples::impl_for_tuples(1, 30)]
163#[tuple_types_custom_trait_bound(Parachain)]
164impl ParaStoredHeaderDataBuilder for C {
165	fn max_free_head_size() -> u32 {
166		let mut result = 0_u32;
167		for_tuples!( #(
168			result = sp_std::cmp::max(
169				result,
170				SingleParaStoredHeaderDataBuilder::<C>::max_free_head_size(),
171			);
172		)* );
173		result
174	}
175
176	fn supported_parachains() -> u32 {
177		let mut result = 0;
178		for_tuples!( #(
179			result += SingleParaStoredHeaderDataBuilder::<C>::supported_parachains();
180		)* );
181		result
182	}
183
184	fn try_build(para_id: ParaId, para_head: &ParaHead) -> Option<ParaStoredHeaderData> {
185		for_tuples!( #(
186			let maybe_para_head = SingleParaStoredHeaderDataBuilder::<C>::try_build(para_id, para_head);
187			if let Some(maybe_para_head) = maybe_para_head {
188				return Some(maybe_para_head);
189			}
190		)* );
191
192		None
193	}
194}
195
196/// Runtime hook for when a parachain head is updated.
197pub trait OnNewHead {
198	/// Called when a parachain head is updated.
199	/// Returns the weight consumed by this function.
200	fn on_new_head(id: ParaId, head: &ParaHead) -> Weight;
201}
202
203#[impl_trait_for_tuples::impl_for_tuples(8)]
204impl OnNewHead for Tuple {
205	fn on_new_head(id: ParaId, head: &ParaHead) -> Weight {
206		let mut weight: Weight = Default::default();
207		for_tuples!( #( weight.saturating_accrue(Tuple::on_new_head(id, head)); )* );
208		weight
209	}
210}