// Copyright (C) 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 teyrchains module. #![warn(missing_docs)] #![cfg_attr(not(feature = "std"), no_std)] pub use bp_header_pez_chain::StoredHeaderData; pub use call_info::{BridgeTeyrchainCall, SubmitTeyrchainHeadsInfo}; use bp_pezkuwi_core::teyrchains::{ParaHash, ParaHead, ParaId}; use codec::{Decode, Encode, MaxEncodedLen}; use pezbp_runtime::{ BlockNumberOf, Chain, HashOf, HeaderOf, StorageDoubleMapKeyProvider, StorageMapKeyProvider, Teyrchain, }; use pezframe_support::{weights::Weight, Blake2_128Concat, Twox64Concat}; use pezsp_core::storage::StorageKey; use pezsp_runtime::{traits::Header as HeaderT, RuntimeDebug}; use pezsp_std::{marker::PhantomData, prelude::*}; use scale_info::TypeInfo; /// Block hash of the bridged relay chain. pub type RelayBlockHash = bp_pezkuwi_core::Hash; /// Block number of the bridged relay chain. pub type RelayBlockNumber = bp_pezkuwi_core::BlockNumber; /// Hasher of the bridged relay chain. pub type RelayBlockHasher = bp_pezkuwi_core::Hasher; mod call_info; /// Best known teyrchain head hash. #[derive(Clone, Decode, Encode, MaxEncodedLen, PartialEq, RuntimeDebug, TypeInfo)] pub struct BestParaHeadHash { /// Number of relay block where this head has been read. /// /// Teyrchain head is opaque to relay chain. So we can't simply decode it as a header of /// teyrchains and call `block_number()` on it. Instead, we're using the fact that teyrchain /// head is always built on top of previous head (because it is blockchain) and relay chain /// always imports teyrchain heads in order. What it means for us is that at any given /// **finalized** relay block `B`, head of teyrchain will be ancestor (or the same) of all /// teyrchain heads available at descendants of `B`. pub at_relay_block_number: RelayBlockNumber, /// Hash of teyrchain head. pub head_hash: ParaHash, } /// Best known teyrchain head as it is stored in the runtime storage. #[derive(Decode, Encode, MaxEncodedLen, PartialEq, RuntimeDebug, TypeInfo)] pub struct ParaInfo { /// Best known teyrchain head hash. pub best_head_hash: BestParaHeadHash, /// Current ring buffer position for this teyrchain. pub next_imported_hash_position: u32, } /// Returns runtime storage key of given teyrchain head at the source chain. /// /// The head is stored by the `paras` pezpallet in the `Heads` map. pub fn teyrchain_head_storage_key_at_source( paras_pallet_name: &str, para_id: ParaId, ) -> StorageKey { pezbp_runtime::storage_map_final_key::( paras_pallet_name, "Heads", ¶_id.encode(), ) } /// Can be use to access the runtime storage key of the teyrchains info at the target chain. /// /// The info is stored by the `pezpallet-bridge-teyrchains` pezpallet 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 teyrchain head at the target chain. /// /// The head is stored by the `pezpallet-bridge-teyrchains` pezpallet 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 teyrchain head. It is encoded version of the /// `pezbp_runtime::StoredHeaderData` structure. /// /// We do not know exact structure of the teyrchain head, so we always store encoded version /// of the `pezbp_runtime::StoredHeaderData`. It is only decoded when we talk about specific /// teyrchain. #[derive(Clone, Decode, Encode, PartialEq, RuntimeDebug, TypeInfo)] pub struct ParaStoredHeaderData(pub Vec); impl ParaStoredHeaderData { /// Decode stored teyrchain head data. pub fn decode_teyrchain_head_data( &self, ) -> Result, HashOf>, codec::Error> { StoredHeaderData::, HashOf>::decode(&mut &self.0[..]) } } /// Stored teyrchain head data builder. pub trait ParaStoredHeaderDataBuilder { /// Maximal teyrchain head size that we may accept for free. All heads above /// this limit are submitted for a regular fee. fn max_free_head_size() -> u32; /// Return number of teyrchains that are supported by this builder. fn supported_teyrchains() -> u32; /// Try to build head data from encoded head of teyrchain with given id. fn try_build(para_id: ParaId, para_head: &ParaHead) -> Option; } /// Helper for using single teyrchain as `ParaStoredHeaderDataBuilder`. pub struct SingleParaStoredHeaderDataBuilder(PhantomData); impl ParaStoredHeaderDataBuilder for SingleParaStoredHeaderDataBuilder { fn max_free_head_size() -> u32 { C::MAX_HEADER_SIZE } fn supported_teyrchains() -> u32 { 1 } fn try_build(para_id: ParaId, para_head: &ParaHead) -> Option { if para_id == ParaId(C::TEYRCHAIN_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(Teyrchain)] impl ParaStoredHeaderDataBuilder for C { fn max_free_head_size() -> u32 { let mut result = 0_u32; for_tuples!( #( result = pezsp_std::cmp::max( result, SingleParaStoredHeaderDataBuilder::::max_free_head_size(), ); )* ); result } fn supported_teyrchains() -> u32 { let mut result = 0; for_tuples!( #( result += SingleParaStoredHeaderDataBuilder::::supported_teyrchains(); )* ); result } 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 } } /// Runtime hook for when a teyrchain head is updated. pub trait OnNewHead { /// Called when a teyrchain head is updated. /// Returns the weight consumed by this function. fn on_new_head(id: ParaId, head: &ParaHead) -> Weight; } #[impl_trait_for_tuples::impl_for_tuples(8)] impl OnNewHead for Tuple { fn on_new_head(id: ParaId, head: &ParaHead) -> Weight { let mut weight: Weight = Default::default(); for_tuples!( #( weight.saturating_accrue(Tuple::on_new_head(id, head)); )* ); weight } }