// Copyright 2019-2021 Parity Technologies (UK) Ltd.
// This file is part of Parity Bridges Common.
// Parity Bridges Common is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity Bridges Common is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity Bridges Common. If not, see .
//! Primitives of parachains module.
#![cfg_attr(not(feature = "std"), no_std)]
pub use bp_header_chain::StoredHeaderData;
use bp_polkadot_core::{
parachains::{ParaHash, ParaHead, ParaHeadsProof, ParaId},
BlockNumber as RelayBlockNumber, Hash as RelayBlockHash,
};
use bp_runtime::{
BlockNumberOf, Chain, HashOf, HeaderOf, Parachain, StorageDoubleMapKeyProvider,
StorageMapKeyProvider,
};
use codec::{Decode, Encode, MaxEncodedLen};
use frame_support::{Blake2_128Concat, RuntimeDebug, Twox64Concat};
use scale_info::TypeInfo;
use sp_core::storage::StorageKey;
use sp_runtime::traits::Header as HeaderT;
use sp_std::{marker::PhantomData, prelude::*};
/// Best known parachain head hash.
#[derive(Clone, Decode, Encode, MaxEncodedLen, PartialEq, RuntimeDebug, TypeInfo)]
pub struct BestParaHeadHash {
/// Number of relay block where this head has been read.
///
/// Parachain head is opaque to relay chain. So we can't simply decode it as a header of
/// parachains and call `block_number()` on it. Instead, we're using the fact that parachain
/// head is always built on top of previous head (because it is blockchain) and relay chain
/// always imports parachain heads in order. What it means for us is that at any given
/// **finalized** relay block `B`, head of parachain will be ancestor (or the same) of all
/// parachain heads available at descendants of `B`.
pub at_relay_block_number: RelayBlockNumber,
/// Hash of parachain head.
pub head_hash: ParaHash,
}
/// Best known parachain head as it is stored in the runtime storage.
#[derive(Decode, Encode, MaxEncodedLen, PartialEq, RuntimeDebug, TypeInfo)]
pub struct ParaInfo {
/// Best known parachain head hash.
pub best_head_hash: BestParaHeadHash,
/// Current ring buffer position for this parachain.
pub next_imported_hash_position: u32,
}
/// Returns runtime storage key of given parachain head at the source chain.
///
/// The head is stored by the `paras` pallet in the `Heads` map.
pub fn parachain_head_storage_key_at_source(
paras_pallet_name: &str,
para_id: ParaId,
) -> StorageKey {
bp_runtime::storage_map_final_key::(paras_pallet_name, "Heads", ¶_id.encode())
}
/// Can be use to access the runtime storage key of the parachains info at the target chain.
///
/// The info is stored by the `pallet-bridge-parachains` pallet in the `ParasInfo` map.
pub struct ParasInfoKeyProvider;
impl StorageMapKeyProvider for ParasInfoKeyProvider {
const MAP_NAME: &'static str = "ParasInfo";
type Hasher = Blake2_128Concat;
type Key = ParaId;
type Value = ParaInfo;
}
/// Can be use to access the runtime storage key of the parachain head at the target chain.
///
/// The head is stored by the `pallet-bridge-parachains` pallet in the `ImportedParaHeads` map.
pub struct ImportedParaHeadsKeyProvider;
impl StorageDoubleMapKeyProvider for ImportedParaHeadsKeyProvider {
const MAP_NAME: &'static str = "ImportedParaHeads";
type Hasher1 = Blake2_128Concat;
type Key1 = ParaId;
type Hasher2 = Blake2_128Concat;
type Key2 = ParaHash;
type Value = ParaStoredHeaderData;
}
/// Stored data of the parachain head. It is encoded version of the
/// `bp_runtime::StoredHeaderData` structure.
///
/// We do not know exact structure of the parachain head, so we always store encoded version
/// of the `bp_runtime::StoredHeaderData`. It is only decoded when we talk about specific parachain.
#[derive(Clone, Decode, Encode, PartialEq, RuntimeDebug, TypeInfo)]
pub struct ParaStoredHeaderData(pub Vec);
impl ParaStoredHeaderData {
/// Decode stored parachain head data.
pub fn decode_parachain_head_data(
&self,
) -> Result, HashOf>, codec::Error> {
StoredHeaderData::, HashOf>::decode(&mut &self.0[..])
}
}
/// Stored parachain head data builder.
pub trait ParaStoredHeaderDataBuilder {
/// Try to build head data from self.
fn try_build(para_id: ParaId, para_head: &ParaHead) -> Option;
}
/// Helper for using single parachain as `ParaStoredHeaderDataBuilder`.
pub struct SingleParaStoredHeaderDataBuilder(PhantomData);
impl ParaStoredHeaderDataBuilder for SingleParaStoredHeaderDataBuilder {
fn try_build(para_id: ParaId, para_head: &ParaHead) -> Option {
if para_id == ParaId(C::PARACHAIN_ID) {
let header = HeaderOf::::decode(&mut ¶_head.0[..]).ok()?;
return Some(ParaStoredHeaderData(
StoredHeaderData { number: *header.number(), state_root: *header.state_root() }
.encode(),
))
}
None
}
}
// Tries to build header data from each tuple member, short-circuiting on first successful one.
#[impl_trait_for_tuples::impl_for_tuples(1, 30)]
#[tuple_types_custom_trait_bound(Parachain)]
impl ParaStoredHeaderDataBuilder for C {
fn try_build(para_id: ParaId, para_head: &ParaHead) -> Option {
for_tuples!( #(
let maybe_para_head = SingleParaStoredHeaderDataBuilder::::try_build(para_id, para_head);
if let Some(maybe_para_head) = maybe_para_head {
return Some(maybe_para_head);
}
)* );
None
}
}
/// A minimized version of `pallet-bridge-parachains::Call` that can be used without a runtime.
#[derive(Encode, Decode, Debug, PartialEq, Eq, Clone, TypeInfo)]
#[allow(non_camel_case_types)]
pub enum BridgeParachainCall {
/// `pallet-bridge-parachains::Call::submit_parachain_heads`
#[codec(index = 0)]
submit_parachain_heads(
(RelayBlockNumber, RelayBlockHash),
Vec<(ParaId, ParaHash)>,
ParaHeadsProof,
),
}