// 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 .
use crate::calls::UtilityCall;
use bp_header_chain::ChainWithGrandpa as ChainWithGrandpaBase;
use bp_messages::ChainWithMessages as ChainWithMessagesBase;
use bp_runtime::{
Chain as ChainBase, EncodedOrDecodedCall, HashOf, Parachain as ParachainBase, TransactionEra,
TransactionEraOf, UnderlyingChainProvider,
};
use codec::{Codec, Decode, Encode};
use jsonrpsee::core::{DeserializeOwned, Serialize};
use num_traits::Zero;
use sc_transaction_pool_api::TransactionStatus;
use scale_info::TypeInfo;
use sp_core::{storage::StorageKey, Pair};
use sp_runtime::{
generic::SignedBlock,
traits::{Block as BlockT, Member},
ConsensusEngineId, EncodedJustification,
};
use std::{fmt::Debug, time::Duration};
/// Substrate-based chain from minimal relay-client point of view.
pub trait Chain: ChainBase + Clone {
/// Chain name.
const NAME: &'static str;
/// Name of the runtime API method that is returning best known finalized header number
/// and hash (as tuple).
///
/// Keep in mind that this method is normally provided by the other chain, which is
/// bridged with this chain.
const BEST_FINALIZED_HEADER_ID_METHOD: &'static str;
/// Name of the runtime API method that is returning interval between source chain
/// headers that may be submitted for free to the target chain.
///
/// Keep in mind that this method is normally provided by the other chain, which is
/// bridged with this chain.
const FREE_HEADERS_INTERVAL_METHOD: &'static str;
/// Average block interval.
///
/// How often blocks are produced on that chain. It's suggested to set this value
/// to match the block time of the chain.
const AVERAGE_BLOCK_INTERVAL: Duration;
/// Block type.
type SignedBlock: Member + Serialize + DeserializeOwned + BlockWithJustification;
/// The aggregated `Call` type.
type Call: Clone + Codec + Debug + Send + Sync;
}
/// Substrate-based relay chain that supports parachains.
///
/// We assume that the parachains are supported using `runtime_parachains::paras` pallet.
pub trait RelayChain: Chain {
/// Name of the `runtime_parachains::paras` pallet in the runtime of this chain.
const PARAS_PALLET_NAME: &'static str;
}
/// Substrate-based chain that is using direct GRANDPA finality from minimal relay-client point of
/// view.
///
/// Keep in mind that parachains are relying on relay chain GRANDPA, so they should not implement
/// this trait.
pub trait ChainWithGrandpa: Chain + ChainWithGrandpaBase {
/// Name of the runtime API method that is returning the GRANDPA info associated with the
/// headers accepted by the `submit_finality_proofs` extrinsic in the queried block.
///
/// Keep in mind that this method is normally provided by the other chain, which is
/// bridged with this chain.
const SYNCED_HEADERS_GRANDPA_INFO_METHOD: &'static str;
/// The type of the key owner proof used by the grandpa engine.
type KeyOwnerProof: Decode + TypeInfo + Send;
}
/// Substrate-based parachain from minimal relay-client point of view.
pub trait Parachain: Chain + ParachainBase {}
impl Parachain for T where T: UnderlyingChainProvider + Chain + ParachainBase {}
/// Substrate-based chain with messaging support from minimal relay-client point of view.
pub trait ChainWithMessages: Chain + ChainWithMessagesBase {
// TODO (https://github.com/paritytech/parity-bridges-common/issues/1692): check all the names
// after the issue is fixed - all names must be changed
/// Name of the bridge relayers pallet (used in `construct_runtime` macro call) that is deployed
/// at some other chain to bridge with this `ChainWithMessages`.
///
/// We assume that all chains that are bridging with this `ChainWithMessages` are using
/// the same name.
const WITH_CHAIN_RELAYERS_PALLET_NAME: Option<&'static str>;
/// Name of the `ToOutboundLaneApi::message_details` runtime API method.
/// The method is provided by the runtime that is bridged with this `ChainWithMessages`.
const TO_CHAIN_MESSAGE_DETAILS_METHOD: &'static str;
/// Name of the `FromInboundLaneApi::message_details` runtime API method.
/// The method is provided by the runtime that is bridged with this `ChainWithMessages`.
const FROM_CHAIN_MESSAGE_DETAILS_METHOD: &'static str;
}
/// Call type used by the chain.
pub type CallOf = ::Call;
/// Transaction status of the chain.
pub type TransactionStatusOf = TransactionStatus, HashOf>;
/// Substrate-based chain with `AccountData` generic argument of `frame_system::AccountInfo` set to
/// the `pallet_balances::AccountData`.
pub trait ChainWithBalances: Chain {
/// Return runtime storage key for getting `frame_system::AccountInfo` of given account.
fn account_info_storage_key(account_id: &Self::AccountId) -> StorageKey;
}
/// SCALE-encoded extrinsic.
pub type EncodedExtrinsic = Vec;
/// Block with justification.
pub trait BlockWithJustification {
/// Return block header.
fn header(&self) -> Header;
/// Return encoded block extrinsics.
fn extrinsics(&self) -> Vec;
/// Return block justification, if known.
fn justification(&self, engine_id: ConsensusEngineId) -> Option<&EncodedJustification>;
}
/// Transaction before it is signed.
#[derive(Clone, Debug, PartialEq)]
pub struct UnsignedTransaction {
/// Runtime call of this transaction.
pub call: EncodedOrDecodedCall,
/// Transaction nonce.
pub nonce: C::Nonce,
/// Tip included into transaction.
pub tip: C::Balance,
/// Transaction era used by the chain.
pub era: TransactionEraOf,
}
impl UnsignedTransaction {
/// Create new unsigned transaction with given call, nonce, era and zero tip.
pub fn new(call: EncodedOrDecodedCall, nonce: C::Nonce) -> Self {
Self { call, nonce, era: TransactionEra::Immortal, tip: Zero::zero() }
}
/// Convert to the transaction of the other compatible chain.
pub fn switch_chain(self) -> UnsignedTransaction
where
Other: Chain<
Nonce = C::Nonce,
Balance = C::Balance,
BlockNumber = C::BlockNumber,
Hash = C::Hash,
>,
{
UnsignedTransaction {
call: EncodedOrDecodedCall::Encoded(self.call.into_encoded()),
nonce: self.nonce,
tip: self.tip,
era: self.era,
}
}
/// Set transaction tip.
#[must_use]
pub fn tip(mut self, tip: C::Balance) -> Self {
self.tip = tip;
self
}
/// Set transaction era.
#[must_use]
pub fn era(mut self, era: TransactionEraOf) -> Self {
self.era = era;
self
}
}
/// Account key pair used by transactions signing scheme.
pub type AccountKeyPairOf = ::AccountKeyPair;
/// Substrate-based chain transactions signing scheme.
pub trait ChainWithTransactions: Chain {
/// Type of key pairs used to sign transactions.
type AccountKeyPair: Pair + Clone + Send + Sync;
/// Signed transaction.
type SignedTransaction: Clone + Debug + Codec + Send + 'static;
/// Create transaction for given runtime call, signed by given account.
fn sign_transaction(
param: SignParam,
unsigned: UnsignedTransaction,
) -> Result
where
Self: Sized;
}
/// Sign transaction parameters
pub struct SignParam {
/// Version of the runtime specification.
pub spec_version: u32,
/// Transaction version
pub transaction_version: u32,
/// Hash of the genesis block.
pub genesis_hash: HashOf,
/// Signer account
pub signer: AccountKeyPairOf,
}
impl BlockWithJustification for SignedBlock {
fn header(&self) -> Block::Header {
self.block.header().clone()
}
fn extrinsics(&self) -> Vec {
self.block.extrinsics().iter().map(Encode::encode).collect()
}
fn justification(&self, engine_id: ConsensusEngineId) -> Option<&EncodedJustification> {
self.justifications.as_ref().and_then(|j| j.get(engine_id))
}
}
/// Trait that provides functionality defined inside `pallet-utility`
pub trait UtilityPallet {
/// Create batch call from given calls vector.
fn build_batch_call(calls: Vec) -> C::Call;
}
/// Structure that implements `UtilityPalletProvider` based on a full runtime.
pub struct FullRuntimeUtilityPallet {
_phantom: std::marker::PhantomData,
}
impl UtilityPallet for FullRuntimeUtilityPallet
where
C: Chain,
R: pallet_utility::Config,
::RuntimeCall: From>,
{
fn build_batch_call(calls: Vec) -> C::Call {
pallet_utility::Call::batch_all { calls }.into()
}
}
/// Structure that implements `UtilityPalletProvider` based on a call conversion.
pub struct MockedRuntimeUtilityPallet {
_phantom: std::marker::PhantomData,
}
impl UtilityPallet for MockedRuntimeUtilityPallet
where
C: Chain,
C::Call: From>,
{
fn build_batch_call(calls: Vec) -> C::Call {
UtilityCall::batch_all(calls).into()
}
}
/// Substrate-based chain that uses `pallet-utility`.
pub trait ChainWithUtilityPallet: Chain {
/// The utility pallet provider.
type UtilityPallet: UtilityPallet;
}