From 904b9f4da56dff6845edfe769aea6d1705ee6d84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Thu, 1 Apr 2021 12:49:49 +0200 Subject: [PATCH] Make relay CLI generic (#849) * Start generalizing rialto-millau commands. * cargo fmt --all * Introduce generic balance. * Unify message payloads. * cargo fmt --all * init - generic * Attempt to unify send message. * Start moving things around. * cargo fmt --all * Move init-bridge. * cargo fmt --all * Improve UX of bridge argument. * Fix clippy. * Fix docs and scripts. * Add docs. * Apply suggestions from code review Co-authored-by: Hernando Castano * Fix copyright. * Add issue numbers. * More todos. * Update comments. Co-authored-by: Hernando Castano --- bridges/README.md | 24 +- bridges/primitives/chain-westend/Cargo.toml | 2 + bridges/primitives/chain-westend/src/lib.rs | 12 + .../bin-ethereum/src/ethereum_exchange.rs | 14 +- .../bin-ethereum/src/ethereum_sync_loop.rs | 14 +- bridges/relays/bin-ethereum/src/main.rs | 5 +- .../relays/bin-ethereum/src/rialto_client.rs | 46 +- bridges/relays/bin-substrate/Cargo.toml | 1 + .../bin-substrate/src/cli/init_bridge.rs | 137 +++ .../bin-substrate/src/{cli.rs => cli/mod.rs} | 120 ++- .../bin-substrate/src/cli/relay_headers.rs | 91 ++ .../bin-substrate/src/finality_pipeline.rs | 17 +- .../bin-substrate/src/rialto_millau/cli.rs | 240 ++--- .../rialto_millau/millau_headers_to_rialto.rs | 21 +- .../millau_messages_to_rialto.rs | 10 +- .../bin-substrate/src/rialto_millau/mod.rs | 884 ++++++++---------- .../rialto_millau/rialto_headers_to_millau.rs | 21 +- .../rialto_messages_to_millau.rs | 10 +- .../westend_headers_to_millau.rs | 21 +- bridges/relays/client-millau/src/lib.rs | 21 +- bridges/relays/client-rialto/src/lib.rs | 29 +- bridges/relays/client-substrate/src/error.rs | 35 +- 22 files changed, 896 insertions(+), 879 deletions(-) create mode 100644 bridges/relays/bin-substrate/src/cli/init_bridge.rs rename bridges/relays/bin-substrate/src/{cli.rs => cli/mod.rs} (81%) create mode 100644 bridges/relays/bin-substrate/src/cli/relay_headers.rs diff --git a/bridges/README.md b/bridges/README.md index c122b8af6d..8f6446c887 100644 --- a/bridges/README.md +++ b/bridges/README.md @@ -158,20 +158,20 @@ Then we need to initialize and run the relayer: ```bash docker run --network=host -it \ - paritytech/substrate-relay initialize-rialto-headers-bridge-in-millau \ - --millau-host localhost \ - --millau-port 9945 \ - --rialto-host localhost \ - --rialto-port 9944 \ - --millau-signer //Alice + paritytech/substrate-relay init-bridge RialtoToMillau \ + --target-host localhost \ + --target-port 9945 \ + --source-host localhost \ + --source-port 9944 \ + --target-signer //Alice docker run --network=host -it \ - paritytech/substrate-relay rialto-headers-to-millau \ - --millau-host localhost \ - --millau-port 9945 \ - --rialto-host localhost \ - --rialto-port 9944 \ - --millau-signer //Bob \ + paritytech/substrate-relay relay-headers RialtoToMillau \ + --target-host localhost \ + --target-port 9945 \ + --source-host localhost \ + --source-port 9944 \ + --target-signer //Bob \ ``` You should now see the relayer submitting headers from the Millau chain to the Rialto chain. diff --git a/bridges/primitives/chain-westend/Cargo.toml b/bridges/primitives/chain-westend/Cargo.toml index df8becd959..3552141da5 100644 --- a/bridges/primitives/chain-westend/Cargo.toml +++ b/bridges/primitives/chain-westend/Cargo.toml @@ -16,6 +16,7 @@ bp-runtime = { path = "../runtime", default-features = false } # Substrate Based Dependencies sp-api = { git = "https://github.com/paritytech/substrate", branch = "master" , default-features = false } sp-std = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-version = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } [features] default = ["std"] @@ -25,4 +26,5 @@ std = [ "bp-runtime/std", "sp-api/std", "sp-std/std", + "sp-version/std", ] diff --git a/bridges/primitives/chain-westend/src/lib.rs b/bridges/primitives/chain-westend/src/lib.rs index 0596da1b7d..0587e76125 100644 --- a/bridges/primitives/chain-westend/src/lib.rs +++ b/bridges/primitives/chain-westend/src/lib.rs @@ -22,12 +22,24 @@ use bp_messages::{LaneId, MessageNonce, UnrewardedRelayersState, Weight}; use sp_std::prelude::*; +use sp_version::RuntimeVersion; pub use bp_polkadot_core::*; /// Westend Chain pub type Westend = PolkadotLike; +/// Runtime version. +pub const VERSION: RuntimeVersion = RuntimeVersion { + spec_name: sp_version::create_runtime_str!("westend"), + impl_name: sp_version::create_runtime_str!("parity-westend"), + authoring_version: 2, + spec_version: 50, + impl_version: 0, + apis: sp_version::create_apis_vec![[]], + transaction_version: 5, +}; + // We use this to get the account on Westend (target) which is derived from Rococo's (source) // account. pub fn derive_account_from_rococo_id(id: bp_runtime::SourceAccount) -> AccountId { diff --git a/bridges/relays/bin-ethereum/src/ethereum_exchange.rs b/bridges/relays/bin-ethereum/src/ethereum_exchange.rs index c075ecb7f8..b92581e1f5 100644 --- a/bridges/relays/bin-ethereum/src/ethereum_exchange.rs +++ b/bridges/relays/bin-ethereum/src/ethereum_exchange.rs @@ -56,7 +56,6 @@ pub enum ExchangeRelayMode { } /// PoA exchange transaction relay params. -#[derive(Debug)] pub struct EthereumExchangeParams { /// Ethereum connection params. pub eth_params: EthereumConnectionParams, @@ -72,6 +71,19 @@ pub struct EthereumExchangeParams { pub instance: Arc, } +impl std::fmt::Debug for EthereumExchangeParams { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + f.debug_struct("EthereumExchangeParams") + .field("eth_params", &self.eth_params) + .field("sub_params", &self.sub_params) + .field("sub_sign", &sp_core::Pair::public(&self.sub_sign)) + .field("mode", &self.mode) + .field("metrics_params", &self.metrics_params) + .field("instance", &self.instance) + .finish() + } +} + /// Ethereum to Substrate exchange pipeline. struct EthereumToSubstrateExchange; diff --git a/bridges/relays/bin-ethereum/src/ethereum_sync_loop.rs b/bridges/relays/bin-ethereum/src/ethereum_sync_loop.rs index ab6483cdb8..b2e18b1c8f 100644 --- a/bridges/relays/bin-ethereum/src/ethereum_sync_loop.rs +++ b/bridges/relays/bin-ethereum/src/ethereum_sync_loop.rs @@ -62,7 +62,6 @@ pub mod consts { } /// Ethereum synchronization parameters. -#[derive(Debug)] pub struct EthereumSyncParams { /// Ethereum connection params. pub eth_params: EthereumConnectionParams, @@ -78,6 +77,19 @@ pub struct EthereumSyncParams { pub instance: Arc, } +impl Debug for EthereumSyncParams { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + f.debug_struct("EthereumSyncParams") + .field("eth_params", &self.eth_params) + .field("sub_params", &self.sub_params) + .field("sub_sign", &sp_core::Pair::public(&self.sub_sign)) + .field("sync_params", &self.sync_params) + .field("metrics_params", &self.metrics_params) + .field("instance", &self.instance) + .finish() + } +} + /// Ethereum synchronization pipeline. #[derive(Clone, Copy, Debug)] #[cfg_attr(test, derive(PartialEq))] diff --git a/bridges/relays/bin-ethereum/src/main.rs b/bridges/relays/bin-ethereum/src/main.rs index b2080c396f..40f056c61c 100644 --- a/bridges/relays/bin-ethereum/src/main.rs +++ b/bridges/relays/bin-ethereum/src/main.rs @@ -167,10 +167,11 @@ fn substrate_connection_params(matches: &clap::ArgMatches) -> Result Result { - let mut params = RialtoSigningParams::default(); + let mut params = sp_keyring::AccountKeyring::Alice.pair(); + if let Some(sub_signer) = matches.value_of("sub-signer") { let sub_signer_password = matches.value_of("sub-signer-password"); - params.signer = sp_core::sr25519::Pair::from_string(sub_signer, sub_signer_password) + params = sp_core::sr25519::Pair::from_string(sub_signer, sub_signer_password) .map_err(|e| format!("Failed to parse sub-signer: {:?}", e))?; } Ok(params) diff --git a/bridges/relays/bin-ethereum/src/rialto_client.rs b/bridges/relays/bin-ethereum/src/rialto_client.rs index c6d731b841..06605fdfd5 100644 --- a/bridges/relays/bin-ethereum/src/rialto_client.rs +++ b/bridges/relays/bin-ethereum/src/rialto_client.rs @@ -156,20 +156,17 @@ impl SubmitEthereumHeaders for SubstrateClient { ) -> SubmittedHeaders { let ids = headers.iter().map(|header| header.id()).collect(); let submission_result = async { - self.submit_signed_extrinsic( - params.signer.public().as_array_ref().clone().into(), - |transaction_nonce| { - Bytes( - Rialto::sign_transaction( - *self.genesis_hash(), - ¶ms.signer, - transaction_nonce, - instance.build_signed_header_call(headers), - ) - .encode(), + self.submit_signed_extrinsic(params.public().as_array_ref().clone().into(), |transaction_nonce| { + Bytes( + Rialto::sign_transaction( + *self.genesis_hash(), + ¶ms, + transaction_nonce, + instance.build_signed_header_call(headers), ) - }, - ) + .encode(), + ) + }) .await?; Ok(()) } @@ -260,20 +257,17 @@ impl SubmitEthereumExchangeTransactionProof for SubstrateClient { instance: Arc, proof: rialto_runtime::exchange::EthereumTransactionInclusionProof, ) -> RpcResult<()> { - self.submit_signed_extrinsic( - params.signer.public().as_array_ref().clone().into(), - |transaction_nonce| { - Bytes( - Rialto::sign_transaction( - *self.genesis_hash(), - ¶ms.signer, - transaction_nonce, - instance.build_currency_exchange_call(proof), - ) - .encode(), + self.submit_signed_extrinsic(params.public().as_array_ref().clone().into(), |transaction_nonce| { + Bytes( + Rialto::sign_transaction( + *self.genesis_hash(), + ¶ms, + transaction_nonce, + instance.build_currency_exchange_call(proof), ) - }, - ) + .encode(), + ) + }) .await?; Ok(()) } diff --git a/bridges/relays/bin-substrate/Cargo.toml b/bridges/relays/bin-substrate/Cargo.toml index a94d6d09ef..8942bf8130 100644 --- a/bridges/relays/bin-substrate/Cargo.toml +++ b/bridges/relays/bin-substrate/Cargo.toml @@ -52,6 +52,7 @@ sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" } sp-finality-grandpa = { git = "https://github.com/paritytech/substrate", branch = "master" } sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master" } sp-trie = { git = "https://github.com/paritytech/substrate", branch = "master" } +sp-version = { git = "https://github.com/paritytech/substrate", branch = "master" } [dev-dependencies] sp-keyring = { git = "https://github.com/paritytech/substrate", branch = "master" } diff --git a/bridges/relays/bin-substrate/src/cli/init_bridge.rs b/bridges/relays/bin-substrate/src/cli/init_bridge.rs new file mode 100644 index 0000000000..ac2b8c7a70 --- /dev/null +++ b/bridges/relays/bin-substrate/src/cli/init_bridge.rs @@ -0,0 +1,137 @@ +// 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::cli::{CliChain, SourceConnectionParams, TargetConnectionParams, TargetSigningParams}; +use bp_runtime::Chain as ChainBase; +use codec::Encode; +use pallet_bridge_grandpa::InitializationData; +use relay_substrate_client::{Chain, TransactionSignScheme}; +use sp_core::{Bytes, Pair}; +use structopt::{clap::arg_enum, StructOpt}; + +/// Initialize bridge pallet. +#[derive(StructOpt)] +pub struct InitBridge { + /// A bridge instance to initalize. + #[structopt(possible_values = &InitBridgeName::variants(), case_insensitive = true)] + bridge: InitBridgeName, + #[structopt(flatten)] + source: SourceConnectionParams, + #[structopt(flatten)] + target: TargetConnectionParams, + #[structopt(flatten)] + target_sign: TargetSigningParams, +} + +// TODO [#851] Use kebab-case. +arg_enum! { + #[derive(Debug)] + /// Bridge to initialize. + pub enum InitBridgeName { + MillauToRialto, + RialtoToMillau, + WestendToMillau, + } +} + +macro_rules! select_bridge { + ($bridge: expr, $generic: tt) => { + match $bridge { + InitBridgeName::MillauToRialto => { + type Source = relay_millau_client::Millau; + type Target = relay_rialto_client::Rialto; + + fn encode_init_bridge( + init_data: InitializationData<::Header>, + ) -> ::Call { + rialto_runtime::SudoCall::sudo(Box::new( + rialto_runtime::BridgeGrandpaMillauCall::initialize(init_data).into(), + )) + .into() + } + + $generic + } + InitBridgeName::RialtoToMillau => { + type Source = relay_rialto_client::Rialto; + type Target = relay_millau_client::Millau; + + fn encode_init_bridge( + init_data: InitializationData<::Header>, + ) -> ::Call { + let initialize_call = millau_runtime::BridgeGrandpaRialtoCall::< + millau_runtime::Runtime, + millau_runtime::RialtoGrandpaInstance, + >::initialize(init_data); + millau_runtime::SudoCall::sudo(Box::new(initialize_call.into())).into() + } + + $generic + } + InitBridgeName::WestendToMillau => { + type Source = relay_westend_client::Westend; + type Target = relay_millau_client::Millau; + + fn encode_init_bridge( + init_data: InitializationData<::Header>, + ) -> ::Call { + // at Westend -> Millau initialization we're not using sudo, because otherwise our deployments + // may fail, because we need to initialize both Rialto -> Millau and Westend -> Millau bridge. + // => since there's single possible sudo account, one of transaction may fail with duplicate nonce error + millau_runtime::BridgeGrandpaWestendCall::< + millau_runtime::Runtime, + millau_runtime::WestendGrandpaInstance, + >::initialize(init_data) + .into() + } + + $generic + } + } + }; +} + +impl InitBridge { + /// Run the command. + pub async fn run(self) -> anyhow::Result<()> { + select_bridge!(self.bridge, { + let source_client = crate::rialto_millau::source_chain_client::(self.source).await?; + let target_client = crate::rialto_millau::target_chain_client::(self.target).await?; + let target_sign = + Target::target_signing_params(self.target_sign).map_err(|e| anyhow::format_err!("{}", e))?; + + crate::headers_initialize::initialize( + source_client, + target_client.clone(), + target_sign.public().into(), + move |transaction_nonce, initialization_data| { + Bytes( + Target::sign_transaction( + *target_client.genesis_hash(), + &target_sign, + transaction_nonce, + encode_init_bridge(initialization_data), + ) + .encode(), + ) + }, + ) + .await; + + Ok(()) + }) + } +} diff --git a/bridges/relays/bin-substrate/src/cli.rs b/bridges/relays/bin-substrate/src/cli/mod.rs similarity index 81% rename from bridges/relays/bin-substrate/src/cli.rs rename to bridges/relays/bin-substrate/src/cli/mod.rs index f871b7919b..6418848c29 100644 --- a/bridges/relays/bin-substrate/src/cli.rs +++ b/bridges/relays/bin-substrate/src/cli/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2019-2020 Parity Technologies (UK) Ltd. +// 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 @@ -18,12 +18,15 @@ use std::convert::TryInto; +use crate::rialto_millau::cli as rialto_millau; use bp_messages::LaneId; use codec::{Decode, Encode}; +use frame_support::weights::Weight; use sp_runtime::app_crypto::Ss58Codec; use structopt::{clap::arg_enum, StructOpt}; -use crate::rialto_millau::cli as rialto_millau; +mod init_bridge; +mod relay_headers; /// Parse relay CLI args. pub fn parse_args() -> Command { @@ -38,7 +41,7 @@ pub enum Command { /// /// The on-chain bridge component should have been already initialized with /// `init-bridge` sub-command. - RelayHeaders(RelayHeaders), + RelayHeaders(relay_headers::RelayHeaders), /// Start messages relay between two chains. /// /// Ties up to `Messages` pallets on both chains and starts relaying messages. @@ -47,7 +50,7 @@ pub enum Command { /// Initialize on-chain bridge pallet with current header data. /// /// Sends initialization transaction to bootstrap the bridge with current finalized block data. - InitBridge(InitBridge), + InitBridge(init_bridge::InitBridge), /// Send custom message over the bridge. /// /// Allows interacting with the bridge by sending messages over `Messages` component. @@ -74,9 +77,9 @@ impl Command { /// Run the command. pub async fn run(self) -> anyhow::Result<()> { match self { - Self::InitBridge(arg) => arg.run().await?, Self::RelayHeaders(arg) => arg.run().await?, Self::RelayMessages(arg) => arg.run().await?, + Self::InitBridge(arg) => arg.run().await?, Self::SendMessage(arg) => arg.run().await?, Self::EncodeCall(arg) => arg.run().await?, Self::EncodeMessagePayload(arg) => arg.run().await?, @@ -87,23 +90,6 @@ impl Command { } } -/// Start headers relayer process. -#[derive(StructOpt)] -pub enum RelayHeaders { - #[structopt(flatten)] - RialtoMillau(rialto_millau::RelayHeaders), -} - -impl RelayHeaders { - /// Run the command. - pub async fn run(self) -> anyhow::Result<()> { - match self { - Self::RialtoMillau(arg) => arg.run().await?, - } - Ok(()) - } -} - /// Start message relayer process. #[derive(StructOpt)] pub enum RelayMessages { @@ -121,23 +107,6 @@ impl RelayMessages { } } -/// Initialize bridge pallet. -#[derive(StructOpt)] -pub enum InitBridge { - #[structopt(flatten)] - RialtoMillau(rialto_millau::InitBridge), -} - -impl InitBridge { - /// Run the command. - pub async fn run(self) -> anyhow::Result<()> { - match self { - Self::RialtoMillau(arg) => arg.run().await?, - } - Ok(()) - } -} - /// Send bridge message. #[derive(StructOpt)] pub enum SendMessage { @@ -240,6 +209,25 @@ arg_enum! { } } +/// Generic balance type. +#[derive(Debug)] +pub struct Balance(pub u128); + +impl std::str::FromStr for Balance { + type Err = ::Err; + + fn from_str(s: &str) -> Result { + Ok(Self(s.parse()?)) + } +} + +impl Balance { + /// Cast balance to `u64` type, panicking if it's too large. + pub fn cast(&self) -> u64 { + self.0.try_into().expect("Balance is too high for this chain.") + } +} + /// Generic account id with custom parser. #[derive(Debug, Clone)] pub struct AccountId { @@ -267,19 +255,19 @@ const SS58_FORMAT_PROOF: &str = "u16 -> Ss58Format is infallible; qed"; impl AccountId { /// Create new SS58-formatted address from raw account id. - pub fn from_raw(account: sp_runtime::AccountId32) -> Self { + pub fn from_raw(account: sp_runtime::AccountId32) -> Self { Self { account, ss58_format: T::ss58_format().try_into().expect(SS58_FORMAT_PROOF), } } - /// Enforces formatting account to be for given `AccountChain` type. + /// Enforces formatting account to be for given [`CliChain`] type. /// /// This will change the `ss58format` of the account to match the requested one. /// Note that a warning will be produced in case the current format does not match /// the requested one, but the conversion always succeeds. - pub fn enforce_chain(&mut self) { + pub fn enforce_chain(&mut self) { let original = self.clone(); self.ss58_format = T::ss58_format().try_into().expect(SS58_FORMAT_PROOF); log::debug!("{} SS58 format: {} (RAW: {})", self, self.ss58_format, self.account); @@ -302,15 +290,48 @@ impl AccountId { } } -/// A trait representing an account address bound to a specific chain. +/// Bridge-supported network definition. /// -/// Can be used to convert [`AccountId`] formatting to be chain-specific. -pub trait AccountChain { - /// Network name associated with the SS58 format. - const NAME: &'static str; +/// Used to abstract away CLI commands. +pub trait CliChain: relay_substrate_client::Chain { + /// Chain's current version of the runtime. + const RUNTIME_VERSION: sp_version::RuntimeVersion; + + /// Crypto keypair type used to send messages. + /// + /// In case of chains supporting multiple cryptos, pick one used by the CLI. + type KeyPair: sp_core::crypto::Pair; + + /// Bridge Message Payload type. + /// + /// TODO [#854] This should be removed in favour of target-specifc types. + type MessagePayload; /// Numeric value of SS58 format. fn ss58_format() -> u16; + + /// Parse CLI call and encode it to be dispatched on this specific chain. + fn encode_call(call: crate::rialto_millau::cli::Call) -> Result; + + /// Construct message payload to be sent over the bridge. + fn encode_message(message: crate::rialto_millau::cli::MessagePayload) -> Result; + + /// Maximal extrinsic weight (from the runtime). + fn max_extrinsic_weight() -> Weight; + + /// Convert CLI signing parameters of `Source` chain into a `KeyPair` instance. + fn source_signing_params(params: SourceSigningParams) -> Result { + use sp_core::crypto::Pair; + Self::KeyPair::from_string(¶ms.source_signer, params.source_signer_password.as_deref()) + .map_err(|e| format!("Failed to parse source-signer: {:?}", e)) + } + + /// Convert CLI signing parameters of `Target` chain into a `KeyPair` instance. + fn target_signing_params(params: TargetSigningParams) -> Result { + use sp_core::crypto::Pair; + Self::KeyPair::from_string(¶ms.target_signer, params.target_signer_password.as_deref()) + .map_err(|e| format!("Failed to parse target-signer: {:?}", e)) + } } /// Lane id. @@ -445,6 +466,11 @@ macro_rules! declare_chain_options { }; } +// TODO [#852] Use structop renames instead of different fields. +// TODO [#852] Add Into? +declare_chain_options!(Source, source); +declare_chain_options!(Target, target); + #[cfg(test)] mod tests { use std::str::FromStr; diff --git a/bridges/relays/bin-substrate/src/cli/relay_headers.rs b/bridges/relays/bin-substrate/src/cli/relay_headers.rs new file mode 100644 index 0000000000..6e90332576 --- /dev/null +++ b/bridges/relays/bin-substrate/src/cli/relay_headers.rs @@ -0,0 +1,91 @@ +// 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::cli::{CliChain, PrometheusParams, SourceConnectionParams, TargetConnectionParams, TargetSigningParams}; +use structopt::{clap::arg_enum, StructOpt}; + +/// Start headers relayer process. +#[derive(StructOpt)] +pub struct RelayHeaders { + /// A bridge instance to relay headers for. + #[structopt(possible_values = &RelayHeadersBridge::variants(), case_insensitive = true)] + bridge: RelayHeadersBridge, + #[structopt(flatten)] + source: SourceConnectionParams, + #[structopt(flatten)] + target: TargetConnectionParams, + #[structopt(flatten)] + target_sign: TargetSigningParams, + #[structopt(flatten)] + prometheus_params: PrometheusParams, +} + +// TODO [#851] Use kebab-case. +arg_enum! { + #[derive(Debug)] + /// Headers relay bridge. + pub enum RelayHeadersBridge { + MillauToRialto, + RialtoToMillau, + WestendToMillau, + } +} + +macro_rules! select_bridge { + ($bridge: expr, $generic: tt) => { + match $bridge { + RelayHeadersBridge::MillauToRialto => { + type Source = relay_millau_client::Millau; + type Target = relay_rialto_client::Rialto; + type Finality = crate::rialto_millau::millau_headers_to_rialto::MillauFinalityToRialto; + + $generic + } + RelayHeadersBridge::RialtoToMillau => { + type Source = relay_rialto_client::Rialto; + type Target = relay_millau_client::Millau; + type Finality = crate::rialto_millau::rialto_headers_to_millau::RialtoFinalityToMillau; + $generic + } + RelayHeadersBridge::WestendToMillau => { + type Source = relay_westend_client::Westend; + type Target = relay_millau_client::Millau; + type Finality = crate::rialto_millau::westend_headers_to_millau::WestendFinalityToMillau; + $generic + } + } + }; +} + +impl RelayHeaders { + /// Run the command. + pub async fn run(self) -> anyhow::Result<()> { + select_bridge!(self.bridge, { + let source_client = crate::rialto_millau::source_chain_client::(self.source).await?; + let target_client = crate::rialto_millau::target_chain_client::(self.target).await?; + let target_sign = + Target::target_signing_params(self.target_sign).map_err(|e| anyhow::format_err!("{}", e))?; + + crate::finality_pipeline::run( + Finality::new(target_client.clone(), target_sign), + source_client, + target_client, + self.prometheus_params.into(), + ) + .await + }) + } +} diff --git a/bridges/relays/bin-substrate/src/finality_pipeline.rs b/bridges/relays/bin-substrate/src/finality_pipeline.rs index d5ae55162e..d58306f44f 100644 --- a/bridges/relays/bin-substrate/src/finality_pipeline.rs +++ b/bridges/relays/bin-substrate/src/finality_pipeline.rs @@ -56,7 +56,7 @@ pub trait SubstrateFinalitySyncPipeline: FinalitySyncPipeline { } /// Substrate-to-Substrate finality proof pipeline. -#[derive(Debug, Clone)] +#[derive(Clone)] pub struct SubstrateFinalityToSubstrate { /// Client for the target chain. pub(crate) target_client: Client, @@ -66,6 +66,16 @@ pub struct SubstrateFinalityToSubstrate, } +impl Debug + for SubstrateFinalityToSubstrate +{ + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + f.debug_struct("SubstrateFinalityToSubstrate") + .field("target_client", &self.target_client) + .finish() + } +} + impl SubstrateFinalityToSubstrate { /// Create new Substrate-to-Substrate headers pipeline. pub fn new(target_client: Client, target_sign: TargetSign) -> Self { @@ -83,7 +93,7 @@ where SourceChain: Clone + Chain + Debug, BlockNumberOf: BlockNumberBase, TargetChain: Clone + Chain + Debug, - TargetSign: Clone + Send + Sync + Debug, + TargetSign: Clone + Send + Sync, { const SOURCE_NAME: &'static str = SourceChain::NAME; const TARGET_NAME: &'static str = TargetChain::NAME; @@ -100,7 +110,7 @@ pub async fn run( source_client: Client, target_client: Client, metrics_params: Option, -) -> Result<(), String> +) -> anyhow::Result<()> where P: SubstrateFinalitySyncPipeline< Hash = HashOf, @@ -132,4 +142,5 @@ where futures::future::pending(), ) .await + .map_err(|e| anyhow::format_err!("{}", e)) } diff --git a/bridges/relays/bin-substrate/src/rialto_millau/cli.rs b/bridges/relays/bin-substrate/src/rialto_millau/cli.rs index 9c89e82343..1005e85472 100644 --- a/bridges/relays/bin-substrate/src/rialto_millau/cli.rs +++ b/bridges/relays/bin-substrate/src/rialto_millau/cli.rs @@ -19,68 +19,26 @@ use frame_support::weights::Weight; use structopt::StructOpt; -use crate::cli::{AccountId, ExplicitOrMaximal, HexBytes, HexLaneId, Origins, PrometheusParams}; -use crate::declare_chain_options; - -/// Start headers relayer process. -#[derive(StructOpt)] -pub enum RelayHeaders { - /// Relay Millau headers to Rialto. - MillauToRialto { - #[structopt(flatten)] - millau: MillauConnectionParams, - #[structopt(flatten)] - rialto: RialtoConnectionParams, - #[structopt(flatten)] - rialto_sign: RialtoSigningParams, - #[structopt(flatten)] - prometheus_params: PrometheusParams, - }, - /// Relay Rialto headers to Millau. - RialtoToMillau { - #[structopt(flatten)] - rialto: RialtoConnectionParams, - #[structopt(flatten)] - millau: MillauConnectionParams, - #[structopt(flatten)] - millau_sign: MillauSigningParams, - #[structopt(flatten)] - prometheus_params: PrometheusParams, - }, - /// Relay Westend headers to Millau. - WestendToMillau { - #[structopt(flatten)] - westend: WestendConnectionParams, - #[structopt(flatten)] - millau: MillauConnectionParams, - #[structopt(flatten)] - millau_sign: MillauSigningParams, - #[structopt(flatten)] - prometheus_params: PrometheusParams, - }, -} - -impl RelayHeaders { - /// Run the command. - pub async fn run(self) -> anyhow::Result<()> { - super::run_relay_headers(self).await.map_err(format_err)?; - Ok(()) - } -} +use crate::cli::{ + AccountId, Balance, ExplicitOrMaximal, HexBytes, HexLaneId, Origins, PrometheusParams, SourceConnectionParams, + SourceSigningParams, TargetConnectionParams, TargetSigningParams, +}; /// Start message relayer process. +/// +/// TODO [#855] Move to separate module. #[derive(StructOpt)] pub enum RelayMessages { /// Serve given lane of Millau -> Rialto messages. MillauToRialto { #[structopt(flatten)] - millau: MillauConnectionParams, + source: SourceConnectionParams, #[structopt(flatten)] - millau_sign: MillauSigningParams, + source_sign: SourceSigningParams, #[structopt(flatten)] - rialto: RialtoConnectionParams, + target: TargetConnectionParams, #[structopt(flatten)] - rialto_sign: RialtoSigningParams, + target_sign: TargetSigningParams, #[structopt(flatten)] prometheus_params: PrometheusParams, /// Hex-encoded lane id that should be served by the relay. Defaults to `00000000`. @@ -90,13 +48,13 @@ pub enum RelayMessages { /// Serve given lane of Rialto -> Millau messages. RialtoToMillau { #[structopt(flatten)] - rialto: RialtoConnectionParams, + source: SourceConnectionParams, #[structopt(flatten)] - rialto_sign: RialtoSigningParams, + source_sign: SourceSigningParams, #[structopt(flatten)] - millau: MillauConnectionParams, + target: TargetConnectionParams, #[structopt(flatten)] - millau_sign: MillauSigningParams, + target_sign: TargetSigningParams, #[structopt(flatten)] prometheus_params: PrometheusParams, /// Hex-encoded lane id that should be served by the relay. Defaults to `00000000`. @@ -113,57 +71,19 @@ impl RelayMessages { } } -/// Initialize bridge pallet. -#[derive(StructOpt)] -pub enum InitBridge { - /// Initialize Millau headers bridge in Rialto. - MillauToRialto { - #[structopt(flatten)] - millau: MillauConnectionParams, - #[structopt(flatten)] - rialto: RialtoConnectionParams, - #[structopt(flatten)] - rialto_sign: RialtoSigningParams, - }, - /// Initialize Rialto headers bridge in Millau. - RialtoToMillau { - #[structopt(flatten)] - rialto: RialtoConnectionParams, - #[structopt(flatten)] - millau: MillauConnectionParams, - #[structopt(flatten)] - millau_sign: MillauSigningParams, - }, - /// Initialize Westend headers bridge in Millau. - WestendToMillau { - #[structopt(flatten)] - westend: WestendConnectionParams, - #[structopt(flatten)] - millau: MillauConnectionParams, - #[structopt(flatten)] - millau_sign: MillauSigningParams, - }, -} - -impl InitBridge { - /// Run the command. - pub async fn run(self) -> anyhow::Result<()> { - super::run_init_bridge(self).await.map_err(format_err)?; - Ok(()) - } -} - /// Send bridge message. +/// +/// TODO [#855] Move to separate module. #[derive(StructOpt)] pub enum SendMessage { /// Submit message to given Millau -> Rialto lane. MillauToRialto { #[structopt(flatten)] - millau: MillauConnectionParams, + source: SourceConnectionParams, #[structopt(flatten)] - millau_sign: MillauSigningParams, + source_sign: SourceSigningParams, #[structopt(flatten)] - rialto_sign: RialtoSigningParams, + target_sign: TargetSigningParams, /// Hex-encoded lane id. Defaults to `00000000`. #[structopt(long, default_value = "00000000")] lane: HexLaneId, @@ -172,10 +92,10 @@ pub enum SendMessage { dispatch_weight: Option>, /// Delivery and dispatch fee in source chain base currency units. If not passed, determined automatically. #[structopt(long)] - fee: Option, + fee: Option, /// Message type. #[structopt(subcommand)] - message: ToRialtoMessage, + message: Call, /// The origin to use when dispatching the message on the target chain. Defaults to /// `SourceAccount`. #[structopt(long, possible_values = &Origins::variants(), default_value = "Source")] @@ -184,11 +104,11 @@ pub enum SendMessage { /// Submit message to given Rialto -> Millau lane. RialtoToMillau { #[structopt(flatten)] - rialto: RialtoConnectionParams, + source: SourceConnectionParams, #[structopt(flatten)] - rialto_sign: RialtoSigningParams, + source_sign: SourceSigningParams, #[structopt(flatten)] - millau_sign: MillauSigningParams, + target_sign: TargetSigningParams, /// Hex-encoded lane id. Defaults to `00000000`. #[structopt(long, default_value = "00000000")] lane: HexLaneId, @@ -197,10 +117,10 @@ pub enum SendMessage { dispatch_weight: Option>, /// Delivery and dispatch fee in source chain base currency units. If not passed, determined automatically. #[structopt(long)] - fee: Option, + fee: Option, /// Message type. #[structopt(subcommand)] - message: ToMillauMessage, + message: Call, /// The origin to use when dispatching the message on the target chain. Defaults to /// `SourceAccount`. #[structopt(long, possible_values = &Origins::variants(), default_value = "Source")] @@ -217,17 +137,19 @@ impl SendMessage { } /// A call to encode. +/// +/// TODO [#855] Move to separate module. #[derive(StructOpt)] pub enum EncodeCall { /// Encode Rialto's Call. Rialto { #[structopt(flatten)] - call: ToRialtoMessage, + call: Call, }, /// Encode Millau's Call. Millau { #[structopt(flatten)] - call: ToMillauMessage, + call: Call, }, } @@ -240,17 +162,19 @@ impl EncodeCall { } /// A `MessagePayload` to encode. +/// +/// TODO [#855] Move to separate module. #[derive(StructOpt)] pub enum EncodeMessagePayload { /// Message Payload of Rialto to Millau call. RialtoToMillau { #[structopt(flatten)] - payload: RialtoToMillauMessagePayload, + payload: MessagePayload, }, /// Message Payload of Millau to Rialto call. MillauToRialto { #[structopt(flatten)] - payload: MillauToRialtoMessagePayload, + payload: MessagePayload, }, } @@ -263,29 +187,31 @@ impl EncodeMessagePayload { } /// Estimate Delivery & Dispatch Fee command. +/// +/// TODO [#855] Move to separate module. #[derive(StructOpt)] pub enum EstimateFee { /// Estimate fee of Rialto to Millau message. RialtoToMillau { #[structopt(flatten)] - rialto: RialtoConnectionParams, + source: SourceConnectionParams, /// Hex-encoded id of lane that will be delivering the message. #[structopt(long)] lane: HexLaneId, /// Payload to send over the bridge. #[structopt(flatten)] - payload: RialtoToMillauMessagePayload, + payload: MessagePayload, }, /// Estimate fee of Rialto to Millau message. MillauToRialto { #[structopt(flatten)] - millau: MillauConnectionParams, + source: SourceConnectionParams, /// Hex-encoded id of lane that will be delivering the message. #[structopt(long)] lane: HexLaneId, /// Payload to send over the bridge. #[structopt(flatten)] - payload: MillauToRialtoMessagePayload, + payload: MessagePayload, }, } @@ -303,6 +229,8 @@ impl EstimateFee { /// that has been sent over the bridge. /// This account can also be used to receive target-chain funds (or other form of ownership), /// since messages sent over the bridge will be able to spend these. +/// +/// TODO [#855] Move to separate module. #[derive(StructOpt)] pub enum DeriveAccount { /// Given Rialto AccountId, display corresponding Millau AccountId. @@ -323,47 +251,31 @@ fn format_err(err: String) -> anyhow::Error { anyhow::anyhow!(err) } -/// MessagePayload that can be delivered to messages pallet on Millau. +/// Generic message payload. #[derive(StructOpt, Debug)] -pub enum MillauToRialtoMessagePayload { +pub enum MessagePayload { /// Raw, SCALE-encoded `MessagePayload`. Raw { /// Hex-encoded SCALE data. data: HexBytes, }, /// Construct message to send over the bridge. - Message { + Call { /// Message details. #[structopt(flatten)] - message: ToRialtoMessage, + call: Call, /// SS58 encoded account that will send the payload (must have SS58Prefix = 42) #[structopt(long)] sender: AccountId, }, } -/// MessagePayload that can be delivered to messages pallet on Rialto. +/// All possible messages that may be delivered to generic Substrate chain. +/// +/// Note this enum may be used in the context of both Source (as part of `encode-call`) +/// and Target chain (as part of `encode-message/send-message`). #[derive(StructOpt, Debug)] -pub enum RialtoToMillauMessagePayload { - /// Raw, SCALE-encoded `MessagePayload`. - Raw { - /// Hex-encoded SCALE data. - data: HexBytes, - }, - /// Construct message to send over the bridge. - Message { - /// Message details. - #[structopt(flatten)] - message: ToMillauMessage, - /// SS58 encoded account that will send the payload (must have SS58Prefix = 42) - #[structopt(long)] - sender: AccountId, - }, -} - -/// All possible messages that may be delivered to the Rialto chain. -#[derive(StructOpt, Debug)] -pub enum ToRialtoMessage { +pub enum Call { /// Raw bytes for the message Raw { /// Raw, SCALE-encoded message @@ -382,10 +294,11 @@ pub enum ToRialtoMessage { recipient: AccountId, /// Amount of target tokens to send in target chain base currency units. #[structopt(long)] - amount: bp_rialto::Balance, + amount: Balance, }, - /// A call to the Millau Bridge Messages pallet to send a message over the bridge. - MillauSendMessage { + // TODO [#853] Support multiple bridges. + /// A call to the specific Bridge Messages pallet to queue message to be sent over a bridge. + BridgeSendMessage { /// Hex-encoded lane id that should be served by the relay. Defaults to `00000000`. #[structopt(long, default_value = "00000000")] lane: HexLaneId, @@ -394,47 +307,6 @@ pub enum ToRialtoMessage { payload: HexBytes, /// Declared delivery and dispatch fee in base source-chain currency units. #[structopt(long)] - fee: bp_rialto::Balance, + fee: Balance, }, } - -/// All possible messages that may be delivered to the Millau chain. -#[derive(StructOpt, Debug)] -pub enum ToMillauMessage { - /// Raw bytes for the message - Raw { - /// Raw, SCALE-encoded message - data: HexBytes, - }, - /// Make an on-chain remark (comment). - Remark { - /// Size of the remark. If not passed, small UTF8-encoded string is generated by relay as remark. - #[structopt(long)] - remark_size: Option>, - }, - /// Transfer the specified `amount` of native tokens to a particular `recipient`. - Transfer { - /// SS58 encoded account that will receive the transfer (must have SS58Prefix = 42) - #[structopt(long)] - recipient: AccountId, - /// Amount of target tokens to send in target chain base currency units. - #[structopt(long)] - amount: bp_millau::Balance, - }, - /// A call to the Rialto Bridge Messages pallet to send a message over the bridge. - RialtoSendMessage { - /// Hex-encoded lane id that should be served by the relay. Defaults to `00000000`. - #[structopt(long, default_value = "00000000")] - lane: HexLaneId, - /// Raw SCALE-encoded Message Payload to submit to the messages pallet. - #[structopt(long)] - payload: HexBytes, - /// Declared delivery and dispatch fee in base source-chain currency units. - #[structopt(long)] - fee: bp_millau::Balance, - }, -} - -declare_chain_options!(Rialto, rialto); -declare_chain_options!(Millau, millau); -declare_chain_options!(Westend, westend); diff --git a/bridges/relays/bin-substrate/src/rialto_millau/millau_headers_to_rialto.rs b/bridges/relays/bin-substrate/src/rialto_millau/millau_headers_to_rialto.rs index 5a30974ba4..f85560bf19 100644 --- a/bridges/relays/bin-substrate/src/rialto_millau/millau_headers_to_rialto.rs +++ b/bridges/relays/bin-substrate/src/rialto_millau/millau_headers_to_rialto.rs @@ -16,7 +16,6 @@ //! Millau-to-Rialto headers sync entrypoint. -use super::{MillauClient, RialtoClient}; use crate::finality_pipeline::{SubstrateFinalitySyncPipeline, SubstrateFinalityToSubstrate}; use codec::Encode; @@ -34,7 +33,7 @@ impl SubstrateFinalitySyncPipeline for MillauFinalityToRialto { type TargetChain = Rialto; fn transactions_author(&self) -> bp_rialto::AccountId { - self.target_sign.signer.public().as_array_ref().clone().into() + self.target_sign.public().as_array_ref().clone().into() } fn make_submit_finality_proof_transaction( @@ -48,24 +47,8 @@ impl SubstrateFinalitySyncPipeline for MillauFinalityToRialto { .into(); let genesis_hash = *self.target_client.genesis_hash(); - let transaction = Rialto::sign_transaction(genesis_hash, &self.target_sign.signer, transaction_nonce, call); + let transaction = Rialto::sign_transaction(genesis_hash, &self.target_sign, transaction_nonce, call); Bytes(transaction.encode()) } } - -/// Run Millau-to-Rialto finality sync. -pub async fn run( - millau_client: MillauClient, - rialto_client: RialtoClient, - rialto_sign: RialtoSigningParams, - metrics_params: Option, -) -> Result<(), String> { - crate::finality_pipeline::run( - MillauFinalityToRialto::new(rialto_client.clone(), rialto_sign), - millau_client, - rialto_client, - metrics_params, - ) - .await -} diff --git a/bridges/relays/bin-substrate/src/rialto_millau/millau_messages_to_rialto.rs b/bridges/relays/bin-substrate/src/rialto_millau/millau_messages_to_rialto.rs index edfd907776..38fe71d368 100644 --- a/bridges/relays/bin-substrate/src/rialto_millau/millau_messages_to_rialto.rs +++ b/bridges/relays/bin-substrate/src/rialto_millau/millau_messages_to_rialto.rs @@ -56,7 +56,7 @@ impl SubstrateMessageLane for MillauMessagesToRialto { type TargetChain = Rialto; fn source_transactions_author(&self) -> bp_rialto::AccountId { - self.source_sign.signer.public().as_array_ref().clone().into() + self.source_sign.public().as_array_ref().clone().into() } fn make_messages_receiving_proof_transaction( @@ -70,7 +70,7 @@ impl SubstrateMessageLane for MillauMessagesToRialto { millau_runtime::MessagesCall::receive_messages_delivery_proof(proof, relayers_state).into(); let call_weight = call.get_dispatch_info().weight; let genesis_hash = *self.source_client.genesis_hash(); - let transaction = Millau::sign_transaction(genesis_hash, &self.source_sign.signer, transaction_nonce, call); + let transaction = Millau::sign_transaction(genesis_hash, &self.source_sign, transaction_nonce, call); log::trace!( target: "bridge", "Prepared Rialto -> Millau confirmation transaction. Weight: {}/{}, size: {}/{}", @@ -83,7 +83,7 @@ impl SubstrateMessageLane for MillauMessagesToRialto { } fn target_transactions_author(&self) -> bp_rialto::AccountId { - self.target_sign.signer.public().as_array_ref().clone().into() + self.target_sign.public().as_array_ref().clone().into() } fn make_messages_delivery_transaction( @@ -109,7 +109,7 @@ impl SubstrateMessageLane for MillauMessagesToRialto { .into(); let call_weight = call.get_dispatch_info().weight; let genesis_hash = *self.target_client.genesis_hash(); - let transaction = Rialto::sign_transaction(genesis_hash, &self.target_sign.signer, transaction_nonce, call); + let transaction = Rialto::sign_transaction(genesis_hash, &self.target_sign, transaction_nonce, call); log::trace!( target: "bridge", "Prepared Millau -> Rialto delivery transaction. Weight: {}/{}, size: {}/{}", @@ -138,7 +138,7 @@ pub async fn run( metrics_params: Option, ) -> Result<(), String> { let stall_timeout = Duration::from_secs(5 * 60); - let relayer_id_at_millau = millau_sign.signer.public().as_array_ref().clone().into(); + let relayer_id_at_millau = millau_sign.public().as_array_ref().clone().into(); let lane = MillauMessagesToRialto { source_client: millau_client.clone(), diff --git a/bridges/relays/bin-substrate/src/rialto_millau/mod.rs b/bridges/relays/bin-substrate/src/rialto_millau/mod.rs index 51e9d2898d..7a48119be7 100644 --- a/bridges/relays/bin-substrate/src/rialto_millau/mod.rs +++ b/bridges/relays/bin-substrate/src/rialto_millau/mod.rs @@ -27,205 +27,72 @@ pub mod westend_headers_to_millau; pub type MillauClient = relay_substrate_client::Client; /// Rialto node client. pub type RialtoClient = relay_substrate_client::Client; -/// Westend node client. -pub type WestendClient = relay_substrate_client::Client; -use crate::cli::{AccountChain, AccountId, ExplicitOrMaximal, HexBytes, Origins}; +use crate::cli::{ + AccountId, CliChain, ExplicitOrMaximal, HexBytes, Origins, SourceConnectionParams, SourceSigningParams, + TargetConnectionParams, TargetSigningParams, +}; use codec::{Decode, Encode}; use frame_support::weights::{GetDispatchInfo, Weight}; use pallet_bridge_dispatch::{CallOrigin, MessagePayload}; -use relay_millau_client::{Millau, SigningParams as MillauSigningParams}; -use relay_rialto_client::{Rialto, SigningParams as RialtoSigningParams}; +use relay_millau_client::Millau; +use relay_rialto_client::Rialto; use relay_substrate_client::{Chain, ConnectionParams, TransactionSignScheme}; use relay_westend_client::Westend; use sp_core::{Bytes, Pair}; -use sp_runtime::traits::IdentifyAccount; +use sp_runtime::{traits::IdentifyAccount, MultiSigner}; +use sp_version::RuntimeVersion; use std::fmt::Debug; -async fn run_init_bridge(command: cli::InitBridge) -> Result<(), String> { - match command { - cli::InitBridge::MillauToRialto { - millau, - rialto, - rialto_sign, - } => { - let millau_client = millau.into_client().await?; - let rialto_client = rialto.into_client().await?; - let rialto_sign = rialto_sign.parse()?; - - crate::headers_initialize::initialize( - millau_client, - rialto_client.clone(), - rialto_sign.signer.public().into(), - move |transaction_nonce, initialization_data| { - Bytes( - Rialto::sign_transaction( - *rialto_client.genesis_hash(), - &rialto_sign.signer, - transaction_nonce, - rialto_runtime::SudoCall::sudo(Box::new( - rialto_runtime::BridgeGrandpaMillauCall::initialize(initialization_data).into(), - )) - .into(), - ) - .encode(), - ) - }, - ) - .await; - } - cli::InitBridge::RialtoToMillau { - rialto, - millau, - millau_sign, - } => { - let rialto_client = rialto.into_client().await?; - let millau_client = millau.into_client().await?; - let millau_sign = millau_sign.parse()?; - - crate::headers_initialize::initialize( - rialto_client, - millau_client.clone(), - millau_sign.signer.public().into(), - move |transaction_nonce, initialization_data| { - let initialize_call = millau_runtime::BridgeGrandpaRialtoCall::< - millau_runtime::Runtime, - millau_runtime::RialtoGrandpaInstance, - >::initialize(initialization_data); - - Bytes( - Millau::sign_transaction( - *millau_client.genesis_hash(), - &millau_sign.signer, - transaction_nonce, - millau_runtime::SudoCall::sudo(Box::new(initialize_call.into())).into(), - ) - .encode(), - ) - }, - ) - .await; - } - cli::InitBridge::WestendToMillau { - westend, - millau, - millau_sign, - } => { - let westend_client = westend.into_client().await?; - let millau_client = millau.into_client().await?; - let millau_sign = millau_sign.parse()?; - - // at Westend -> Millau initialization we're not using sudo, because otherwise our deployments - // may fail, because we need to initialize both Rialto -> Millau and Westend -> Millau bridge. - // => since there's single possible sudo account, one of transaction may fail with duplicate nonce error - crate::headers_initialize::initialize( - westend_client, - millau_client.clone(), - millau_sign.signer.public().into(), - move |transaction_nonce, initialization_data| { - let initialize_call = millau_runtime::BridgeGrandpaWestendCall::< - millau_runtime::Runtime, - millau_runtime::WestendGrandpaInstance, - >::initialize(initialization_data); - - Bytes( - Millau::sign_transaction( - *millau_client.genesis_hash(), - &millau_sign.signer, - transaction_nonce, - initialize_call.into(), - ) - .encode(), - ) - }, - ) - .await; - } - } - Ok(()) -} - -async fn run_relay_headers(command: cli::RelayHeaders) -> Result<(), String> { - match command { - cli::RelayHeaders::MillauToRialto { - millau, - rialto, - rialto_sign, - prometheus_params, - } => { - let millau_client = millau.into_client().await?; - let rialto_client = rialto.into_client().await?; - let rialto_sign = rialto_sign.parse()?; - millau_headers_to_rialto::run(millau_client, rialto_client, rialto_sign, prometheus_params.into()).await - } - cli::RelayHeaders::RialtoToMillau { - rialto, - millau, - millau_sign, - prometheus_params, - } => { - let rialto_client = rialto.into_client().await?; - let millau_client = millau.into_client().await?; - let millau_sign = millau_sign.parse()?; - rialto_headers_to_millau::run(rialto_client, millau_client, millau_sign, prometheus_params.into()).await - } - cli::RelayHeaders::WestendToMillau { - westend, - millau, - millau_sign, - prometheus_params, - } => { - let westend_client = westend.into_client().await?; - let millau_client = millau.into_client().await?; - let millau_sign = millau_sign.parse()?; - westend_headers_to_millau::run(westend_client, millau_client, millau_sign, prometheus_params.into()).await - } - } -} - async fn run_relay_messages(command: cli::RelayMessages) -> Result<(), String> { match command { cli::RelayMessages::MillauToRialto { - millau, - millau_sign, - rialto, - rialto_sign, + source, + source_sign, + target, + target_sign, prometheus_params, lane, } => { - let millau_client = millau.into_client().await?; - let millau_sign = millau_sign.parse()?; - let rialto_client = rialto.into_client().await?; - let rialto_sign = rialto_sign.parse()?; + type Source = Millau; + type Target = Rialto; + + let source_client = source_chain_client::(source).await?; + let source_sign = Source::source_signing_params(source_sign)?; + let target_client = target_chain_client::(target).await?; + let target_sign = Target::target_signing_params(target_sign)?; millau_messages_to_rialto::run( - millau_client, - millau_sign, - rialto_client, - rialto_sign, + source_client, + source_sign, + target_client, + target_sign, lane.into(), prometheus_params.into(), ) .await } cli::RelayMessages::RialtoToMillau { - rialto, - rialto_sign, - millau, - millau_sign, + source, + source_sign, + target, + target_sign, prometheus_params, lane, } => { - let rialto_client = rialto.into_client().await?; - let rialto_sign = rialto_sign.parse()?; - let millau_client = millau.into_client().await?; - let millau_sign = millau_sign.parse()?; + type Source = Rialto; + type Target = Millau; + + let source_client = source_chain_client::(source).await?; + let source_sign = Source::source_signing_params(source_sign)?; + let target_client = target_chain_client::(target).await?; + let target_sign = Target::target_signing_params(target_sign)?; rialto_messages_to_millau::run( - rialto_client, - rialto_sign, - millau_client, - millau_sign, + source_client, + source_sign, + target_client, + target_sign, lane.into(), prometheus_params.into(), ) @@ -237,9 +104,9 @@ async fn run_relay_messages(command: cli::RelayMessages) -> Result<(), String> { async fn run_send_message(command: cli::SendMessage) -> Result<(), String> { match command { cli::SendMessage::MillauToRialto { - millau, - millau_sign, - rialto_sign, + source, + source_sign, + target_sign, lane, message, dispatch_weight, @@ -247,57 +114,105 @@ async fn run_send_message(command: cli::SendMessage) -> Result<(), String> { origin, .. } => { - let millau_client = millau.into_client().await?; - let millau_sign = millau_sign.parse()?; - let rialto_sign = rialto_sign.parse()?; - let rialto_call = message.into_call()?; + type Source = Millau; + type Target = Rialto; - let payload = - millau_to_rialto_message_payload(&millau_sign, &rialto_sign, &rialto_call, origin, dispatch_weight); + let account_ownership_digest = |target_call, source_account_id| { + millau_runtime::rialto_account_ownership_digest( + &target_call, + source_account_id, + Target::RUNTIME_VERSION.spec_version, + ) + }; + let estimate_message_fee_method = bp_rialto::TO_RIALTO_ESTIMATE_MESSAGE_FEE_METHOD; + let fee = fee.map(|x| x.cast()); + let send_message_call = |lane, payload, fee| { + millau_runtime::Call::BridgeRialtoMessages(millau_runtime::MessagesCall::send_message( + lane, payload, fee, + )) + }; + + let source_client = source_chain_client::(source).await?; + let source_sign = Source::source_signing_params(source_sign)?; + let target_sign = Target::target_signing_params(target_sign)?; + let target_call = Target::encode_call(message)?; + + let payload = { + let target_call_weight = prepare_call_dispatch_weight( + dispatch_weight, + ExplicitOrMaximal::Explicit(target_call.get_dispatch_info().weight), + compute_maximal_message_dispatch_weight(Target::max_extrinsic_weight()), + ); + let source_sender_public: MultiSigner = source_sign.public().into(); + let source_account_id = source_sender_public.into_account(); + + message_payload( + Target::RUNTIME_VERSION.spec_version, + target_call_weight, + match origin { + Origins::Source => CallOrigin::SourceAccount(source_account_id), + Origins::Target => { + let digest = account_ownership_digest(&target_call, source_account_id.clone()); + let target_origin_public = target_sign.public(); + let digest_signature = target_sign.sign(&digest); + CallOrigin::TargetAccount( + source_account_id, + target_origin_public.into(), + digest_signature.into(), + ) + } + }, + &target_call, + ) + }; let dispatch_weight = payload.weight; let lane = lane.into(); let fee = get_fee(fee, || { estimate_message_delivery_and_dispatch_fee( - &millau_client, - bp_rialto::TO_RIALTO_ESTIMATE_MESSAGE_FEE_METHOD, + &source_client, + estimate_message_fee_method, lane, payload.clone(), ) }) .await?; - millau_client - .submit_signed_extrinsic(millau_sign.signer.public().clone().into(), |transaction_nonce| { - let millau_call = millau_runtime::Call::BridgeRialtoMessages( - millau_runtime::MessagesCall::send_message(lane, payload, fee), - ); + source_client + .submit_signed_extrinsic(source_sign.public().into(), |transaction_nonce| { + let send_message_call = send_message_call(lane, payload, fee); - let signed_millau_call = Millau::sign_transaction( - *millau_client.genesis_hash(), - &millau_sign.signer, + let signed_source_call = Source::sign_transaction( + *source_client.genesis_hash(), + &source_sign, transaction_nonce, - millau_call, + send_message_call, ) .encode(); log::info!( target: "bridge", - "Sending message to Rialto. Size: {}. Dispatch weight: {}. Fee: {}", - signed_millau_call.len(), + "Sending message to {}. Size: {}. Dispatch weight: {}. Fee: {}", + Target::NAME, + signed_source_call.len(), dispatch_weight, fee, ); - log::info!(target: "bridge", "Signed Millau Call: {:?}", HexBytes::encode(&signed_millau_call)); + log::info!( + target: "bridge", + "Signed {} Call: {:?}", + Source::NAME, + HexBytes::encode(&signed_source_call) + ); - Bytes(signed_millau_call) + Bytes(signed_source_call) }) .await?; } cli::SendMessage::RialtoToMillau { - rialto, - rialto_sign, - millau_sign, + source, + source_sign, + target_sign, lane, message, dispatch_weight, @@ -305,50 +220,98 @@ async fn run_send_message(command: cli::SendMessage) -> Result<(), String> { origin, .. } => { - let rialto_client = rialto.into_client().await?; - let rialto_sign = rialto_sign.parse()?; - let millau_sign = millau_sign.parse()?; - let millau_call = message.into_call()?; + type Source = Rialto; + type Target = Millau; - let payload = - rialto_to_millau_message_payload(&rialto_sign, &millau_sign, &millau_call, origin, dispatch_weight); + let account_ownership_digest = |target_call, source_account_id| { + rialto_runtime::millau_account_ownership_digest( + &target_call, + source_account_id, + Target::RUNTIME_VERSION.spec_version, + ) + }; + let estimate_message_fee_method = bp_millau::TO_MILLAU_ESTIMATE_MESSAGE_FEE_METHOD; + let fee = fee.map(|x| x.0); + let send_message_call = |lane, payload, fee| { + rialto_runtime::Call::BridgeMillauMessages(rialto_runtime::MessagesCall::send_message( + lane, payload, fee, + )) + }; + + let source_client = source_chain_client::(source).await?; + let source_sign = Source::source_signing_params(source_sign)?; + let target_sign = Target::target_signing_params(target_sign)?; + let target_call = Target::encode_call(message)?; + + let payload = { + let target_call_weight = prepare_call_dispatch_weight( + dispatch_weight, + ExplicitOrMaximal::Explicit(target_call.get_dispatch_info().weight), + compute_maximal_message_dispatch_weight(Target::max_extrinsic_weight()), + ); + let source_sender_public: MultiSigner = source_sign.public().into(); + let source_account_id = source_sender_public.into_account(); + + message_payload( + Target::RUNTIME_VERSION.spec_version, + target_call_weight, + match origin { + Origins::Source => CallOrigin::SourceAccount(source_account_id), + Origins::Target => { + let digest = account_ownership_digest(&target_call, source_account_id.clone()); + let target_origin_public = target_sign.public(); + let digest_signature = target_sign.sign(&digest); + CallOrigin::TargetAccount( + source_account_id, + target_origin_public.into(), + digest_signature.into(), + ) + } + }, + &target_call, + ) + }; let dispatch_weight = payload.weight; let lane = lane.into(); let fee = get_fee(fee, || { estimate_message_delivery_and_dispatch_fee( - &rialto_client, - bp_millau::TO_MILLAU_ESTIMATE_MESSAGE_FEE_METHOD, + &source_client, + estimate_message_fee_method, lane, payload.clone(), ) }) .await?; - rialto_client - .submit_signed_extrinsic(rialto_sign.signer.public().clone().into(), |transaction_nonce| { - let rialto_call = rialto_runtime::Call::BridgeMillauMessages( - rialto_runtime::MessagesCall::send_message(lane, payload, fee), - ); + source_client + .submit_signed_extrinsic(source_sign.public().into(), |transaction_nonce| { + let send_message_call = send_message_call(lane, payload, fee); - let signed_rialto_call = Rialto::sign_transaction( - *rialto_client.genesis_hash(), - &rialto_sign.signer, + let signed_source_call = Source::sign_transaction( + *source_client.genesis_hash(), + &source_sign, transaction_nonce, - rialto_call, + send_message_call, ) .encode(); log::info!( target: "bridge", - "Sending message to Millau. Size: {}. Dispatch weight: {}. Fee: {}", - signed_rialto_call.len(), + "Sending message to {}. Size: {}. Dispatch weight: {}. Fee: {}", + Target::NAME, + signed_source_call.len(), dispatch_weight, fee, ); - log::info!(target: "bridge", "Signed Rialto Call: {:?}", HexBytes::encode(&signed_rialto_call)); + log::info!( + target: "bridge", + "Signed {} Call: {:?}", + Source::NAME, + HexBytes::encode(&signed_source_call) + ); - Bytes(signed_rialto_call) + Bytes(signed_source_call) }) .await?; } @@ -359,12 +322,15 @@ async fn run_send_message(command: cli::SendMessage) -> Result<(), String> { async fn run_encode_call(call: cli::EncodeCall) -> Result<(), String> { match call { cli::EncodeCall::Rialto { call } => { - let call = call.into_call()?; + type Source = Rialto; + let call = Source::encode_call(call)?; println!("{:?}", HexBytes::encode(&call)); } cli::EncodeCall::Millau { call } => { - let call = call.into_call()?; + type Source = Millau; + + let call = Source::encode_call(call)?; println!("{:?}", HexBytes::encode(&call)); } } @@ -374,13 +340,15 @@ async fn run_encode_call(call: cli::EncodeCall) -> Result<(), String> { async fn run_encode_message_payload(call: cli::EncodeMessagePayload) -> Result<(), String> { match call { cli::EncodeMessagePayload::RialtoToMillau { payload } => { - let payload = payload.into_payload()?; + type Source = Rialto; + let payload = Source::encode_message(payload)?; println!("{:?}", HexBytes::encode(&payload)); } cli::EncodeMessagePayload::MillauToRialto { payload } => { - let payload = payload.into_payload()?; + type Source = Millau; + let payload = Source::encode_message(payload)?; println!("{:?}", HexBytes::encode(&payload)); } } @@ -389,33 +357,35 @@ async fn run_encode_message_payload(call: cli::EncodeMessagePayload) -> Result<( async fn run_estimate_fee(cmd: cli::EstimateFee) -> Result<(), String> { match cmd { - cli::EstimateFee::RialtoToMillau { rialto, lane, payload } => { - let client = rialto.into_client().await?; - let lane = lane.into(); - let payload = payload.into_payload()?; + cli::EstimateFee::RialtoToMillau { source, lane, payload } => { + type Source = Rialto; + type SourceBalance = bp_rialto::Balance; - let fee: Option = estimate_message_delivery_and_dispatch_fee( - &client, - bp_millau::TO_MILLAU_ESTIMATE_MESSAGE_FEE_METHOD, - lane, - payload, - ) - .await?; + let estimate_message_fee_method = bp_millau::TO_MILLAU_ESTIMATE_MESSAGE_FEE_METHOD; + + let source_client = source_chain_client::(source).await?; + let lane = lane.into(); + let payload = Source::encode_message(payload)?; + + let fee: Option = + estimate_message_delivery_and_dispatch_fee(&source_client, estimate_message_fee_method, lane, payload) + .await?; println!("Fee: {:?}", fee); } - cli::EstimateFee::MillauToRialto { millau, lane, payload } => { - let client = millau.into_client().await?; - let lane = lane.into(); - let payload = payload.into_payload()?; + cli::EstimateFee::MillauToRialto { source, lane, payload } => { + type Source = Millau; + type SourceBalance = bp_millau::Balance; - let fee: Option = estimate_message_delivery_and_dispatch_fee( - &client, - bp_rialto::TO_RIALTO_ESTIMATE_MESSAGE_FEE_METHOD, - lane, - payload, - ) - .await?; + let estimate_message_fee_method = bp_rialto::TO_RIALTO_ESTIMATE_MESSAGE_FEE_METHOD; + + let source_client = source_chain_client::(source).await?; + let lane = lane.into(); + let payload = Source::encode_message(payload)?; + + let fee: Option = + estimate_message_delivery_and_dispatch_fee(&source_client, estimate_message_fee_method, lane, payload) + .await?; println!("Fee: {:?}", fee); } @@ -427,20 +397,34 @@ async fn run_estimate_fee(cmd: cli::EstimateFee) -> Result<(), String> { async fn run_derive_account(cmd: cli::DeriveAccount) -> Result<(), String> { match cmd { cli::DeriveAccount::RialtoToMillau { mut account } => { - account.enforce_chain::(); + type Source = Rialto; + type Target = Millau; + + account.enforce_chain::(); let acc = bp_runtime::SourceAccount::Account(account.raw_id()); let id = bp_millau::derive_account_from_rialto_id(acc); - let derived_account = AccountId::from_raw::(id); - println!("Source address:\n{} (Rialto)", account); - println!("->Corresponding (derived) address:\n{} (Millau)", derived_account); + let derived_account = AccountId::from_raw::(id); + println!("Source address:\n{} ({})", account, Source::NAME); + println!( + "->Corresponding (derived) address:\n{} ({})", + derived_account, + Target::NAME, + ); } cli::DeriveAccount::MillauToRialto { mut account } => { - account.enforce_chain::(); + type Source = Millau; + type Target = Rialto; + + account.enforce_chain::(); let acc = bp_runtime::SourceAccount::Account(account.raw_id()); let id = bp_rialto::derive_account_from_millau_id(acc); - let derived_account = AccountId::from_raw::(id); - println!("Source address:\n{} (Millau)", account); - println!("->Corresponding (derived) address:\n{} (Rialto)", derived_account); + let derived_account = AccountId::from_raw::(id); + println!("Source address:\n{} ({})", account, Source::NAME); + println!( + "->Corresponding (derived) address:\n{} ({})", + derived_account, + Target::NAME, + ); } } @@ -514,80 +498,6 @@ where } } -fn rialto_to_millau_message_payload( - rialto_sign: &RialtoSigningParams, - millau_sign: &MillauSigningParams, - millau_call: &millau_runtime::Call, - origin: Origins, - user_specified_dispatch_weight: Option>, -) -> rialto_runtime::millau_messages::ToMillauMessagePayload { - let millau_call_weight = prepare_call_dispatch_weight( - user_specified_dispatch_weight, - ExplicitOrMaximal::Explicit(millau_call.get_dispatch_info().weight), - compute_maximal_message_dispatch_weight(bp_millau::max_extrinsic_weight()), - ); - let rialto_sender_public: bp_rialto::AccountSigner = rialto_sign.signer.public().clone().into(); - let rialto_account_id: bp_rialto::AccountId = rialto_sender_public.into_account(); - let millau_origin_public = millau_sign.signer.public(); - - message_payload( - millau_runtime::VERSION.spec_version, - millau_call_weight, - match origin { - Origins::Source => CallOrigin::SourceAccount(rialto_account_id), - Origins::Target => { - let digest = rialto_runtime::millau_account_ownership_digest( - &millau_call, - rialto_account_id.clone(), - millau_runtime::VERSION.spec_version, - ); - - let digest_signature = millau_sign.signer.sign(&digest); - - CallOrigin::TargetAccount(rialto_account_id, millau_origin_public.into(), digest_signature.into()) - } - }, - &millau_call, - ) -} - -fn millau_to_rialto_message_payload( - millau_sign: &MillauSigningParams, - rialto_sign: &RialtoSigningParams, - rialto_call: &rialto_runtime::Call, - origin: Origins, - user_specified_dispatch_weight: Option>, -) -> millau_runtime::rialto_messages::ToRialtoMessagePayload { - let rialto_call_weight = prepare_call_dispatch_weight( - user_specified_dispatch_weight, - ExplicitOrMaximal::Explicit(rialto_call.get_dispatch_info().weight), - compute_maximal_message_dispatch_weight(bp_rialto::max_extrinsic_weight()), - ); - let millau_sender_public: bp_millau::AccountSigner = millau_sign.signer.public().clone().into(); - let millau_account_id: bp_millau::AccountId = millau_sender_public.into_account(); - let rialto_origin_public = rialto_sign.signer.public(); - - message_payload( - rialto_runtime::VERSION.spec_version, - rialto_call_weight, - match origin { - Origins::Source => CallOrigin::SourceAccount(millau_account_id), - Origins::Target => { - let digest = millau_runtime::rialto_account_ownership_digest( - &rialto_call, - millau_account_id.clone(), - rialto_runtime::VERSION.spec_version, - ); - - let digest_signature = rialto_sign.signer.sign(&digest); - - CallOrigin::TargetAccount(millau_account_id, rialto_origin_public.into(), digest_signature.into()) - } - }, - &rialto_call, - ) -} - fn prepare_call_dispatch_weight( user_specified_dispatch_weight: Option>, weight_from_pre_dispatch_call: ExplicitOrMaximal, @@ -640,145 +550,26 @@ fn compute_maximal_message_arguments_size( maximal_call_size - service_bytes } -impl cli::MillauToRialtoMessagePayload { - /// Parse the CLI parameters and construct message payload. - pub fn into_payload( - self, - ) -> Result>, String> { - match self { - Self::Raw { data } => MessagePayload::decode(&mut &*data.0) - .map_err(|e| format!("Failed to decode Millau's MessagePayload: {:?}", e)), - Self::Message { message, mut sender } => { - let spec_version = rialto_runtime::VERSION.spec_version; - sender.enforce_chain::(); - let origin = CallOrigin::SourceAccount(sender.raw_id()); - let call = message.into_call()?; - let weight = call.get_dispatch_info().weight; +impl CliChain for Millau { + const RUNTIME_VERSION: RuntimeVersion = millau_runtime::VERSION; - Ok(message_payload(spec_version, weight, origin, &call)) - } - } + type KeyPair = sp_core::sr25519::Pair; + type MessagePayload = MessagePayload>; + + fn ss58_format() -> u16 { + millau_runtime::SS58Prefix::get() as u16 } -} -impl cli::RialtoToMillauMessagePayload { - /// Parse the CLI parameters and construct message payload. - pub fn into_payload( - self, - ) -> Result>, String> { - match self { - Self::Raw { data } => MessagePayload::decode(&mut &*data.0) - .map_err(|e| format!("Failed to decode Rialto's MessagePayload: {:?}", e)), - Self::Message { message, mut sender } => { - let spec_version = millau_runtime::VERSION.spec_version; - sender.enforce_chain::(); - let origin = CallOrigin::SourceAccount(sender.raw_id()); - let call = message.into_call()?; - let weight = call.get_dispatch_info().weight; - - Ok(message_payload(spec_version, weight, origin, &call)) - } - } + fn max_extrinsic_weight() -> Weight { + bp_millau::max_extrinsic_weight() } -} -impl cli::RialtoSigningParams { - /// Parse CLI parameters into typed signing params. - pub fn parse(self) -> Result { - RialtoSigningParams::from_suri(&self.rialto_signer, self.rialto_signer_password.as_deref()) - .map_err(|e| format!("Failed to parse rialto-signer: {:?}", e)) - } -} - -impl cli::MillauSigningParams { - /// Parse CLI parameters into typed signing params. - pub fn parse(self) -> Result { - MillauSigningParams::from_suri(&self.millau_signer, self.millau_signer_password.as_deref()) - .map_err(|e| format!("Failed to parse millau-signer: {:?}", e)) - } -} - -impl cli::MillauConnectionParams { - /// Convert CLI connection parameters into Millau RPC Client. - pub async fn into_client(self) -> relay_substrate_client::Result { - MillauClient::new(ConnectionParams { - host: self.millau_host, - port: self.millau_port, - secure: self.millau_secure, - }) - .await - } -} - -impl cli::RialtoConnectionParams { - /// Convert CLI connection parameters into Rialto RPC Client. - pub async fn into_client(self) -> relay_substrate_client::Result { - RialtoClient::new(ConnectionParams { - host: self.rialto_host, - port: self.rialto_port, - secure: self.rialto_secure, - }) - .await - } -} - -impl cli::WestendConnectionParams { - /// Convert CLI connection parameters into Westend RPC Client. - pub async fn into_client(self) -> relay_substrate_client::Result { - WestendClient::new(ConnectionParams { - host: self.westend_host, - port: self.westend_port, - secure: self.westend_secure, - }) - .await - } -} - -impl cli::ToRialtoMessage { - /// Convert CLI call request into runtime `Call` instance. - pub fn into_call(self) -> Result { - let call = match self { - cli::ToRialtoMessage::Raw { data } => { + fn encode_call(call: cli::Call) -> Result { + let call = match call { + cli::Call::Raw { data } => { Decode::decode(&mut &*data.0).map_err(|e| format!("Unable to decode message: {:#?}", e))? } - cli::ToRialtoMessage::Remark { remark_size } => { - rialto_runtime::Call::System(rialto_runtime::SystemCall::remark(remark_payload( - remark_size, - compute_maximal_message_arguments_size( - bp_millau::max_extrinsic_size(), - bp_rialto::max_extrinsic_size(), - ), - ))) - } - cli::ToRialtoMessage::Transfer { mut recipient, amount } => { - recipient.enforce_chain::(); - rialto_runtime::Call::Balances(rialto_runtime::BalancesCall::transfer(recipient.raw_id(), amount)) - } - cli::ToRialtoMessage::MillauSendMessage { lane, payload, fee } => { - let payload = cli::RialtoToMillauMessagePayload::Raw { data: payload }.into_payload()?; - let lane = lane.into(); - rialto_runtime::Call::BridgeMillauMessages(rialto_runtime::MessagesCall::send_message( - lane, payload, fee, - )) - } - }; - - log::info!(target: "bridge", "Generated Rialto call: {:#?}", call); - log::info!(target: "bridge", "Weight of Rialto call: {}", call.get_dispatch_info().weight); - log::info!(target: "bridge", "Encoded Rialto call: {:?}", HexBytes::encode(&call)); - - Ok(call) - } -} - -impl cli::ToMillauMessage { - /// Convert CLI call request into runtime `Call` instance. - pub fn into_call(self) -> Result { - let call = match self { - cli::ToMillauMessage::Raw { data } => { - Decode::decode(&mut &*data.0).map_err(|e| format!("Unable to decode message: {:#?}", e))? - } - cli::ToMillauMessage::Remark { remark_size } => { + cli::Call::Remark { remark_size } => { millau_runtime::Call::System(millau_runtime::SystemCall::remark(remark_payload( remark_size, compute_maximal_message_arguments_size( @@ -787,15 +578,20 @@ impl cli::ToMillauMessage { ), ))) } - cli::ToMillauMessage::Transfer { mut recipient, amount } => { + cli::Call::Transfer { mut recipient, amount } => { recipient.enforce_chain::(); + let amount = amount.cast(); millau_runtime::Call::Balances(millau_runtime::BalancesCall::transfer(recipient.raw_id(), amount)) } - cli::ToMillauMessage::RialtoSendMessage { lane, payload, fee } => { - let payload = cli::MillauToRialtoMessagePayload::Raw { data: payload }.into_payload()?; + cli::Call::BridgeSendMessage { lane, payload, fee } => { + type Target = Rialto; + + let payload = Target::encode_message(cli::MessagePayload::Raw { data: payload })?; let lane = lane.into(); millau_runtime::Call::BridgeRialtoMessages(millau_runtime::MessagesCall::send_message( - lane, payload, fee, + lane, + payload, + fee.cast(), )) } }; @@ -806,22 +602,154 @@ impl cli::ToMillauMessage { Ok(call) } + + // TODO [#854|#843] support multiple bridges? + fn encode_message(message: cli::MessagePayload) -> Result { + match message { + cli::MessagePayload::Raw { data } => MessagePayload::decode(&mut &*data.0) + .map_err(|e| format!("Failed to decode Millau's MessagePayload: {:?}", e)), + cli::MessagePayload::Call { call, mut sender } => { + type Source = Millau; + type Target = Rialto; + + sender.enforce_chain::(); + let spec_version = Target::RUNTIME_VERSION.spec_version; + let origin = CallOrigin::SourceAccount(sender.raw_id()); + let call = Target::encode_call(call)?; + let weight = call.get_dispatch_info().weight; + + Ok(message_payload(spec_version, weight, origin, &call)) + } + } + } } -impl AccountChain for Rialto { - const NAME: &'static str = "Rialto"; +impl CliChain for Rialto { + const RUNTIME_VERSION: RuntimeVersion = rialto_runtime::VERSION; + + type KeyPair = sp_core::sr25519::Pair; + type MessagePayload = MessagePayload>; fn ss58_format() -> u16 { rialto_runtime::SS58Prefix::get() as u16 } + + fn max_extrinsic_weight() -> Weight { + bp_rialto::max_extrinsic_weight() + } + + fn encode_call(call: cli::Call) -> Result { + let call = match call { + cli::Call::Raw { data } => { + Decode::decode(&mut &*data.0).map_err(|e| format!("Unable to decode message: {:#?}", e))? + } + cli::Call::Remark { remark_size } => { + rialto_runtime::Call::System(rialto_runtime::SystemCall::remark(remark_payload( + remark_size, + compute_maximal_message_arguments_size( + bp_millau::max_extrinsic_size(), + bp_rialto::max_extrinsic_size(), + ), + ))) + } + cli::Call::Transfer { mut recipient, amount } => { + type Source = Rialto; + + recipient.enforce_chain::(); + let amount = amount.0; + rialto_runtime::Call::Balances(rialto_runtime::BalancesCall::transfer(recipient.raw_id(), amount)) + } + cli::Call::BridgeSendMessage { lane, payload, fee } => { + type Target = Millau; + + let payload = Target::encode_message(cli::MessagePayload::Raw { data: payload })?; + let lane = lane.into(); + rialto_runtime::Call::BridgeMillauMessages(rialto_runtime::MessagesCall::send_message( + lane, payload, fee.0, + )) + } + }; + + log::info!(target: "bridge", "Generated Rialto call: {:#?}", call); + log::info!(target: "bridge", "Weight of Rialto call: {}", call.get_dispatch_info().weight); + log::info!(target: "bridge", "Encoded Rialto call: {:?}", HexBytes::encode(&call)); + + Ok(call) + } + + fn encode_message(message: cli::MessagePayload) -> Result { + match message { + cli::MessagePayload::Raw { data } => MessagePayload::decode(&mut &*data.0) + .map_err(|e| format!("Failed to decode Rialto's MessagePayload: {:?}", e)), + cli::MessagePayload::Call { call, mut sender } => { + type Source = Rialto; + type Target = Millau; + + sender.enforce_chain::(); + let spec_version = Target::RUNTIME_VERSION.spec_version; + let origin = CallOrigin::SourceAccount(sender.raw_id()); + let call = Target::encode_call(call)?; + let weight = call.get_dispatch_info().weight; + + Ok(message_payload(spec_version, weight, origin, &call)) + } + } + } + + fn source_signing_params(params: SourceSigningParams) -> Result { + Self::KeyPair::from_string(¶ms.source_signer, params.source_signer_password.as_deref()) + .map_err(|e| format!("Failed to parse source-signer: {:?}", e)) + } + + fn target_signing_params(params: TargetSigningParams) -> Result { + Self::KeyPair::from_string(¶ms.target_signer, params.target_signer_password.as_deref()) + .map_err(|e| format!("Failed to parse target-signer: {:?}", e)) + } } -impl AccountChain for Millau { - const NAME: &'static str = "Millau"; +impl CliChain for Westend { + const RUNTIME_VERSION: RuntimeVersion = bp_westend::VERSION; + + type KeyPair = sp_core::sr25519::Pair; + type MessagePayload = (); fn ss58_format() -> u16 { - millau_runtime::SS58Prefix::get() as u16 + 42 } + + fn max_extrinsic_weight() -> Weight { + 0 + } + + fn encode_call(_: cli::Call) -> Result { + Err("Calling into Westend is not supported yet.".into()) + } + + fn encode_message(_message: cli::MessagePayload) -> Result { + Err("Sending messages from Westend is not yet supported.".into()) + } +} + +pub async fn source_chain_client( + params: SourceConnectionParams, +) -> relay_substrate_client::Result> { + relay_substrate_client::Client::new(ConnectionParams { + host: params.source_host, + port: params.source_port, + secure: params.source_secure, + }) + .await +} + +pub async fn target_chain_client( + params: TargetConnectionParams, +) -> relay_substrate_client::Result> { + relay_substrate_client::Client::new(ConnectionParams { + host: params.target_host, + port: params.target_port, + secure: params.target_secure, + }) + .await } #[cfg(test)] @@ -833,11 +761,11 @@ mod tests { #[test] fn millau_signature_is_valid_on_rialto() { - let millau_sign = relay_millau_client::SigningParams::from_suri("//Dave", None).unwrap(); + let millau_sign = relay_millau_client::SigningParams::from_string("//Dave", None).unwrap(); let call = rialto_runtime::Call::System(rialto_runtime::SystemCall::remark(vec![])); - let millau_public: bp_millau::AccountSigner = millau_sign.signer.public().clone().into(); + let millau_public: bp_millau::AccountSigner = millau_sign.public().into(); let millau_account_id: bp_millau::AccountId = millau_public.into_account(); let digest = millau_runtime::rialto_account_ownership_digest( @@ -846,19 +774,19 @@ mod tests { rialto_runtime::VERSION.spec_version, ); - let rialto_signer = relay_rialto_client::SigningParams::from_suri("//Dave", None).unwrap(); - let signature = rialto_signer.signer.sign(&digest); + let rialto_signer = relay_rialto_client::SigningParams::from_string("//Dave", None).unwrap(); + let signature = rialto_signer.sign(&digest); - assert!(signature.verify(&digest[..], &rialto_signer.signer.public())); + assert!(signature.verify(&digest[..], &rialto_signer.public())); } #[test] fn rialto_signature_is_valid_on_millau() { - let rialto_sign = relay_rialto_client::SigningParams::from_suri("//Dave", None).unwrap(); + let rialto_sign = relay_rialto_client::SigningParams::from_string("//Dave", None).unwrap(); let call = millau_runtime::Call::System(millau_runtime::SystemCall::remark(vec![])); - let rialto_public: bp_rialto::AccountSigner = rialto_sign.signer.public().clone().into(); + let rialto_public: bp_rialto::AccountSigner = rialto_sign.public().into(); let rialto_account_id: bp_rialto::AccountId = rialto_public.into_account(); let digest = rialto_runtime::millau_account_ownership_digest( @@ -867,10 +795,10 @@ mod tests { millau_runtime::VERSION.spec_version, ); - let millau_signer = relay_millau_client::SigningParams::from_suri("//Dave", None).unwrap(); - let signature = millau_signer.signer.sign(&digest); + let millau_signer = relay_millau_client::SigningParams::from_string("//Dave", None).unwrap(); + let signature = millau_signer.sign(&digest); - assert!(signature.verify(&digest[..], &millau_signer.signer.public())); + assert!(signature.verify(&digest[..], &millau_signer.public())); } #[test] diff --git a/bridges/relays/bin-substrate/src/rialto_millau/rialto_headers_to_millau.rs b/bridges/relays/bin-substrate/src/rialto_millau/rialto_headers_to_millau.rs index 910d2bf03b..93a5e48b83 100644 --- a/bridges/relays/bin-substrate/src/rialto_millau/rialto_headers_to_millau.rs +++ b/bridges/relays/bin-substrate/src/rialto_millau/rialto_headers_to_millau.rs @@ -16,7 +16,6 @@ //! Rialto-to-Millau headers sync entrypoint. -use super::{MillauClient, RialtoClient}; use crate::finality_pipeline::{SubstrateFinalitySyncPipeline, SubstrateFinalityToSubstrate}; use codec::Encode; @@ -34,7 +33,7 @@ impl SubstrateFinalitySyncPipeline for RialtoFinalityToMillau { type TargetChain = Millau; fn transactions_author(&self) -> bp_millau::AccountId { - self.target_sign.signer.public().as_array_ref().clone().into() + self.target_sign.public().as_array_ref().clone().into() } fn make_submit_finality_proof_transaction( @@ -50,24 +49,8 @@ impl SubstrateFinalitySyncPipeline for RialtoFinalityToMillau { .into(); let genesis_hash = *self.target_client.genesis_hash(); - let transaction = Millau::sign_transaction(genesis_hash, &self.target_sign.signer, transaction_nonce, call); + let transaction = Millau::sign_transaction(genesis_hash, &self.target_sign, transaction_nonce, call); Bytes(transaction.encode()) } } - -/// Run Rialto-to-Millau finality sync. -pub async fn run( - rialto_client: RialtoClient, - millau_client: MillauClient, - millau_sign: MillauSigningParams, - metrics_params: Option, -) -> Result<(), String> { - crate::finality_pipeline::run( - RialtoFinalityToMillau::new(millau_client.clone(), millau_sign), - rialto_client, - millau_client, - metrics_params, - ) - .await -} diff --git a/bridges/relays/bin-substrate/src/rialto_millau/rialto_messages_to_millau.rs b/bridges/relays/bin-substrate/src/rialto_millau/rialto_messages_to_millau.rs index 7268ff07e0..23c338390b 100644 --- a/bridges/relays/bin-substrate/src/rialto_millau/rialto_messages_to_millau.rs +++ b/bridges/relays/bin-substrate/src/rialto_millau/rialto_messages_to_millau.rs @@ -56,7 +56,7 @@ impl SubstrateMessageLane for RialtoMessagesToMillau { type TargetChain = Millau; fn source_transactions_author(&self) -> bp_rialto::AccountId { - self.source_sign.signer.public().as_array_ref().clone().into() + self.source_sign.public().as_array_ref().clone().into() } fn make_messages_receiving_proof_transaction( @@ -70,7 +70,7 @@ impl SubstrateMessageLane for RialtoMessagesToMillau { rialto_runtime::MessagesCall::receive_messages_delivery_proof(proof, relayers_state).into(); let call_weight = call.get_dispatch_info().weight; let genesis_hash = *self.source_client.genesis_hash(); - let transaction = Rialto::sign_transaction(genesis_hash, &self.source_sign.signer, transaction_nonce, call); + let transaction = Rialto::sign_transaction(genesis_hash, &self.source_sign, transaction_nonce, call); log::trace!( target: "bridge", "Prepared Millau -> Rialto confirmation transaction. Weight: {}/{}, size: {}/{}", @@ -83,7 +83,7 @@ impl SubstrateMessageLane for RialtoMessagesToMillau { } fn target_transactions_author(&self) -> bp_rialto::AccountId { - self.target_sign.signer.public().as_array_ref().clone().into() + self.target_sign.public().as_array_ref().clone().into() } fn make_messages_delivery_transaction( @@ -109,7 +109,7 @@ impl SubstrateMessageLane for RialtoMessagesToMillau { .into(); let call_weight = call.get_dispatch_info().weight; let genesis_hash = *self.target_client.genesis_hash(); - let transaction = Millau::sign_transaction(genesis_hash, &self.target_sign.signer, transaction_nonce, call); + let transaction = Millau::sign_transaction(genesis_hash, &self.target_sign, transaction_nonce, call); log::trace!( target: "bridge", "Prepared Rialto -> Millau delivery transaction. Weight: {}/{}, size: {}/{}", @@ -138,7 +138,7 @@ pub async fn run( metrics_params: Option, ) -> Result<(), String> { let stall_timeout = Duration::from_secs(5 * 60); - let relayer_id_at_rialto = rialto_sign.signer.public().as_array_ref().clone().into(); + let relayer_id_at_rialto = rialto_sign.public().as_array_ref().clone().into(); let lane = RialtoMessagesToMillau { source_client: rialto_client.clone(), diff --git a/bridges/relays/bin-substrate/src/rialto_millau/westend_headers_to_millau.rs b/bridges/relays/bin-substrate/src/rialto_millau/westend_headers_to_millau.rs index ca670e05f3..4aa6b569f0 100644 --- a/bridges/relays/bin-substrate/src/rialto_millau/westend_headers_to_millau.rs +++ b/bridges/relays/bin-substrate/src/rialto_millau/westend_headers_to_millau.rs @@ -16,7 +16,6 @@ //! Westend-to-Millau headers sync entrypoint. -use super::{MillauClient, WestendClient}; use crate::finality_pipeline::{SubstrateFinalitySyncPipeline, SubstrateFinalityToSubstrate}; use codec::Encode; @@ -34,7 +33,7 @@ impl SubstrateFinalitySyncPipeline for WestendFinalityToMillau { type TargetChain = Millau; fn transactions_author(&self) -> bp_millau::AccountId { - self.target_sign.signer.public().as_array_ref().clone().into() + self.target_sign.public().as_array_ref().clone().into() } fn make_submit_finality_proof_transaction( @@ -50,24 +49,8 @@ impl SubstrateFinalitySyncPipeline for WestendFinalityToMillau { .into(); let genesis_hash = *self.target_client.genesis_hash(); - let transaction = Millau::sign_transaction(genesis_hash, &self.target_sign.signer, transaction_nonce, call); + let transaction = Millau::sign_transaction(genesis_hash, &self.target_sign, transaction_nonce, call); Bytes(transaction.encode()) } } - -/// Run Westend-to-Millau finality sync. -pub async fn run( - westend_client: WestendClient, - millau_client: MillauClient, - millau_sign: MillauSigningParams, - metrics_params: Option, -) -> Result<(), String> { - crate::finality_pipeline::run( - WestendFinalityToMillau::new(millau_client.clone(), millau_sign), - westend_client, - millau_client, - metrics_params, - ) - .await -} diff --git a/bridges/relays/client-millau/src/lib.rs b/bridges/relays/client-millau/src/lib.rs index 36444cda45..a547fb9ac6 100644 --- a/bridges/relays/client-millau/src/lib.rs +++ b/bridges/relays/client-millau/src/lib.rs @@ -100,26 +100,7 @@ impl TransactionSignScheme for Millau { } /// Millau signing params. -#[derive(Clone)] -pub struct SigningParams { - /// Substrate transactions signer. - pub signer: sp_core::sr25519::Pair, -} - -impl SigningParams { - /// Create signing params from SURI and password. - pub fn from_suri(suri: &str, password: Option<&str>) -> Result { - Ok(SigningParams { - signer: sp_core::sr25519::Pair::from_string(suri, password)?, - }) - } -} - -impl std::fmt::Debug for SigningParams { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - write!(f, "{}", self.signer.public()) - } -} +pub type SigningParams = sp_core::sr25519::Pair; /// Millau header type used in headers sync. pub type SyncHeader = relay_substrate_client::SyncHeader; diff --git a/bridges/relays/client-rialto/src/lib.rs b/bridges/relays/client-rialto/src/lib.rs index bac65b6427..d74d6a8806 100644 --- a/bridges/relays/client-rialto/src/lib.rs +++ b/bridges/relays/client-rialto/src/lib.rs @@ -100,34 +100,7 @@ impl TransactionSignScheme for Rialto { } /// Rialto signing params. -#[derive(Clone)] -pub struct SigningParams { - /// Substrate transactions signer. - pub signer: sp_core::sr25519::Pair, -} - -impl SigningParams { - /// Create signing params from SURI and password. - pub fn from_suri(suri: &str, password: Option<&str>) -> Result { - Ok(SigningParams { - signer: sp_core::sr25519::Pair::from_string(suri, password)?, - }) - } -} - -impl std::fmt::Debug for SigningParams { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - write!(f, "{}", self.signer.public()) - } -} - -impl Default for SigningParams { - fn default() -> Self { - SigningParams { - signer: sp_keyring::AccountKeyring::Alice.pair(), - } - } -} +pub type SigningParams = sp_core::sr25519::Pair; /// Rialto header type used in headers sync. pub type SyncHeader = relay_substrate_client::SyncHeader; diff --git a/bridges/relays/client-substrate/src/error.rs b/bridges/relays/client-substrate/src/error.rs index c513cf1b70..4e1f45eca3 100644 --- a/bridges/relays/client-substrate/src/error.rs +++ b/bridges/relays/client-substrate/src/error.rs @@ -42,6 +42,19 @@ pub enum Error { Custom(String), } +impl std::error::Error for Error { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + match self { + Self::RpcError(ref e) => Some(e), + Self::ResponseParseFailed(ref e) => Some(e), + Self::UninitializedBridgePallet => None, + Self::AccountDoesNotExist => None, + Self::ClientNotSynced(_) => None, + Self::Custom(_) => None, + } + } +} + impl From for Error { fn from(error: RpcError) -> Self { Error::RpcError(error) @@ -61,21 +74,23 @@ impl MaybeConnectionError for Error { } } -impl From for String { - fn from(error: Error) -> String { - error.to_string() - } -} - -impl ToString for Error { - fn to_string(&self) -> String { - match self { +impl std::fmt::Display for Error { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + let s = match self { Self::RpcError(e) => e.to_string(), Self::ResponseParseFailed(e) => e.to_string(), Self::UninitializedBridgePallet => "The Substrate bridge pallet has not been initialized yet.".into(), Self::AccountDoesNotExist => "Account does not exist on the chain".into(), Self::ClientNotSynced(health) => format!("Substrate client is not synced: {}", health), Self::Custom(e) => e.clone(), - } + }; + + write!(f, "{}", s) + } +} + +impl From for String { + fn from(error: Error) -> String { + error.to_string() } }