Skip to content
...@@ -18,12 +18,13 @@ ...@@ -18,12 +18,13 @@
pub mod codegen_runtime; pub mod codegen_runtime;
use bp_polkadot_core::SuffixedCommonTransactionExtensionExt; use bp_polkadot_core::SuffixedCommonSignedExtensionExt;
use bp_rococo::ROCOCO_SYNCED_HEADERS_GRANDPA_INFO_METHOD; use bp_rococo::ROCOCO_SYNCED_HEADERS_GRANDPA_INFO_METHOD;
use codec::Encode; use codec::Encode;
use relay_substrate_client::{ use relay_substrate_client::{
Chain, ChainWithBalances, ChainWithGrandpa, ChainWithTransactions, Error as SubstrateError, Chain, ChainWithBalances, ChainWithGrandpa, ChainWithRuntimeVersion, ChainWithTransactions,
RelayChain, SignParam, UnderlyingChainProvider, UnsignedTransaction, Error as SubstrateError, RelayChain, SignParam, SimpleRuntimeVersion, UnderlyingChainProvider,
UnsignedTransaction,
}; };
use sp_core::{storage::StorageKey, Pair}; use sp_core::{storage::StorageKey, Pair};
use sp_runtime::{generic::SignedPayload, traits::IdentifyAccount, MultiAddress}; use sp_runtime::{generic::SignedPayload, traits::IdentifyAccount, MultiAddress};
...@@ -87,7 +88,7 @@ impl RelayChain for Rococo { ...@@ -87,7 +88,7 @@ impl RelayChain for Rococo {
impl ChainWithTransactions for Rococo { impl ChainWithTransactions for Rococo {
type AccountKeyPair = sp_core::sr25519::Pair; type AccountKeyPair = sp_core::sr25519::Pair;
type SignedTransaction = type SignedTransaction =
bp_polkadot_core::UncheckedExtrinsic<Self::Call, bp_rococo::TransactionExtension>; bp_polkadot_core::UncheckedExtrinsic<Self::Call, bp_rococo::SignedExtension>;
fn sign_transaction( fn sign_transaction(
param: SignParam<Self>, param: SignParam<Self>,
...@@ -95,7 +96,7 @@ impl ChainWithTransactions for Rococo { ...@@ -95,7 +96,7 @@ impl ChainWithTransactions for Rococo {
) -> Result<Self::SignedTransaction, SubstrateError> { ) -> Result<Self::SignedTransaction, SubstrateError> {
let raw_payload = SignedPayload::new( let raw_payload = SignedPayload::new(
unsigned.call, unsigned.call,
bp_rococo::TransactionExtension::from_params( bp_rococo::SignedExtension::from_params(
param.spec_version, param.spec_version,
param.transaction_version, param.transaction_version,
unsigned.era, unsigned.era,
...@@ -118,3 +119,8 @@ impl ChainWithTransactions for Rococo { ...@@ -118,3 +119,8 @@ impl ChainWithTransactions for Rococo {
)) ))
} }
} }
impl ChainWithRuntimeVersion for Rococo {
const RUNTIME_VERSION: Option<SimpleRuntimeVersion> =
Some(SimpleRuntimeVersion { spec_version: 1_009_000, transaction_version: 24 });
}
[package] [package]
name = "relay-westend-client" name = "relay-westend-client"
version = "0.1.0" version = "0.1.0"
authors = ["Parity Technologies <[email protected]>"] authors.workspace = true
edition = "2021" edition.workspace = true
license = "GPL-3.0-or-later WITH Classpath-exception-2.0" license = "GPL-3.0-or-later WITH Classpath-exception-2.0"
repository.workspace = true
[lints] [lints]
workspace = true workspace = true
[dependencies] [dependencies]
codec = { package = "parity-scale-codec", version = "3.1.5", features = ["derive"] } codec = { package = "parity-scale-codec", version = "3.6.1", features = ["derive"] }
scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] }
subxt = { version = "0.32.1", default-features = false, features = ["native"] } subxt = { version = "0.35.3", default-features = false, features = ["native"] }
# Bridge dependencies # Bridge dependencies
bp-polkadot-core = { path = "../../primitives/polkadot-core" } bp-polkadot-core = { git = "https://github.com/paritytech/polkadot-sdk", branch = "master" }
bp-runtime = { path = "../../primitives/runtime" } bp-runtime = { git = "https://github.com/paritytech/polkadot-sdk", branch = "master" }
bp-westend = { path = "../../primitives/chain-westend" } bp-westend = { git = "https://github.com/paritytech/polkadot-sdk", branch = "master" }
relay-substrate-client = { path = "../client-substrate" } relay-substrate-client = { git = "https://github.com/paritytech/polkadot-sdk", branch = "master" }
relay-utils = { path = "../utils" } relay-utils = { git = "https://github.com/paritytech/polkadot-sdk", branch = "master" }
# Substrate Dependencies # Substrate Dependencies
......
...@@ -18,12 +18,13 @@ ...@@ -18,12 +18,13 @@
pub mod codegen_runtime; pub mod codegen_runtime;
use bp_polkadot_core::SuffixedCommonTransactionExtensionExt; use bp_polkadot_core::SuffixedCommonSignedExtensionExt;
use bp_westend::WESTEND_SYNCED_HEADERS_GRANDPA_INFO_METHOD; use bp_westend::WESTEND_SYNCED_HEADERS_GRANDPA_INFO_METHOD;
use codec::Encode; use codec::Encode;
use relay_substrate_client::{ use relay_substrate_client::{
Chain, ChainWithBalances, ChainWithGrandpa, ChainWithTransactions, Error as SubstrateError, Chain, ChainWithBalances, ChainWithGrandpa, ChainWithRuntimeVersion, ChainWithTransactions,
RelayChain, SignParam, UnderlyingChainProvider, UnsignedTransaction, Error as SubstrateError, RelayChain, SignParam, SimpleRuntimeVersion, UnderlyingChainProvider,
UnsignedTransaction,
}; };
use sp_core::{storage::StorageKey, Pair}; use sp_core::{storage::StorageKey, Pair};
use sp_runtime::{generic::SignedPayload, traits::IdentifyAccount, MultiAddress}; use sp_runtime::{generic::SignedPayload, traits::IdentifyAccount, MultiAddress};
...@@ -87,7 +88,7 @@ impl ChainWithBalances for Westend { ...@@ -87,7 +88,7 @@ impl ChainWithBalances for Westend {
impl ChainWithTransactions for Westend { impl ChainWithTransactions for Westend {
type AccountKeyPair = sp_core::sr25519::Pair; type AccountKeyPair = sp_core::sr25519::Pair;
type SignedTransaction = type SignedTransaction =
bp_polkadot_core::UncheckedExtrinsic<Self::Call, bp_westend::TransactionExtension>; bp_polkadot_core::UncheckedExtrinsic<Self::Call, bp_westend::SignedExtension>;
fn sign_transaction( fn sign_transaction(
param: SignParam<Self>, param: SignParam<Self>,
...@@ -95,7 +96,7 @@ impl ChainWithTransactions for Westend { ...@@ -95,7 +96,7 @@ impl ChainWithTransactions for Westend {
) -> Result<Self::SignedTransaction, SubstrateError> { ) -> Result<Self::SignedTransaction, SubstrateError> {
let raw_payload = SignedPayload::new( let raw_payload = SignedPayload::new(
unsigned.call, unsigned.call,
bp_westend::TransactionExtension::from_params( bp_westend::SignedExtension::from_params(
param.spec_version, param.spec_version,
param.transaction_version, param.transaction_version,
unsigned.era, unsigned.era,
...@@ -118,3 +119,8 @@ impl ChainWithTransactions for Westend { ...@@ -118,3 +119,8 @@ impl ChainWithTransactions for Westend {
)) ))
} }
} }
impl ChainWithRuntimeVersion for Westend {
const RUNTIME_VERSION: Option<SimpleRuntimeVersion> =
Some(SimpleRuntimeVersion { spec_version: 1_009_000, transaction_version: 24 });
}
[package]
name = "substrate-relay"
version = "1.2.0"
authors = ["Parity Technologies <[email protected]>"]
edition = "2021"
license = "GPL-3.0-or-later WITH Classpath-exception-2.0"
[lints]
workspace = true
[dependencies]
anyhow = "1.0"
async-std = "1.9.0"
async-trait = "0.1"
codec = { package = "parity-scale-codec", version = "3.1.5" }
env_logger = "0.11"
futures = "0.3.30"
hex = "0.4"
log = { workspace = true }
num-format = "0.4"
num-traits = "0.2"
rbtag = "0.3"
structopt = "0.3"
signal-hook = "0.3.15"
signal-hook-async-std = "0.2.2"
strum = { version = "0.26.2", features = ["derive"] }
# Bridge dependencies
bp-bridge-hub-polkadot = { path = "../../primitives/chain-bridge-hub-polkadot" }
bp-bridge-hub-rococo = { path = "../../primitives/chain-bridge-hub-rococo" }
bp-header-chain = { path = "../../primitives/header-chain" }
bp-messages = { path = "../../primitives/messages" }
bp-parachains = { path = "../../primitives/parachains" }
bp-polkadot-bulletin = { path = "../../primitives/chain-polkadot-bulletin" }
bp-polkadot = { path = "../../primitives/chain-polkadot" }
bp-polkadot-core = { path = "../../primitives/polkadot-core" }
bp-rococo = { path = "../../primitives/chain-rococo" }
bp-runtime = { path = "../../primitives/runtime" }
bridge-runtime-common = { path = "../../bin/runtime-common" }
pallet-bridge-parachains = { path = "../../modules/parachains" }
parachains-relay = { path = "../parachains" }
relay-bridge-hub-kusama-client = { path = "../client-bridge-hub-kusama" }
relay-bridge-hub-polkadot-client = { path = "../client-bridge-hub-polkadot" }
relay-bridge-hub-rococo-client = { path = "../client-bridge-hub-rococo" }
relay-bridge-hub-westend-client = { path = "../client-bridge-hub-westend" }
relay-kusama-client = { path = "../client-kusama" }
relay-polkadot-client = { path = "../client-polkadot" }
relay-polkadot-bulletin-client = { path = "../client-polkadot-bulletin" }
relay-rococo-client = { path = "../client-rococo" }
relay-substrate-client = { path = "../client-substrate" }
relay-utils = { path = "../utils" }
relay-westend-client = { path = "../client-westend" }
substrate-relay-helper = { path = "../lib-substrate-relay" }
# Substrate Dependencies
frame-support = { git = "https://github.com/paritytech/polkadot-sdk", branch = "master" }
sp-core = { git = "https://github.com/paritytech/polkadot-sdk", branch = "master" }
sp-runtime = { git = "https://github.com/paritytech/polkadot-sdk", branch = "master" }
[dev-dependencies]
bp-test-utils = { path = "../../primitives/test-utils" }
hex-literal = "0.4"
sp-keyring = { git = "https://github.com/paritytech/polkadot-sdk", branch = "master" }
tempfile = "3.10"
finality-grandpa = { version = "0.16.2" }
// Copyright 2022 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 <http://www.gnu.org/licenses/>.
//! Kusama + Kusama parachains specification for CLI.
use crate::cli::CliChain;
use relay_bridge_hub_kusama_client::BridgeHubKusama;
use relay_kusama_client::Kusama;
use relay_substrate_client::SimpleRuntimeVersion;
impl CliChain for Kusama {
const RUNTIME_VERSION: Option<SimpleRuntimeVersion> =
Some(SimpleRuntimeVersion { spec_version: 1_001_002, transaction_version: 25 });
}
impl CliChain for BridgeHubKusama {
const RUNTIME_VERSION: Option<SimpleRuntimeVersion> =
Some(SimpleRuntimeVersion { spec_version: 1_001_000, transaction_version: 4 });
}
// 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 <http://www.gnu.org/licenses/>.
//! Chain-specific relayer configuration.
mod kusama;
mod polkadot;
mod polkadot_bulletin;
mod rococo;
mod westend;
// Copyright 2022 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 <http://www.gnu.org/licenses/>.
//! Polkadot + Polkadot parachains specification for CLI.
use crate::cli::CliChain;
use relay_bridge_hub_polkadot_client::BridgeHubPolkadot;
use relay_polkadot_client::Polkadot;
use relay_substrate_client::SimpleRuntimeVersion;
impl CliChain for Polkadot {
const RUNTIME_VERSION: Option<SimpleRuntimeVersion> =
Some(SimpleRuntimeVersion { spec_version: 1_001_002, transaction_version: 25 });
}
impl CliChain for BridgeHubPolkadot {
const RUNTIME_VERSION: Option<SimpleRuntimeVersion> =
Some(SimpleRuntimeVersion { spec_version: 1_001_000, transaction_version: 3 });
}
// Copyright 2022 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 <http://www.gnu.org/licenses/>.
//! Polkadot + Polkadot parachains specification for CLI.
use crate::cli::CliChain;
use relay_polkadot_bulletin_client::PolkadotBulletin;
use relay_substrate_client::SimpleRuntimeVersion;
impl CliChain for PolkadotBulletin {
const RUNTIME_VERSION: Option<SimpleRuntimeVersion> =
Some(SimpleRuntimeVersion { spec_version: 100, transaction_version: 1 });
}
// Copyright 2022 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 <http://www.gnu.org/licenses/>.
//! Rococo + Rococo parachains specification for CLI.
use crate::cli::CliChain;
use relay_bridge_hub_rococo_client::BridgeHubRococo;
use relay_rococo_client::Rococo;
use relay_substrate_client::SimpleRuntimeVersion;
impl CliChain for Rococo {
const RUNTIME_VERSION: Option<SimpleRuntimeVersion> =
Some(SimpleRuntimeVersion { spec_version: 1_008_000, transaction_version: 24 });
}
impl CliChain for BridgeHubRococo {
const RUNTIME_VERSION: Option<SimpleRuntimeVersion> =
Some(SimpleRuntimeVersion { spec_version: 1_008_000, transaction_version: 4 });
}
// 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 <http://www.gnu.org/licenses/>.
//! Westend chain specification for CLI.
use crate::cli::CliChain;
use relay_bridge_hub_westend_client::BridgeHubWestend;
use relay_substrate_client::SimpleRuntimeVersion;
use relay_westend_client::Westend;
impl CliChain for Westend {
const RUNTIME_VERSION: Option<SimpleRuntimeVersion> =
Some(SimpleRuntimeVersion { spec_version: 1_008_000, transaction_version: 24 });
}
impl CliChain for BridgeHubWestend {
const RUNTIME_VERSION: Option<SimpleRuntimeVersion> =
Some(SimpleRuntimeVersion { spec_version: 1_008_000, transaction_version: 4 });
}
// 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 <http://www.gnu.org/licenses/>.
use crate::cli::CliChain;
use pallet_bridge_parachains::{RelayBlockHash, RelayBlockHasher, RelayBlockNumber};
use relay_substrate_client::{Chain, ChainWithTransactions, Parachain, RelayChain};
use strum::{EnumString, VariantNames};
use substrate_relay_helper::{
equivocation::SubstrateEquivocationDetectionPipeline,
finality::SubstrateFinalitySyncPipeline,
messages_lane::{MessagesRelayLimits, SubstrateMessageLane},
parachains::SubstrateParachainsPipeline,
};
#[derive(Debug, PartialEq, Eq, EnumString, VariantNames)]
#[strum(serialize_all = "kebab_case")]
/// Supported full bridges (headers + messages).
pub enum FullBridge {
BridgeHubRococoToBridgeHubWestend,
BridgeHubWestendToBridgeHubRococo,
BridgeHubKusamaToBridgeHubPolkadot,
BridgeHubPolkadotToBridgeHubKusama,
PolkadotBulletinToBridgeHubPolkadot,
BridgeHubPolkadotToPolkadotBulletin,
RococoBulletinToBridgeHubRococo,
BridgeHubRococoToRococoBulletin,
}
/// Minimal bridge representation that can be used from the CLI.
/// It connects a source chain to a target chain.
pub trait CliBridgeBase: Sized {
/// The source chain.
type Source: Chain + CliChain;
/// The target chain.
type Target: ChainWithTransactions + CliChain;
}
/// Bridge representation that can be used from the CLI for relaying headers
/// from a relay chain to a relay chain.
pub trait RelayToRelayHeadersCliBridge: CliBridgeBase {
/// Finality proofs synchronization pipeline.
type Finality: SubstrateFinalitySyncPipeline<
SourceChain = Self::Source,
TargetChain = Self::Target,
>;
}
/// Convenience trait that adds bounds to `CliBridgeBase`.
pub trait RelayToRelayEquivocationDetectionCliBridgeBase: CliBridgeBase {
type BoundedSource: ChainWithTransactions;
}
impl<T> RelayToRelayEquivocationDetectionCliBridgeBase for T
where
T: CliBridgeBase,
T::Source: ChainWithTransactions,
{
type BoundedSource = T::Source;
}
/// Bridge representation that can be used from the CLI for detecting equivocations
/// in the headers synchronized from a relay chain to a relay chain.
pub trait RelayToRelayEquivocationDetectionCliBridge:
RelayToRelayEquivocationDetectionCliBridgeBase
{
/// Equivocation detection pipeline.
type Equivocation: SubstrateEquivocationDetectionPipeline<
SourceChain = Self::Source,
TargetChain = Self::Target,
>;
}
/// Bridge representation that can be used from the CLI for relaying headers
/// from a parachain to a relay chain.
pub trait ParachainToRelayHeadersCliBridge: CliBridgeBase
where
Self::Source: Parachain,
{
// The `CliBridgeBase` type represents the parachain in this situation.
// We need to add an extra type for the relay chain.
type SourceRelay: Chain<BlockNumber = RelayBlockNumber, Hash = RelayBlockHash, Hasher = RelayBlockHasher>
+ CliChain
+ RelayChain;
/// Finality proofs synchronization pipeline (source parachain -> target).
type ParachainFinality: SubstrateParachainsPipeline<
SourceRelayChain = Self::SourceRelay,
SourceParachain = Self::Source,
TargetChain = Self::Target,
>;
/// Finality proofs synchronization pipeline (source relay chain -> target).
type RelayFinality: SubstrateFinalitySyncPipeline<
SourceChain = Self::SourceRelay,
TargetChain = Self::Target,
>;
}
/// Bridge representation that can be used from the CLI for relaying messages.
pub trait MessagesCliBridge: CliBridgeBase {
/// The Source -> Destination messages synchronization pipeline.
type MessagesLane: SubstrateMessageLane<SourceChain = Self::Source, TargetChain = Self::Target>;
/// Optional messages delivery transaction limits that the messages relay is going
/// to use. If it returns `None`, limits are estimated using `TransactionPayment` API
/// at the target chain.
fn maybe_messages_limits() -> Option<MessagesRelayLimits> {
None
}
}
// Copyright 2019-2022 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 <http://www.gnu.org/licenses/>.
use relay_substrate_client::{AccountKeyPairOf, ChainWithTransactions};
use structopt::StructOpt;
use strum::{EnumString, VariantNames};
use crate::cli::CliChain;
pub use relay_substrate_client::{ChainRuntimeVersion, SimpleRuntimeVersion};
use substrate_relay_helper::TransactionParams;
#[doc = "Runtime version params."]
#[derive(StructOpt, Debug, PartialEq, Eq, Clone, Copy, EnumString, VariantNames)]
pub enum RuntimeVersionType {
/// Auto query version from chain
Auto,
/// Custom `spec_version` and `transaction_version`
Custom,
/// Read version from bundle dependencies directly.
Bundle,
}
/// Create chain-specific set of runtime version parameters.
#[macro_export]
macro_rules! declare_chain_runtime_version_params_cli_schema {
($chain:ident, $chain_prefix:ident) => {
bp_runtime::paste::item! {
#[doc = $chain " runtime version params."]
#[derive(StructOpt, Debug, PartialEq, Eq, Clone, Copy)]
pub struct [<$chain RuntimeVersionParams>] {
#[doc = "The type of runtime version for chain " $chain]
#[structopt(long, default_value = "Bundle")]
pub [<$chain_prefix _version_mode>]: RuntimeVersionType,
#[doc = "The custom sepc_version for chain " $chain]
#[structopt(long)]
pub [<$chain_prefix _spec_version>]: Option<u32>,
#[doc = "The custom transaction_version for chain " $chain]
#[structopt(long)]
pub [<$chain_prefix _transaction_version>]: Option<u32>,
}
impl [<$chain RuntimeVersionParams>] {
/// Converts self into `ChainRuntimeVersion`.
pub fn into_runtime_version(
self,
bundle_runtime_version: Option<SimpleRuntimeVersion>,
) -> anyhow::Result<ChainRuntimeVersion> {
Ok(match self.[<$chain_prefix _version_mode>] {
RuntimeVersionType::Auto => ChainRuntimeVersion::Auto,
RuntimeVersionType::Custom => {
let custom_spec_version = self.[<$chain_prefix _spec_version>]
.ok_or_else(|| anyhow::Error::msg(format!("The {}-spec-version is required when choose custom mode", stringify!($chain_prefix))))?;
let custom_transaction_version = self.[<$chain_prefix _transaction_version>]
.ok_or_else(|| anyhow::Error::msg(format!("The {}-transaction-version is required when choose custom mode", stringify!($chain_prefix))))?;
ChainRuntimeVersion::Custom(
SimpleRuntimeVersion {
spec_version: custom_spec_version,
transaction_version: custom_transaction_version
}
)
},
RuntimeVersionType::Bundle => match bundle_runtime_version {
Some(runtime_version) => ChainRuntimeVersion::Custom(runtime_version),
None => {
return Err(anyhow::format_err!("Cannot use bundled runtime version of {}: it is not known to the relay", stringify!($chain_prefix)));
}
},
})
}
}
}
};
}
/// Create chain-specific set of runtime version parameters.
#[macro_export]
macro_rules! declare_chain_connection_params_cli_schema {
($chain:ident, $chain_prefix:ident) => {
bp_runtime::paste::item! {
#[doc = $chain " connection params."]
#[derive(StructOpt, Debug, PartialEq, Eq, Clone)]
pub struct [<$chain ConnectionParams>] {
#[doc = "Connect to " $chain " node at given host."]
#[structopt(long, default_value = "127.0.0.1")]
pub [<$chain_prefix _host>]: String,
#[doc = "Connect to " $chain " node websocket server at given port."]
#[structopt(long, default_value = "9944")]
pub [<$chain_prefix _port>]: u16,
#[doc = "Use secure websocket connection."]
#[structopt(long)]
pub [<$chain_prefix _secure>]: bool,
#[doc = "Custom runtime version"]
#[structopt(flatten)]
pub [<$chain_prefix _runtime_version>]: [<$chain RuntimeVersionParams>],
}
impl [<$chain ConnectionParams>] {
/// Convert connection params into Substrate client.
#[allow(dead_code)]
pub async fn into_client<Chain: CliChain>(
self,
) -> anyhow::Result<relay_substrate_client::Client<Chain>> {
let chain_runtime_version = self
.[<$chain_prefix _runtime_version>]
.into_runtime_version(Chain::RUNTIME_VERSION)?;
Ok(relay_substrate_client::Client::new(relay_substrate_client::ConnectionParams {
host: self.[<$chain_prefix _host>],
port: self.[<$chain_prefix _port>],
secure: self.[<$chain_prefix _secure>],
chain_runtime_version,
})
.await
)
}
}
}
};
}
/// Create chain-specific set of signing parameters.
#[macro_export]
macro_rules! declare_chain_signing_params_cli_schema {
($chain:ident, $chain_prefix:ident) => {
bp_runtime::paste::item! {
#[doc = $chain " signing params."]
#[derive(StructOpt, Debug, PartialEq, Eq, Clone)]
pub struct [<$chain SigningParams>] {
#[doc = "The SURI of secret key to use when transactions are submitted to the " $chain " node."]
#[structopt(long)]
pub [<$chain_prefix _signer>]: Option<String>,
#[doc = "The password for the SURI of secret key to use when transactions are submitted to the " $chain " node."]
#[structopt(long)]
pub [<$chain_prefix _signer_password>]: Option<String>,
#[doc = "Path to the file, that contains SURI of secret key to use when transactions are submitted to the " $chain " node. Can be overridden with " $chain_prefix "_signer option."]
#[structopt(long)]
pub [<$chain_prefix _signer_file>]: Option<std::path::PathBuf>,
#[doc = "Path to the file, that password for the SURI of secret key to use when transactions are submitted to the " $chain " node. Can be overridden with " $chain_prefix "_signer_password option."]
#[structopt(long)]
pub [<$chain_prefix _signer_password_file>]: Option<std::path::PathBuf>,
#[doc = "Transactions mortality period, in blocks. MUST be a power of two in [4; 65536] range. MAY NOT be larger than `BlockHashCount` parameter of the chain system module."]
#[structopt(long)]
pub [<$chain_prefix _transactions_mortality>]: Option<u32>,
}
impl [<$chain SigningParams>] {
/// Return transactions mortality.
#[allow(dead_code)]
pub fn transactions_mortality(&self) -> anyhow::Result<Option<u32>> {
self.[<$chain_prefix _transactions_mortality>]
.map(|transactions_mortality| {
if !(4..=65536).contains(&transactions_mortality)
|| !transactions_mortality.is_power_of_two()
{
Err(anyhow::format_err!(
"Transactions mortality {} is not a power of two in a [4; 65536] range",
transactions_mortality,
))
} else {
Ok(transactions_mortality)
}
})
.transpose()
}
/// Parse signing params into chain-specific KeyPair.
#[allow(dead_code)]
pub fn to_keypair<Chain: ChainWithTransactions>(&self) -> anyhow::Result<AccountKeyPairOf<Chain>> {
let suri = match (self.[<$chain_prefix _signer>].as_ref(), self.[<$chain_prefix _signer_file>].as_ref()) {
(Some(suri), _) => suri.to_owned(),
(None, Some(suri_file)) => std::fs::read_to_string(suri_file)
.map_err(|err| anyhow::format_err!(
"Failed to read SURI from file {:?}: {}",
suri_file,
err,
))?,
(None, None) => return Err(anyhow::format_err!(
"One of options must be specified: '{}' or '{}'",
stringify!([<$chain_prefix _signer>]),
stringify!([<$chain_prefix _signer_file>]),
)),
};
let suri_password = match (
self.[<$chain_prefix _signer_password>].as_ref(),
self.[<$chain_prefix _signer_password_file>].as_ref(),
) {
(Some(suri_password), _) => Some(suri_password.to_owned()),
(None, Some(suri_password_file)) => std::fs::read_to_string(suri_password_file)
.map(Some)
.map_err(|err| anyhow::format_err!(
"Failed to read SURI password from file {:?}: {}",
suri_password_file,
err,
))?,
_ => None,
};
use sp_core::crypto::Pair;
AccountKeyPairOf::<Chain>::from_string(
&suri,
suri_password.as_deref()
).map_err(|e| anyhow::format_err!("{:?}", e))
}
/// Return transaction parameters.
#[allow(dead_code)]
pub fn transaction_params<Chain: ChainWithTransactions>(
&self,
) -> anyhow::Result<TransactionParams<AccountKeyPairOf<Chain>>> {
Ok(TransactionParams {
mortality: self.transactions_mortality()?,
signer: self.to_keypair::<Chain>()?,
})
}
}
}
};
}
/// Create chain-specific set of configuration objects: connection parameters,
/// signing parameters and bridge initialization parameters.
#[macro_export]
macro_rules! declare_chain_cli_schema {
($chain:ident, $chain_prefix:ident) => {
$crate::declare_chain_runtime_version_params_cli_schema!($chain, $chain_prefix);
$crate::declare_chain_connection_params_cli_schema!($chain, $chain_prefix);
$crate::declare_chain_signing_params_cli_schema!($chain, $chain_prefix);
};
}
declare_chain_cli_schema!(Source, source);
declare_chain_cli_schema!(Target, target);
declare_chain_cli_schema!(Relaychain, relaychain);
declare_chain_cli_schema!(Parachain, parachain);
#[cfg(test)]
mod tests {
use super::*;
use sp_core::Pair;
#[test]
fn reads_suri_from_file() {
const ALICE: &str = "//Alice";
const BOB: &str = "//Bob";
const ALICE_PASSWORD: &str = "alice_password";
const BOB_PASSWORD: &str = "bob_password";
let alice: sp_core::sr25519::Pair = Pair::from_string(ALICE, Some(ALICE_PASSWORD)).unwrap();
let bob: sp_core::sr25519::Pair = Pair::from_string(BOB, Some(BOB_PASSWORD)).unwrap();
let bob_with_alice_password =
sp_core::sr25519::Pair::from_string(BOB, Some(ALICE_PASSWORD)).unwrap();
let temp_dir = tempfile::tempdir().unwrap();
let mut suri_file_path = temp_dir.path().to_path_buf();
let mut password_file_path = temp_dir.path().to_path_buf();
suri_file_path.push("suri");
password_file_path.push("password");
std::fs::write(&suri_file_path, BOB.as_bytes()).unwrap();
std::fs::write(&password_file_path, BOB_PASSWORD.as_bytes()).unwrap();
// when both seed and password are read from file
assert_eq!(
TargetSigningParams {
target_signer: Some(ALICE.into()),
target_signer_password: Some(ALICE_PASSWORD.into()),
target_signer_file: None,
target_signer_password_file: None,
target_transactions_mortality: None,
}
.to_keypair::<relay_polkadot_client::Polkadot>()
.map(|p| p.public())
.map_err(drop),
Ok(alice.public()),
);
// when both seed and password are read from file
assert_eq!(
TargetSigningParams {
target_signer: None,
target_signer_password: None,
target_signer_file: Some(suri_file_path.clone()),
target_signer_password_file: Some(password_file_path.clone()),
target_transactions_mortality: None,
}
.to_keypair::<relay_polkadot_client::Polkadot>()
.map(|p| p.public())
.map_err(drop),
Ok(bob.public()),
);
// when password are is overriden by cli option
assert_eq!(
TargetSigningParams {
target_signer: None,
target_signer_password: Some(ALICE_PASSWORD.into()),
target_signer_file: Some(suri_file_path.clone()),
target_signer_password_file: Some(password_file_path.clone()),
target_transactions_mortality: None,
}
.to_keypair::<relay_polkadot_client::Polkadot>()
.map(|p| p.public())
.map_err(drop),
Ok(bob_with_alice_password.public()),
);
// when both seed and password are overriden by cli options
assert_eq!(
TargetSigningParams {
target_signer: Some(ALICE.into()),
target_signer_password: Some(ALICE_PASSWORD.into()),
target_signer_file: Some(suri_file_path),
target_signer_password_file: Some(password_file_path),
target_transactions_mortality: None,
}
.to_keypair::<relay_polkadot_client::Polkadot>()
.map(|p| p.public())
.map_err(drop),
Ok(alice.public()),
);
}
}
// Copyright 2019-2022 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 <http://www.gnu.org/licenses/>.
use async_trait::async_trait;
use std::sync::Arc;
use crate::cli::{
bridge::{CliBridgeBase, MessagesCliBridge, ParachainToRelayHeadersCliBridge},
relay_headers_and_messages::{Full2WayBridgeBase, Full2WayBridgeCommonParams},
CliChain,
};
use bp_polkadot_core::parachains::ParaHash;
use pallet_bridge_parachains::{RelayBlockHash, RelayBlockHasher, RelayBlockNumber};
use relay_substrate_client::{
AccountIdOf, AccountKeyPairOf, Chain, ChainWithTransactions, Client, Parachain,
};
use sp_core::Pair;
use substrate_relay_helper::{
finality::SubstrateFinalitySyncPipeline,
on_demand::{
headers::OnDemandHeadersRelay, parachains::OnDemandParachainsRelay, OnDemandRelay,
},
};
/// A base relay between two parachain from different consensus systems.
///
/// Such relay starts 2 messages relay. It also starts 2 on-demand header relays and 2 on-demand
/// parachain heads relay.
pub struct ParachainToParachainBridge<
L2R: MessagesCliBridge + ParachainToRelayHeadersCliBridge,
R2L: MessagesCliBridge + ParachainToRelayHeadersCliBridge,
> where
<L2R as CliBridgeBase>::Source: Parachain,
<R2L as CliBridgeBase>::Source: Parachain,
{
/// Parameters that are shared by all bridge types.
pub common:
Full2WayBridgeCommonParams<<R2L as CliBridgeBase>::Target, <L2R as CliBridgeBase>::Target>,
/// Client of the left relay chain.
pub left_relay: Client<<L2R as ParachainToRelayHeadersCliBridge>::SourceRelay>,
/// Client of the right relay chain.
pub right_relay: Client<<R2L as ParachainToRelayHeadersCliBridge>::SourceRelay>,
}
macro_rules! declare_parachain_to_parachain_bridge_schema {
// left-parachain, relay-chain-of-left-parachain, right-parachain, relay-chain-of-right-parachain
($left_parachain:ident, $left_chain:ident, $right_parachain:ident, $right_chain:ident) => {
bp_runtime::paste::item! {
#[doc = $left_parachain ", " $left_chain ", " $right_parachain " and " $right_chain " headers+parachains+messages relay params."]
#[derive(Debug, PartialEq, StructOpt)]
pub struct [<$left_parachain $right_parachain HeadersAndMessages>] {
// shared parameters
#[structopt(flatten)]
shared: HeadersAndMessagesSharedParams,
#[structopt(flatten)]
left: [<$left_parachain ConnectionParams>],
// default signer, which is always used to sign messages relay transactions on the left chain
#[structopt(flatten)]
left_sign: [<$left_parachain SigningParams>],
#[structopt(flatten)]
left_relay: [<$left_chain ConnectionParams>],
#[structopt(flatten)]
right: [<$right_parachain ConnectionParams>],
// default signer, which is always used to sign messages relay transactions on the right chain
#[structopt(flatten)]
right_sign: [<$right_parachain SigningParams>],
#[structopt(flatten)]
right_relay: [<$right_chain ConnectionParams>],
}
impl [<$left_parachain $right_parachain HeadersAndMessages>] {
async fn into_bridge<
Left: ChainWithTransactions + CliChain + Parachain,
LeftRelay: CliChain,
Right: ChainWithTransactions + CliChain + Parachain,
RightRelay: CliChain,
L2R: CliBridgeBase<Source = Left, Target = Right>
+ MessagesCliBridge
+ ParachainToRelayHeadersCliBridge<SourceRelay = LeftRelay>,
R2L: CliBridgeBase<Source = Right, Target = Left>
+ MessagesCliBridge
+ ParachainToRelayHeadersCliBridge<SourceRelay = RightRelay>,
>(
self,
) -> anyhow::Result<ParachainToParachainBridge<L2R, R2L>> {
Ok(ParachainToParachainBridge {
common: Full2WayBridgeCommonParams::new::<L2R>(
self.shared,
BridgeEndCommonParams {
client: self.left.into_client::<Left>().await?,
tx_params: self.left_sign.transaction_params::<Left>()?,
accounts: vec![],
},
BridgeEndCommonParams {
client: self.right.into_client::<Right>().await?,
tx_params: self.right_sign.transaction_params::<Right>()?,
accounts: vec![],
},
)?,
left_relay: self.left_relay.into_client::<LeftRelay>().await?,
right_relay: self.right_relay.into_client::<RightRelay>().await?,
})
}
}
}
};
}
#[async_trait]
impl<
Left: Chain<Hash = ParaHash> + ChainWithTransactions + CliChain + Parachain,
Right: Chain<Hash = ParaHash> + ChainWithTransactions + CliChain + Parachain,
LeftRelay: Chain<BlockNumber = RelayBlockNumber, Hash = RelayBlockHash, Hasher = RelayBlockHasher>
+ CliChain,
RightRelay: Chain<BlockNumber = RelayBlockNumber, Hash = RelayBlockHash, Hasher = RelayBlockHasher>
+ CliChain,
L2R: CliBridgeBase<Source = Left, Target = Right>
+ MessagesCliBridge
+ ParachainToRelayHeadersCliBridge<SourceRelay = LeftRelay>,
R2L: CliBridgeBase<Source = Right, Target = Left>
+ MessagesCliBridge
+ ParachainToRelayHeadersCliBridge<SourceRelay = RightRelay>,
> Full2WayBridgeBase for ParachainToParachainBridge<L2R, R2L>
where
AccountIdOf<Left>: From<<AccountKeyPairOf<Left> as Pair>::Public>,
AccountIdOf<Right>: From<<AccountKeyPairOf<Right> as Pair>::Public>,
{
type Params = ParachainToParachainBridge<L2R, R2L>;
type Left = Left;
type Right = Right;
fn common(&self) -> &Full2WayBridgeCommonParams<Left, Right> {
&self.common
}
fn mut_common(&mut self) -> &mut Full2WayBridgeCommonParams<Self::Left, Self::Right> {
&mut self.common
}
async fn start_on_demand_headers_relayers(
&mut self,
) -> anyhow::Result<(
Arc<dyn OnDemandRelay<Self::Left, Self::Right>>,
Arc<dyn OnDemandRelay<Self::Right, Self::Left>>,
)> {
<L2R as ParachainToRelayHeadersCliBridge>::RelayFinality::start_relay_guards(
&self.common.right.client,
self.common.right.client.can_start_version_guard(),
)
.await?;
<R2L as ParachainToRelayHeadersCliBridge>::RelayFinality::start_relay_guards(
&self.common.left.client,
self.common.left.client.can_start_version_guard(),
)
.await?;
let left_relay_to_right_on_demand_headers =
OnDemandHeadersRelay::<<L2R as ParachainToRelayHeadersCliBridge>::RelayFinality>::new(
self.left_relay.clone(),
self.common.right.client.clone(),
self.common.right.tx_params.clone(),
self.common.shared.headers_to_relay(),
Some(self.common.metrics_params.clone()),
);
let right_relay_to_left_on_demand_headers =
OnDemandHeadersRelay::<<R2L as ParachainToRelayHeadersCliBridge>::RelayFinality>::new(
self.right_relay.clone(),
self.common.left.client.clone(),
self.common.left.tx_params.clone(),
self.common.shared.headers_to_relay(),
Some(self.common.metrics_params.clone()),
);
let left_to_right_on_demand_parachains = OnDemandParachainsRelay::<
<L2R as ParachainToRelayHeadersCliBridge>::ParachainFinality,
>::new(
self.left_relay.clone(),
self.common.right.client.clone(),
self.common.right.tx_params.clone(),
Arc::new(left_relay_to_right_on_demand_headers),
);
let right_to_left_on_demand_parachains = OnDemandParachainsRelay::<
<R2L as ParachainToRelayHeadersCliBridge>::ParachainFinality,
>::new(
self.right_relay.clone(),
self.common.left.client.clone(),
self.common.left.tx_params.clone(),
Arc::new(right_relay_to_left_on_demand_headers),
);
Ok((
Arc::new(left_to_right_on_demand_parachains),
Arc::new(right_to_left_on_demand_parachains),
))
}
}
// Copyright 2019-2022 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 <http://www.gnu.org/licenses/>.
use async_trait::async_trait;
use std::sync::Arc;
use crate::cli::{
bridge::{
CliBridgeBase, MessagesCliBridge, ParachainToRelayHeadersCliBridge,
RelayToRelayHeadersCliBridge,
},
relay_headers_and_messages::{Full2WayBridgeBase, Full2WayBridgeCommonParams},
CliChain,
};
use bp_polkadot_core::parachains::ParaHash;
use pallet_bridge_parachains::{RelayBlockHash, RelayBlockHasher, RelayBlockNumber};
use relay_substrate_client::{
AccountIdOf, AccountKeyPairOf, Chain, ChainWithTransactions, Client, Parachain,
};
use sp_core::Pair;
use substrate_relay_helper::{
finality::SubstrateFinalitySyncPipeline,
on_demand::{
headers::OnDemandHeadersRelay, parachains::OnDemandParachainsRelay, OnDemandRelay,
},
};
/// A base relay between standalone (relay) chain and a parachain from another consensus system.
///
/// Such relay starts 2 messages relay. It also starts 2 on-demand header relays and 1 on-demand
/// parachain heads relay.
pub struct RelayToParachainBridge<
L2R: MessagesCliBridge + RelayToRelayHeadersCliBridge,
R2L: MessagesCliBridge + ParachainToRelayHeadersCliBridge,
> where
<R2L as CliBridgeBase>::Source: Parachain,
{
/// Parameters that are shared by all bridge types.
pub common:
Full2WayBridgeCommonParams<<R2L as CliBridgeBase>::Target, <L2R as CliBridgeBase>::Target>,
/// Client of the right relay chain.
pub right_relay: Client<<R2L as ParachainToRelayHeadersCliBridge>::SourceRelay>,
}
macro_rules! declare_relay_to_parachain_bridge_schema {
// chain, parachain, relay-chain-of-parachain
($left_chain:ident, $right_parachain:ident, $right_chain:ident) => {
bp_runtime::paste::item! {
#[doc = $left_chain ", " $right_parachain " and " $right_chain " headers+parachains+messages relay params."]
#[derive(Debug, PartialEq, StructOpt)]
pub struct [<$left_chain $right_parachain HeadersAndMessages>] {
// shared parameters
#[structopt(flatten)]
shared: HeadersAndMessagesSharedParams,
#[structopt(flatten)]
left: [<$left_chain ConnectionParams>],
// default signer, which is always used to sign messages relay transactions on the left chain
#[structopt(flatten)]
left_sign: [<$left_chain SigningParams>],
#[structopt(flatten)]
right: [<$right_parachain ConnectionParams>],
// default signer, which is always used to sign messages relay transactions on the right chain
#[structopt(flatten)]
right_sign: [<$right_parachain SigningParams>],
#[structopt(flatten)]
right_relay: [<$right_chain ConnectionParams>],
}
impl [<$left_chain $right_parachain HeadersAndMessages>] {
async fn into_bridge<
Left: ChainWithTransactions + CliChain,
Right: ChainWithTransactions + CliChain + Parachain,
RightRelay: CliChain,
L2R: CliBridgeBase<Source = Left, Target = Right> + MessagesCliBridge + RelayToRelayHeadersCliBridge,
R2L: CliBridgeBase<Source = Right, Target = Left>
+ MessagesCliBridge
+ ParachainToRelayHeadersCliBridge<SourceRelay = RightRelay>,
>(
self,
) -> anyhow::Result<RelayToParachainBridge<L2R, R2L>> {
Ok(RelayToParachainBridge {
common: Full2WayBridgeCommonParams::new::<L2R>(
self.shared,
BridgeEndCommonParams {
client: self.left.into_client::<Left>().await?,
tx_params: self.left_sign.transaction_params::<Left>()?,
accounts: vec![],
},
BridgeEndCommonParams {
client: self.right.into_client::<Right>().await?,
tx_params: self.right_sign.transaction_params::<Right>()?,
accounts: vec![],
},
)?,
right_relay: self.right_relay.into_client::<RightRelay>().await?,
})
}
}
}
};
}
#[async_trait]
impl<
Left: ChainWithTransactions + CliChain,
Right: Chain<Hash = ParaHash> + ChainWithTransactions + CliChain + Parachain,
RightRelay: Chain<BlockNumber = RelayBlockNumber, Hash = RelayBlockHash, Hasher = RelayBlockHasher>
+ CliChain,
L2R: CliBridgeBase<Source = Left, Target = Right>
+ MessagesCliBridge
+ RelayToRelayHeadersCliBridge,
R2L: CliBridgeBase<Source = Right, Target = Left>
+ MessagesCliBridge
+ ParachainToRelayHeadersCliBridge<SourceRelay = RightRelay>,
> Full2WayBridgeBase for RelayToParachainBridge<L2R, R2L>
where
AccountIdOf<Left>: From<<AccountKeyPairOf<Left> as Pair>::Public>,
AccountIdOf<Right>: From<<AccountKeyPairOf<Right> as Pair>::Public>,
{
type Params = RelayToParachainBridge<L2R, R2L>;
type Left = Left;
type Right = Right;
fn common(&self) -> &Full2WayBridgeCommonParams<Left, Right> {
&self.common
}
fn mut_common(&mut self) -> &mut Full2WayBridgeCommonParams<Self::Left, Self::Right> {
&mut self.common
}
async fn start_on_demand_headers_relayers(
&mut self,
) -> anyhow::Result<(
Arc<dyn OnDemandRelay<Self::Left, Self::Right>>,
Arc<dyn OnDemandRelay<Self::Right, Self::Left>>,
)> {
<L2R as RelayToRelayHeadersCliBridge>::Finality::start_relay_guards(
&self.common.right.client,
self.common.right.client.can_start_version_guard(),
)
.await?;
<R2L as ParachainToRelayHeadersCliBridge>::RelayFinality::start_relay_guards(
&self.common.left.client,
self.common.left.client.can_start_version_guard(),
)
.await?;
let left_to_right_on_demand_headers =
OnDemandHeadersRelay::<<L2R as RelayToRelayHeadersCliBridge>::Finality>::new(
self.common.left.client.clone(),
self.common.right.client.clone(),
self.common.right.tx_params.clone(),
self.common.shared.headers_to_relay(),
None,
);
let right_relay_to_left_on_demand_headers =
OnDemandHeadersRelay::<<R2L as ParachainToRelayHeadersCliBridge>::RelayFinality>::new(
self.right_relay.clone(),
self.common.left.client.clone(),
self.common.left.tx_params.clone(),
self.common.shared.headers_to_relay(),
Some(self.common.metrics_params.clone()),
);
let right_to_left_on_demand_parachains = OnDemandParachainsRelay::<
<R2L as ParachainToRelayHeadersCliBridge>::ParachainFinality,
>::new(
self.right_relay.clone(),
self.common.left.client.clone(),
self.common.left.tx_params.clone(),
Arc::new(right_relay_to_left_on_demand_headers),
);
Ok((
Arc::new(left_to_right_on_demand_headers),
Arc::new(right_to_left_on_demand_parachains),
))
}
}
// Copyright 2019-2022 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 <http://www.gnu.org/licenses/>.
// we don't have any relay/standalone <> relay/standalone chain bridges, but we may need it in a
// future
#![allow(unused_macros)]
use async_trait::async_trait;
use std::sync::Arc;
use crate::cli::{
bridge::{CliBridgeBase, MessagesCliBridge, RelayToRelayHeadersCliBridge},
relay_headers_and_messages::{Full2WayBridgeBase, Full2WayBridgeCommonParams},
CliChain,
};
use relay_substrate_client::{AccountIdOf, AccountKeyPairOf, ChainWithTransactions};
use sp_core::Pair;
use substrate_relay_helper::{
finality::SubstrateFinalitySyncPipeline,
on_demand::{headers::OnDemandHeadersRelay, OnDemandRelay},
};
/// A base relay between two standalone (relay) chains.
///
/// Such relay starts 2 messages relay and 2 on-demand header relays.
pub struct RelayToRelayBridge<
L2R: MessagesCliBridge + RelayToRelayHeadersCliBridge,
R2L: MessagesCliBridge + RelayToRelayHeadersCliBridge,
> {
/// Parameters that are shared by all bridge types.
pub common:
Full2WayBridgeCommonParams<<R2L as CliBridgeBase>::Target, <L2R as CliBridgeBase>::Target>,
}
macro_rules! declare_relay_to_relay_bridge_schema {
($left_chain:ident, $right_chain:ident) => {
bp_runtime::paste::item! {
#[doc = $left_chain " and " $right_chain " headers+messages relay params."]
#[derive(Debug, PartialEq, StructOpt)]
pub struct [<$left_chain $right_chain HeadersAndMessages>] {
#[structopt(flatten)]
shared: HeadersAndMessagesSharedParams,
#[structopt(flatten)]
left: [<$left_chain ConnectionParams>],
// default signer, which is always used to sign messages relay transactions on the left chain
#[structopt(flatten)]
left_sign: [<$left_chain SigningParams>],
#[structopt(flatten)]
right: [<$right_chain ConnectionParams>],
#[structopt(flatten)]
// default signer, which is always used to sign messages relay transactions on the right chain
right_sign: [<$right_chain SigningParams>],
}
impl [<$left_chain $right_chain HeadersAndMessages>] {
async fn into_bridge<
Left: ChainWithTransactions + CliChain,
Right: ChainWithTransactions + CliChain,
L2R: CliBridgeBase<Source = Left, Target = Right> + MessagesCliBridge + RelayToRelayHeadersCliBridge,
R2L: CliBridgeBase<Source = Right, Target = Left> + MessagesCliBridge + RelayToRelayHeadersCliBridge,
>(
self,
) -> anyhow::Result<RelayToRelayBridge<L2R, R2L>> {
Ok(RelayToRelayBridge {
common: Full2WayBridgeCommonParams::new::<L2R>(
self.shared,
BridgeEndCommonParams {
client: self.left.into_client::<Left>().await?,
tx_params: self.left_sign.transaction_params::<Left>()?,
accounts: vec![],
},
BridgeEndCommonParams {
client: self.right.into_client::<Right>().await?,
tx_params: self.right_sign.transaction_params::<Right>()?,
accounts: vec![],
},
)?,
right_to_left_transaction_params: self.left_sign.transaction_params::<Left>(),
left_to_right_transaction_params: self.right_sign.transaction_params::<Right>(),
})
}
}
}
};
}
#[async_trait]
impl<
Left: ChainWithTransactions + CliChain,
Right: ChainWithTransactions + CliChain,
L2R: CliBridgeBase<Source = Left, Target = Right>
+ MessagesCliBridge
+ RelayToRelayHeadersCliBridge,
R2L: CliBridgeBase<Source = Right, Target = Left>
+ MessagesCliBridge
+ RelayToRelayHeadersCliBridge,
> Full2WayBridgeBase for RelayToRelayBridge<L2R, R2L>
where
AccountIdOf<Left>: From<<AccountKeyPairOf<Left> as Pair>::Public>,
AccountIdOf<Right>: From<<AccountKeyPairOf<Right> as Pair>::Public>,
{
type Params = RelayToRelayBridge<L2R, R2L>;
type Left = Left;
type Right = Right;
fn common(&self) -> &Full2WayBridgeCommonParams<Left, Right> {
&self.common
}
fn mut_common(&mut self) -> &mut Full2WayBridgeCommonParams<Self::Left, Self::Right> {
&mut self.common
}
async fn start_on_demand_headers_relayers(
&mut self,
) -> anyhow::Result<(
Arc<dyn OnDemandRelay<Self::Left, Self::Right>>,
Arc<dyn OnDemandRelay<Self::Right, Self::Left>>,
)> {
<L2R as RelayToRelayHeadersCliBridge>::Finality::start_relay_guards(
&self.common.right.client,
self.common.right.client.can_start_version_guard(),
)
.await?;
<R2L as RelayToRelayHeadersCliBridge>::Finality::start_relay_guards(
&self.common.left.client,
self.common.left.client.can_start_version_guard(),
)
.await?;
let left_to_right_on_demand_headers =
OnDemandHeadersRelay::<<L2R as RelayToRelayHeadersCliBridge>::Finality>::new(
self.common.left.client.clone(),
self.common.right.client.clone(),
self.common.right.tx_params.clone(),
self.common.shared.headers_to_relay(),
None,
);
let right_to_left_on_demand_headers =
OnDemandHeadersRelay::<<R2L as RelayToRelayHeadersCliBridge>::Finality>::new(
self.common.right.client.clone(),
self.common.left.client.clone(),
self.common.left.tx_params.clone(),
self.common.shared.headers_to_relay(),
None,
);
Ok((Arc::new(left_to_right_on_demand_headers), Arc::new(right_to_left_on_demand_headers)))
}
}
[package]
name = "relay-bridge-hub-rococo-client"
version = "0.1.0"
authors = ["Parity Technologies <[email protected]>"]
edition = "2021"
license = "GPL-3.0-or-later WITH Classpath-exception-2.0"
[lints]
workspace = true
[dependencies]
codec = { package = "parity-scale-codec", version = "3.1.5", features = ["derive"] }
scale-info = { version = "2.10.0", default-features = false, features = ["derive"] }
subxt = { version = "0.32.1", default-features = false, features = ["native"] }
# Bridge dependencies
bp-bridge-hub-rococo = { path = "../../primitives/chain-bridge-hub-rococo" }
bp-header-chain = { path = "../../primitives/header-chain" }
bp-messages = { path = "../../primitives/messages" }
bp-parachains = { path = "../../primitives/parachains" }
bp-polkadot-core = { path = "../../primitives/polkadot-core" }
bp-runtime = { path = "../../primitives/runtime" }
bridge-runtime-common = { path = "../../bin/runtime-common" }
relay-substrate-client = { path = "../client-substrate" }
# Substrate Dependencies
sp-core = { git = "https://github.com/paritytech/polkadot-sdk", branch = "master" }
sp-runtime = { git = "https://github.com/paritytech/polkadot-sdk", branch = "master" }
sp-weights = { git = "https://github.com/paritytech/polkadot-sdk", branch = "master" }
[package]
name = "relay-substrate-client"
version = "0.1.0"
authors = ["Parity Technologies <[email protected]>"]
edition = "2021"
license = "GPL-3.0-or-later WITH Classpath-exception-2.0"
[lints]
workspace = true
[dependencies]
async-std = { version = "1.6.5", features = ["attributes"] }
async-trait = "0.1"
codec = { package = "parity-scale-codec", version = "3.1.5" }
futures = "0.3.30"
jsonrpsee = { version = "0.17", features = ["macros", "ws-client"] }
log = { workspace = true }
num-traits = "0.2"
rand = "0.8"
scale-info = { version = "2.10.0", features = ["derive"] }
tokio = { version = "1.36", features = ["rt-multi-thread"] }
thiserror = { workspace = true }
# Bridge dependencies
bp-header-chain = { path = "../../primitives/header-chain" }
bp-messages = { path = "../../primitives/messages" }
bp-polkadot-core = { path = "../../primitives/polkadot-core" }
bp-runtime = { path = "../../primitives/runtime" }
pallet-bridge-messages = { path = "../../modules/messages" }
finality-relay = { path = "../finality" }
relay-utils = { path = "../utils" }
# Substrate Dependencies
frame-support = { git = "https://github.com/paritytech/polkadot-sdk", branch = "master" }
frame-system = { git = "https://github.com/paritytech/polkadot-sdk", branch = "master" }
pallet-balances = { git = "https://github.com/paritytech/polkadot-sdk", branch = "master" }
pallet-transaction-payment = { git = "https://github.com/paritytech/polkadot-sdk", branch = "master" }
pallet-transaction-payment-rpc-runtime-api = { git = "https://github.com/paritytech/polkadot-sdk", branch = "master" }
pallet-utility = { git = "https://github.com/paritytech/polkadot-sdk", branch = "master" }
sc-chain-spec = { git = "https://github.com/paritytech/polkadot-sdk", branch = "master" }
sc-rpc-api = { git = "https://github.com/paritytech/polkadot-sdk", branch = "master" }
sc-transaction-pool-api = { git = "https://github.com/paritytech/polkadot-sdk", branch = "master" }
sp-consensus-grandpa = { git = "https://github.com/paritytech/polkadot-sdk", branch = "master" }
sp-core = { git = "https://github.com/paritytech/polkadot-sdk", branch = "master" }
sp-rpc = { git = "https://github.com/paritytech/polkadot-sdk", branch = "master" }
sp-runtime = { git = "https://github.com/paritytech/polkadot-sdk", branch = "master" }
sp-std = { git = "https://github.com/paritytech/polkadot-sdk", branch = "master" }
sp-trie = { git = "https://github.com/paritytech/polkadot-sdk", branch = "master" }
sp-version = { git = "https://github.com/paritytech/polkadot-sdk", branch = "master" }
# Polkadot Dependencies
xcm = { package = "staging-xcm", git = "https://github.com/paritytech/polkadot-sdk", branch = "master", default-features = false }
[features]
default = []
test-helpers = []
// Copyright 2019-2023 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 <http://www.gnu.org/licenses/>.
//! Basic runtime calls.
use codec::{Decode, Encode};
use scale_info::TypeInfo;
use sp_std::{boxed::Box, vec::Vec};
use xcm::{VersionedLocation, VersionedXcm};
/// A minimized version of `frame-system::Call` that can be used without a runtime.
#[derive(Encode, Decode, Debug, PartialEq, Eq, Clone, TypeInfo)]
#[allow(non_camel_case_types)]
pub enum SystemCall {
/// `frame-system::Call::remark`
#[codec(index = 1)]
remark(Vec<u8>),
}
/// A minimized version of `pallet-utility::Call` that can be used without a runtime.
#[derive(Encode, Decode, Debug, PartialEq, Eq, Clone, TypeInfo)]
#[allow(non_camel_case_types)]
pub enum UtilityCall<Call> {
/// `pallet-utility::Call::batch_all`
#[codec(index = 2)]
batch_all(Vec<Call>),
}
/// A minimized version of `pallet-sudo::Call` that can be used without a runtime.
#[derive(Encode, Decode, Debug, PartialEq, Eq, Clone, TypeInfo)]
#[allow(non_camel_case_types)]
pub enum SudoCall<Call> {
/// `pallet-sudo::Call::sudo`
#[codec(index = 0)]
sudo(Box<Call>),
}
/// A minimized version of `pallet-xcm::Call`, that can be used without a runtime.
#[derive(Encode, Decode, Debug, PartialEq, Eq, Clone, TypeInfo)]
#[allow(non_camel_case_types)]
pub enum XcmCall {
/// `pallet-xcm::Call::send`
#[codec(index = 0)]
send(Box<VersionedLocation>, Box<VersionedXcm<()>>),
}
// 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 <http://www.gnu.org/licenses/>.
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<Self::Header>;
/// 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;
/// Name of the `pallet-bridge-parachains`, deployed at the **bridged** chain to sync
/// parachains of **this** chain.
const WITH_CHAIN_BRIDGE_PARACHAINS_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<T> 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 `To<ChainWithMessages>OutboundLaneApi::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 `From<ChainWithMessages>InboundLaneApi::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<C> = <C as Chain>::Call;
/// Transaction status of the chain.
pub type TransactionStatusOf<C> = TransactionStatus<HashOf<C>, HashOf<C>>;
/// Substrate-based chain with `AccountData` generic argument of `frame_system::AccountInfo` set to
/// the `pallet_balances::AccountData<Balance>`.
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<u8>;
/// Block with justification.
pub trait BlockWithJustification<Header> {
/// Return block header.
fn header(&self) -> Header;
/// Return encoded block extrinsics.
fn extrinsics(&self) -> Vec<EncodedExtrinsic>;
/// 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<C: Chain> {
/// Runtime call of this transaction.
pub call: EncodedOrDecodedCall<C::Call>,
/// Transaction nonce.
pub nonce: C::Nonce,
/// Tip included into transaction.
pub tip: C::Balance,
/// Transaction era used by the chain.
pub era: TransactionEraOf<C>,
}
impl<C: Chain> UnsignedTransaction<C> {
/// Create new unsigned transaction with given call, nonce, era and zero tip.
pub fn new(call: EncodedOrDecodedCall<C::Call>, 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<Other>(self) -> UnsignedTransaction<Other>
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<C>) -> Self {
self.era = era;
self
}
}
/// Account key pair used by transactions signing scheme.
pub type AccountKeyPairOf<S> = <S as ChainWithTransactions>::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<Self>,
unsigned: UnsignedTransaction<Self>,
) -> Result<Self::SignedTransaction, crate::Error>
where
Self: Sized;
}
/// Sign transaction parameters
pub struct SignParam<C: ChainWithTransactions> {
/// Version of the runtime specification.
pub spec_version: u32,
/// Transaction version
pub transaction_version: u32,
/// Hash of the genesis block.
pub genesis_hash: HashOf<C>,
/// Signer account
pub signer: AccountKeyPairOf<C>,
}
impl<Block: BlockT> BlockWithJustification<Block::Header> for SignedBlock<Block> {
fn header(&self) -> Block::Header {
self.block.header().clone()
}
fn extrinsics(&self) -> Vec<EncodedExtrinsic> {
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<C: Chain> {
/// Create batch call from given calls vector.
fn build_batch_call(calls: Vec<C::Call>) -> C::Call;
}
/// Structure that implements `UtilityPalletProvider` based on a full runtime.
pub struct FullRuntimeUtilityPallet<R> {
_phantom: std::marker::PhantomData<R>,
}
impl<C, R> UtilityPallet<C> for FullRuntimeUtilityPallet<R>
where
C: Chain,
R: pallet_utility::Config<RuntimeCall = C::Call>,
<R as pallet_utility::Config>::RuntimeCall: From<pallet_utility::Call<R>>,
{
fn build_batch_call(calls: Vec<C::Call>) -> C::Call {
pallet_utility::Call::batch_all { calls }.into()
}
}
/// Structure that implements `UtilityPalletProvider` based on a call conversion.
pub struct MockedRuntimeUtilityPallet<Call> {
_phantom: std::marker::PhantomData<Call>,
}
impl<C, Call> UtilityPallet<C> for MockedRuntimeUtilityPallet<Call>
where
C: Chain,
C::Call: From<UtilityCall<C::Call>>,
{
fn build_batch_call(calls: Vec<C::Call>) -> 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<Self>;
}