diff --git a/bridges/relays/ethereum-client/Cargo.toml b/bridges/relays/clients/ethereum/Cargo.toml similarity index 79% rename from bridges/relays/ethereum-client/Cargo.toml rename to bridges/relays/clients/ethereum/Cargo.toml index 4c04f4889469b..b73a66a44c0e1 100644 --- a/bridges/relays/ethereum-client/Cargo.toml +++ b/bridges/relays/clients/ethereum/Cargo.toml @@ -6,14 +6,14 @@ edition = "2018" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" [dependencies] -bp-eth-poa = { path = "../../primitives/ethereum-poa" } +bp-eth-poa = { path = "../../../primitives/ethereum-poa" } codec = { package = "parity-scale-codec", version = "2.0.0" } -headers-relay = { path = "../headers-relay" } +headers-relay = { path = "../../generic/headers" } hex-literal = "0.3" jsonrpsee-proc-macros = "0.2.0-alpha" jsonrpsee-types = "0.2.0-alpha" jsonrpsee-ws-client = "0.2.0-alpha" libsecp256k1 = { version = "0.3.4", default-features = false, features = ["hmac"] } log = "0.4.11" -relay-utils = { path = "../utils" } +relay-utils = { path = "../../generic/utils" } web3 = { version = "0.15", git = "https://github.com/tomusdrw/rust-web3", branch ="td-ethabi", default-features = false } diff --git a/bridges/relays/ethereum-client/src/client.rs b/bridges/relays/clients/ethereum/src/client.rs similarity index 100% rename from bridges/relays/ethereum-client/src/client.rs rename to bridges/relays/clients/ethereum/src/client.rs diff --git a/bridges/relays/ethereum-client/src/error.rs b/bridges/relays/clients/ethereum/src/error.rs similarity index 100% rename from bridges/relays/ethereum-client/src/error.rs rename to bridges/relays/clients/ethereum/src/error.rs diff --git a/bridges/relays/ethereum-client/src/lib.rs b/bridges/relays/clients/ethereum/src/lib.rs similarity index 100% rename from bridges/relays/ethereum-client/src/lib.rs rename to bridges/relays/clients/ethereum/src/lib.rs diff --git a/bridges/relays/ethereum-client/src/rpc.rs b/bridges/relays/clients/ethereum/src/rpc.rs similarity index 100% rename from bridges/relays/ethereum-client/src/rpc.rs rename to bridges/relays/clients/ethereum/src/rpc.rs diff --git a/bridges/relays/ethereum-client/src/sign.rs b/bridges/relays/clients/ethereum/src/sign.rs similarity index 100% rename from bridges/relays/ethereum-client/src/sign.rs rename to bridges/relays/clients/ethereum/src/sign.rs diff --git a/bridges/relays/ethereum-client/src/types.rs b/bridges/relays/clients/ethereum/src/types.rs similarity index 100% rename from bridges/relays/ethereum-client/src/types.rs rename to bridges/relays/clients/ethereum/src/types.rs diff --git a/bridges/relays/kusama-client/Cargo.toml b/bridges/relays/clients/kusama/Cargo.toml similarity index 80% rename from bridges/relays/kusama-client/Cargo.toml rename to bridges/relays/clients/kusama/Cargo.toml index cd311830ae615..e8e44ce2a87c0 100644 --- a/bridges/relays/kusama-client/Cargo.toml +++ b/bridges/relays/clients/kusama/Cargo.toml @@ -7,13 +7,13 @@ license = "GPL-3.0-or-later WITH Classpath-exception-2.0" [dependencies] codec = { package = "parity-scale-codec", version = "2.0.0" } -headers-relay = { path = "../headers-relay" } -relay-substrate-client = { path = "../substrate-client" } -relay-utils = { path = "../utils" } +headers-relay = { path = "../../generic/headers" } +relay-substrate-client = { path = "../substrate" } +relay-utils = { path = "../../generic/utils" } # Bridge dependencies -bp-kusama = { path = "../../primitives/chains/kusama" } +bp-kusama = { path = "../../../primitives/chains/kusama" } # Substrate Dependencies diff --git a/bridges/relays/kusama-client/src/lib.rs b/bridges/relays/clients/kusama/src/lib.rs similarity index 100% rename from bridges/relays/kusama-client/src/lib.rs rename to bridges/relays/clients/kusama/src/lib.rs diff --git a/bridges/relays/millau-client/Cargo.toml b/bridges/relays/clients/millau/Cargo.toml similarity index 79% rename from bridges/relays/millau-client/Cargo.toml rename to bridges/relays/clients/millau/Cargo.toml index 5f9cbd170c938..f975022aea869 100644 --- a/bridges/relays/millau-client/Cargo.toml +++ b/bridges/relays/clients/millau/Cargo.toml @@ -7,13 +7,13 @@ license = "GPL-3.0-or-later WITH Classpath-exception-2.0" [dependencies] codec = { package = "parity-scale-codec", version = "2.0.0" } -headers-relay = { path = "../headers-relay" } -relay-substrate-client = { path = "../substrate-client" } -relay-utils = { path = "../utils" } +headers-relay = { path = "../../generic/headers" } +relay-substrate-client = { path = "../../clients/substrate" } +relay-utils = { path = "../../generic/utils" } # Supported Chains -millau-runtime = { path = "../../bin/millau/runtime" } +millau-runtime = { path = "../../../bin/millau/runtime" } # Substrate Dependencies diff --git a/bridges/relays/millau-client/src/lib.rs b/bridges/relays/clients/millau/src/lib.rs similarity index 100% rename from bridges/relays/millau-client/src/lib.rs rename to bridges/relays/clients/millau/src/lib.rs diff --git a/bridges/relays/polkadot-client/Cargo.toml b/bridges/relays/clients/polkadot/Cargo.toml similarity index 79% rename from bridges/relays/polkadot-client/Cargo.toml rename to bridges/relays/clients/polkadot/Cargo.toml index a1d82758f8d62..b40397f194f34 100644 --- a/bridges/relays/polkadot-client/Cargo.toml +++ b/bridges/relays/clients/polkadot/Cargo.toml @@ -7,13 +7,13 @@ license = "GPL-3.0-or-later WITH Classpath-exception-2.0" [dependencies] codec = { package = "parity-scale-codec", version = "2.0.0" } -headers-relay = { path = "../headers-relay" } -relay-substrate-client = { path = "../substrate-client" } -relay-utils = { path = "../utils" } +headers-relay = { path = "../../generic/headers" } +relay-substrate-client = { path = "../substrate" } +relay-utils = { path = "../../generic/utils" } # Bridge dependencies -bp-polkadot = { path = "../../primitives/chains/polkadot" } +bp-polkadot = { path = "../../../primitives/chains/polkadot" } # Substrate Dependencies diff --git a/bridges/relays/polkadot-client/src/lib.rs b/bridges/relays/clients/polkadot/src/lib.rs similarity index 100% rename from bridges/relays/polkadot-client/src/lib.rs rename to bridges/relays/clients/polkadot/src/lib.rs diff --git a/bridges/relays/rialto-client/Cargo.toml b/bridges/relays/clients/rialto/Cargo.toml similarity index 80% rename from bridges/relays/rialto-client/Cargo.toml rename to bridges/relays/clients/rialto/Cargo.toml index 6142ba05c963c..74aeb8c30f00b 100644 --- a/bridges/relays/rialto-client/Cargo.toml +++ b/bridges/relays/clients/rialto/Cargo.toml @@ -7,13 +7,13 @@ license = "GPL-3.0-or-later WITH Classpath-exception-2.0" [dependencies] codec = { package = "parity-scale-codec", version = "2.0.0" } -headers-relay = { path = "../headers-relay" } -relay-substrate-client = { path = "../substrate-client" } -relay-utils = { path = "../utils" } +headers-relay = { path = "../../generic/headers" } +relay-substrate-client = { path = "../substrate" } +relay-utils = { path = "../../generic/utils" } # Bridge dependencies -rialto-runtime = { path = "../../bin/rialto/runtime" } +rialto-runtime = { path = "../../../bin/rialto/runtime" } # Substrate Dependencies diff --git a/bridges/relays/rialto-client/src/lib.rs b/bridges/relays/clients/rialto/src/lib.rs similarity index 100% rename from bridges/relays/rialto-client/src/lib.rs rename to bridges/relays/clients/rialto/src/lib.rs diff --git a/bridges/relays/substrate-client/Cargo.toml b/bridges/relays/clients/substrate/Cargo.toml similarity index 79% rename from bridges/relays/substrate-client/Cargo.toml rename to bridges/relays/clients/substrate/Cargo.toml index d02c08ab7ad70..bd73043e0a50d 100644 --- a/bridges/relays/substrate-client/Cargo.toml +++ b/bridges/relays/clients/substrate/Cargo.toml @@ -18,12 +18,12 @@ rand = "0.7" # Bridge dependencies -bp-header-chain = { path = "../../primitives/header-chain" } -bp-message-lane = { path = "../../primitives/message-lane" } -bp-runtime = { path = "../../primitives/runtime" } -finality-relay = { path = "../finality-relay" } -headers-relay = { path = "../headers-relay" } -relay-utils = { path = "../utils" } +bp-header-chain = { path = "../../../primitives/header-chain" } +bp-message-lane = { path = "../../../primitives/message-lane" } +bp-runtime = { path = "../../../primitives/runtime" } +finality-relay = { path = "../../generic/finality" } +headers-relay = { path = "../../generic/headers" } +relay-utils = { path = "../../generic/utils" } # Substrate Dependencies diff --git a/bridges/relays/substrate-client/src/chain.rs b/bridges/relays/clients/substrate/src/chain.rs similarity index 100% rename from bridges/relays/substrate-client/src/chain.rs rename to bridges/relays/clients/substrate/src/chain.rs diff --git a/bridges/relays/substrate-client/src/client.rs b/bridges/relays/clients/substrate/src/client.rs similarity index 100% rename from bridges/relays/substrate-client/src/client.rs rename to bridges/relays/clients/substrate/src/client.rs diff --git a/bridges/relays/substrate-client/src/error.rs b/bridges/relays/clients/substrate/src/error.rs similarity index 100% rename from bridges/relays/substrate-client/src/error.rs rename to bridges/relays/clients/substrate/src/error.rs diff --git a/bridges/relays/substrate-client/src/finality_source.rs b/bridges/relays/clients/substrate/src/finality_source.rs similarity index 100% rename from bridges/relays/substrate-client/src/finality_source.rs rename to bridges/relays/clients/substrate/src/finality_source.rs diff --git a/bridges/relays/substrate-client/src/guard.rs b/bridges/relays/clients/substrate/src/guard.rs similarity index 100% rename from bridges/relays/substrate-client/src/guard.rs rename to bridges/relays/clients/substrate/src/guard.rs diff --git a/bridges/relays/substrate-client/src/headers_source.rs b/bridges/relays/clients/substrate/src/headers_source.rs similarity index 100% rename from bridges/relays/substrate-client/src/headers_source.rs rename to bridges/relays/clients/substrate/src/headers_source.rs diff --git a/bridges/relays/substrate-client/src/lib.rs b/bridges/relays/clients/substrate/src/lib.rs similarity index 100% rename from bridges/relays/substrate-client/src/lib.rs rename to bridges/relays/clients/substrate/src/lib.rs diff --git a/bridges/relays/substrate-client/src/rpc.rs b/bridges/relays/clients/substrate/src/rpc.rs similarity index 100% rename from bridges/relays/substrate-client/src/rpc.rs rename to bridges/relays/clients/substrate/src/rpc.rs diff --git a/bridges/relays/substrate-client/src/sync_header.rs b/bridges/relays/clients/substrate/src/sync_header.rs similarity index 100% rename from bridges/relays/substrate-client/src/sync_header.rs rename to bridges/relays/clients/substrate/src/sync_header.rs diff --git a/bridges/relays/ethereum/Cargo.toml b/bridges/relays/ethereum/Cargo.toml index fbc1ef00fcaa9..1975830e5a5a4 100644 --- a/bridges/relays/ethereum/Cargo.toml +++ b/bridges/relays/ethereum/Cargo.toml @@ -29,13 +29,13 @@ time = "0.2" bp-currency-exchange = { path = "../../primitives/currency-exchange" } bp-eth-poa = { path = "../../primitives/ethereum-poa" } -exchange-relay = { path = "../exchange-relay" } -headers-relay = { path = "../headers-relay" } -messages-relay = { path = "../messages-relay" } -relay-ethereum-client = { path = "../ethereum-client" } -relay-rialto-client = { path = "../rialto-client" } -relay-substrate-client = { path = "../substrate-client" } -relay-utils = { path = "../utils" } +exchange-relay = { path = "../generic/exchange" } +headers-relay = { path = "../generic/headers" } +messages-relay = { path = "../generic/messages" } +relay-ethereum-client = { path = "../clients/ethereum" } +relay-rialto-client = { path = "../clients/rialto" } +relay-substrate-client = { path = "../clients/substrate" } +relay-utils = { path = "../generic/utils" } rialto-runtime = { path = "../../bin/rialto/runtime" } # Substrate Dependencies diff --git a/bridges/relays/exchange-relay/Cargo.toml b/bridges/relays/generic/exchange/Cargo.toml similarity index 100% rename from bridges/relays/exchange-relay/Cargo.toml rename to bridges/relays/generic/exchange/Cargo.toml diff --git a/bridges/relays/exchange-relay/src/exchange.rs b/bridges/relays/generic/exchange/src/exchange.rs similarity index 100% rename from bridges/relays/exchange-relay/src/exchange.rs rename to bridges/relays/generic/exchange/src/exchange.rs diff --git a/bridges/relays/exchange-relay/src/exchange_loop.rs b/bridges/relays/generic/exchange/src/exchange_loop.rs similarity index 100% rename from bridges/relays/exchange-relay/src/exchange_loop.rs rename to bridges/relays/generic/exchange/src/exchange_loop.rs diff --git a/bridges/relays/exchange-relay/src/exchange_loop_metrics.rs b/bridges/relays/generic/exchange/src/exchange_loop_metrics.rs similarity index 100% rename from bridges/relays/exchange-relay/src/exchange_loop_metrics.rs rename to bridges/relays/generic/exchange/src/exchange_loop_metrics.rs diff --git a/bridges/relays/exchange-relay/src/lib.rs b/bridges/relays/generic/exchange/src/lib.rs similarity index 100% rename from bridges/relays/exchange-relay/src/lib.rs rename to bridges/relays/generic/exchange/src/lib.rs diff --git a/bridges/relays/finality-relay/Cargo.toml b/bridges/relays/generic/finality/Cargo.toml similarity index 90% rename from bridges/relays/finality-relay/Cargo.toml rename to bridges/relays/generic/finality/Cargo.toml index 9667ba2fa674c..e70fb39d137e1 100644 --- a/bridges/relays/finality-relay/Cargo.toml +++ b/bridges/relays/generic/finality/Cargo.toml @@ -11,7 +11,7 @@ async-std = "1.6.5" async-trait = "0.1.40" backoff = "0.2" futures = "0.3.5" -headers-relay = { path = "../headers-relay" } +headers-relay = { path = "../headers" } log = "0.4.11" num-traits = "0.2" relay-utils = { path = "../utils" } diff --git a/bridges/relays/finality-relay/src/finality_loop.rs b/bridges/relays/generic/finality/src/finality_loop.rs similarity index 100% rename from bridges/relays/finality-relay/src/finality_loop.rs rename to bridges/relays/generic/finality/src/finality_loop.rs diff --git a/bridges/relays/finality-relay/src/finality_loop_tests.rs b/bridges/relays/generic/finality/src/finality_loop_tests.rs similarity index 100% rename from bridges/relays/finality-relay/src/finality_loop_tests.rs rename to bridges/relays/generic/finality/src/finality_loop_tests.rs diff --git a/bridges/relays/finality-relay/src/lib.rs b/bridges/relays/generic/finality/src/lib.rs similarity index 100% rename from bridges/relays/finality-relay/src/lib.rs rename to bridges/relays/generic/finality/src/lib.rs diff --git a/bridges/relays/headers-relay/Cargo.toml b/bridges/relays/generic/headers/Cargo.toml similarity index 100% rename from bridges/relays/headers-relay/Cargo.toml rename to bridges/relays/generic/headers/Cargo.toml diff --git a/bridges/relays/headers-relay/src/headers.rs b/bridges/relays/generic/headers/src/headers.rs similarity index 100% rename from bridges/relays/headers-relay/src/headers.rs rename to bridges/relays/generic/headers/src/headers.rs diff --git a/bridges/relays/headers-relay/src/lib.rs b/bridges/relays/generic/headers/src/lib.rs similarity index 100% rename from bridges/relays/headers-relay/src/lib.rs rename to bridges/relays/generic/headers/src/lib.rs diff --git a/bridges/relays/headers-relay/src/sync.rs b/bridges/relays/generic/headers/src/sync.rs similarity index 100% rename from bridges/relays/headers-relay/src/sync.rs rename to bridges/relays/generic/headers/src/sync.rs diff --git a/bridges/relays/headers-relay/src/sync_loop.rs b/bridges/relays/generic/headers/src/sync_loop.rs similarity index 100% rename from bridges/relays/headers-relay/src/sync_loop.rs rename to bridges/relays/generic/headers/src/sync_loop.rs diff --git a/bridges/relays/headers-relay/src/sync_loop_metrics.rs b/bridges/relays/generic/headers/src/sync_loop_metrics.rs similarity index 100% rename from bridges/relays/headers-relay/src/sync_loop_metrics.rs rename to bridges/relays/generic/headers/src/sync_loop_metrics.rs diff --git a/bridges/relays/headers-relay/src/sync_loop_tests.rs b/bridges/relays/generic/headers/src/sync_loop_tests.rs similarity index 100% rename from bridges/relays/headers-relay/src/sync_loop_tests.rs rename to bridges/relays/generic/headers/src/sync_loop_tests.rs diff --git a/bridges/relays/headers-relay/src/sync_types.rs b/bridges/relays/generic/headers/src/sync_types.rs similarity index 100% rename from bridges/relays/headers-relay/src/sync_types.rs rename to bridges/relays/generic/headers/src/sync_types.rs diff --git a/bridges/relays/messages-relay/Cargo.toml b/bridges/relays/generic/messages/Cargo.toml similarity index 85% rename from bridges/relays/messages-relay/Cargo.toml rename to bridges/relays/generic/messages/Cargo.toml index 9c2daefdb4271..427fe4829d7be 100644 --- a/bridges/relays/messages-relay/Cargo.toml +++ b/bridges/relays/generic/messages/Cargo.toml @@ -15,5 +15,5 @@ parking_lot = "0.11.0" # Bridge Dependencies -bp-message-lane = { path = "../../primitives/message-lane" } +bp-message-lane = { path = "../../../primitives/message-lane" } relay-utils = { path = "../utils" } diff --git a/bridges/relays/messages-relay/src/lib.rs b/bridges/relays/generic/messages/src/lib.rs similarity index 100% rename from bridges/relays/messages-relay/src/lib.rs rename to bridges/relays/generic/messages/src/lib.rs diff --git a/bridges/relays/messages-relay/src/message_lane.rs b/bridges/relays/generic/messages/src/message_lane.rs similarity index 100% rename from bridges/relays/messages-relay/src/message_lane.rs rename to bridges/relays/generic/messages/src/message_lane.rs diff --git a/bridges/relays/messages-relay/src/message_lane_loop.rs b/bridges/relays/generic/messages/src/message_lane_loop.rs similarity index 100% rename from bridges/relays/messages-relay/src/message_lane_loop.rs rename to bridges/relays/generic/messages/src/message_lane_loop.rs diff --git a/bridges/relays/messages-relay/src/message_race_delivery.rs b/bridges/relays/generic/messages/src/message_race_delivery.rs similarity index 100% rename from bridges/relays/messages-relay/src/message_race_delivery.rs rename to bridges/relays/generic/messages/src/message_race_delivery.rs diff --git a/bridges/relays/messages-relay/src/message_race_loop.rs b/bridges/relays/generic/messages/src/message_race_loop.rs similarity index 100% rename from bridges/relays/messages-relay/src/message_race_loop.rs rename to bridges/relays/generic/messages/src/message_race_loop.rs diff --git a/bridges/relays/messages-relay/src/message_race_receiving.rs b/bridges/relays/generic/messages/src/message_race_receiving.rs similarity index 100% rename from bridges/relays/messages-relay/src/message_race_receiving.rs rename to bridges/relays/generic/messages/src/message_race_receiving.rs diff --git a/bridges/relays/messages-relay/src/message_race_strategy.rs b/bridges/relays/generic/messages/src/message_race_strategy.rs similarity index 100% rename from bridges/relays/messages-relay/src/message_race_strategy.rs rename to bridges/relays/generic/messages/src/message_race_strategy.rs diff --git a/bridges/relays/messages-relay/src/metrics.rs b/bridges/relays/generic/messages/src/metrics.rs similarity index 100% rename from bridges/relays/messages-relay/src/metrics.rs rename to bridges/relays/generic/messages/src/metrics.rs diff --git a/bridges/relays/utils/Cargo.toml b/bridges/relays/generic/utils/Cargo.toml similarity index 100% rename from bridges/relays/utils/Cargo.toml rename to bridges/relays/generic/utils/Cargo.toml diff --git a/bridges/relays/utils/src/initialize.rs b/bridges/relays/generic/utils/src/initialize.rs similarity index 100% rename from bridges/relays/utils/src/initialize.rs rename to bridges/relays/generic/utils/src/initialize.rs diff --git a/bridges/relays/utils/src/lib.rs b/bridges/relays/generic/utils/src/lib.rs similarity index 100% rename from bridges/relays/utils/src/lib.rs rename to bridges/relays/generic/utils/src/lib.rs diff --git a/bridges/relays/utils/src/metrics.rs b/bridges/relays/generic/utils/src/metrics.rs similarity index 100% rename from bridges/relays/utils/src/metrics.rs rename to bridges/relays/generic/utils/src/metrics.rs diff --git a/bridges/relays/utils/src/relay_loop.rs b/bridges/relays/generic/utils/src/relay_loop.rs similarity index 100% rename from bridges/relays/utils/src/relay_loop.rs rename to bridges/relays/generic/utils/src/relay_loop.rs diff --git a/bridges/relays/substrate/Cargo.toml b/bridges/relays/substrate/Cargo.toml index fb5d48120c46b..d71cfa2f1e10f 100644 --- a/bridges/relays/substrate/Cargo.toml +++ b/bridges/relays/substrate/Cargo.toml @@ -6,6 +6,7 @@ edition = "2018" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" [dependencies] +anyhow = "1.0" async-std = "1.9.0" async-trait = "0.1.42" codec = { package = "parity-scale-codec", version = "2.0.0" } @@ -26,19 +27,19 @@ bp-polkadot = { path = "../../primitives/chains/polkadot" } bp-runtime = { path = "../../primitives/runtime" } bp-rialto = { path = "../../primitives/chains/rialto" } bridge-runtime-common = { path = "../../bin/runtime-common" } -finality-relay = { path = "../finality-relay" } -headers-relay = { path = "../headers-relay" } -messages-relay = { path = "../messages-relay" } +finality-relay = { path = "../generic/finality" } +headers-relay = { path = "../generic/headers" } +messages-relay = { path = "../generic/messages" } millau-runtime = { path = "../../bin/millau/runtime" } pallet-bridge-call-dispatch = { path = "../../modules/call-dispatch" } pallet-finality-verifier = { path = "../../modules/finality-verifier" } pallet-message-lane = { path = "../../modules/message-lane" } -relay-kusama-client = { path = "../kusama-client" } -relay-millau-client = { path = "../millau-client" } -relay-polkadot-client = { path = "../polkadot-client" } -relay-rialto-client = { path = "../rialto-client" } -relay-substrate-client = { path = "../substrate-client" } -relay-utils = { path = "../utils" } +relay-kusama-client = { path = "../clients/kusama" } +relay-millau-client = { path = "../clients/millau" } +relay-polkadot-client = { path = "../clients/polkadot" } +relay-rialto-client = { path = "../clients/rialto" } +relay-substrate-client = { path = "../clients/substrate" } +relay-utils = { path = "../generic/utils" } rialto-runtime = { path = "../../bin/rialto/runtime" } # Substrate Dependencies diff --git a/bridges/relays/substrate/src/cli.rs b/bridges/relays/substrate/src/cli.rs index d9bec5774740e..bfe5f6f549229 100644 --- a/bridges/relays/substrate/src/cli.rs +++ b/bridges/relays/substrate/src/cli.rs @@ -17,12 +17,12 @@ //! Deal with CLI args of substrate-to-substrate relay. use bp_message_lane::LaneId; -use frame_support::weights::Weight; -use sp_core::Bytes; -use sp_finality_grandpa::SetId as GrandpaAuthoritiesSetId; +use codec::{Decode, Encode}; use sp_runtime::app_crypto::Ss58Codec; use structopt::{clap::arg_enum, StructOpt}; +use crate::rialto_millau::cli as rialto_millau; + /// Parse relay CLI args. pub fn parse_args() -> Command { Command::from_args() @@ -68,207 +68,140 @@ pub enum Command { DeriveAccount(DeriveAccount), } +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::SendMessage(arg) => arg.run().await?, + Self::EncodeCall(arg) => arg.run().await?, + Self::EncodeMessagePayload(arg) => arg.run().await?, + Self::EstimateFee(arg) => arg.run().await?, + Self::DeriveAccount(arg) => arg.run().await?, + } + Ok(()) + } +} + /// 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, - }, + #[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 { - /// Serve given lane of Millau -> Rialto messages. - MillauToRialto { - #[structopt(flatten)] - millau: MillauConnectionParams, - #[structopt(flatten)] - millau_sign: MillauSigningParams, - #[structopt(flatten)] - rialto: RialtoConnectionParams, - #[structopt(flatten)] - rialto_sign: RialtoSigningParams, - #[structopt(flatten)] - prometheus_params: PrometheusParams, - /// Hex-encoded lane id that should be served by the relay. Defaults to `00000000`. - #[structopt(long, default_value = "00000000")] - lane: HexLaneId, - }, - /// Serve given lane of Rialto -> Millau messages. - RialtoToMillau { - #[structopt(flatten)] - rialto: RialtoConnectionParams, - #[structopt(flatten)] - rialto_sign: RialtoSigningParams, - #[structopt(flatten)] - millau: MillauConnectionParams, - #[structopt(flatten)] - millau_sign: MillauSigningParams, - #[structopt(flatten)] - prometheus_params: PrometheusParams, - /// Hex-encoded lane id that should be served by the relay. Defaults to `00000000`. - #[structopt(long, default_value = "00000000")] - lane: HexLaneId, - }, + #[structopt(flatten)] + RialtoMillau(rialto_millau::RelayMessages), +} + +impl RelayMessages { + /// Run the command. + pub async fn run(self) -> anyhow::Result<()> { + match self { + Self::RialtoMillau(arg) => arg.run().await?, + } + Ok(()) + } } /// 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, - #[structopt(flatten)] - millau_bridge_params: MillauBridgeInitializationParams, - }, - /// Initialize Rialto headers bridge in Millau. - RialtoToMillau { - #[structopt(flatten)] - rialto: RialtoConnectionParams, - #[structopt(flatten)] - millau: MillauConnectionParams, - #[structopt(flatten)] - millau_sign: MillauSigningParams, - #[structopt(flatten)] - rialto_bridge_params: RialtoBridgeInitializationParams, - }, + #[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 { - /// Submit message to given Millau -> Rialto lane. - MillauToRialto { - #[structopt(flatten)] - millau: MillauConnectionParams, - #[structopt(flatten)] - millau_sign: MillauSigningParams, - #[structopt(flatten)] - rialto_sign: RialtoSigningParams, - /// Hex-encoded lane id. Defaults to `00000000`. - #[structopt(long, default_value = "00000000")] - lane: HexLaneId, - /// Dispatch weight of the message. If not passed, determined automatically. - #[structopt(long)] - dispatch_weight: Option>, - /// Delivery and dispatch fee in source chain base currency units. If not passed, determined automatically. - #[structopt(long)] - fee: Option, - /// Message type. - #[structopt(subcommand)] - message: ToRialtoMessage, - /// The origin to use when dispatching the message on the target chain. Defaults to - /// `SourceAccount`. - #[structopt(long, possible_values = &Origins::variants(), default_value = "Source")] - origin: Origins, - }, - /// Submit message to given Rialto -> Millau lane. - RialtoToMillau { - #[structopt(flatten)] - rialto: RialtoConnectionParams, - #[structopt(flatten)] - rialto_sign: RialtoSigningParams, - #[structopt(flatten)] - millau_sign: MillauSigningParams, - /// Hex-encoded lane id. Defaults to `00000000`. - #[structopt(long, default_value = "00000000")] - lane: HexLaneId, - /// Dispatch weight of the message. If not passed, determined automatically. - #[structopt(long)] - dispatch_weight: Option>, - /// Delivery and dispatch fee in source chain base currency units. If not passed, determined automatically. - #[structopt(long)] - fee: Option, - /// Message type. - #[structopt(subcommand)] - message: ToMillauMessage, - /// The origin to use when dispatching the message on the target chain. Defaults to - /// `SourceAccount`. - #[structopt(long, possible_values = &Origins::variants(), default_value = "Source")] - origin: Origins, - }, + #[structopt(flatten)] + RialtoMillau(rialto_millau::SendMessage), +} + +impl SendMessage { + /// Run the command. + pub async fn run(self) -> anyhow::Result<()> { + match self { + Self::RialtoMillau(arg) => arg.run().await?, + } + Ok(()) + } } /// A call to encode. #[derive(StructOpt)] pub enum EncodeCall { - /// Encode Rialto's Call. - Rialto { - #[structopt(flatten)] - call: ToRialtoMessage, - }, - /// Encode Millau's Call. - Millau { - #[structopt(flatten)] - call: ToMillauMessage, - }, + #[structopt(flatten)] + RialtoMillau(rialto_millau::EncodeCall), +} + +impl EncodeCall { + /// Run the command. + pub async fn run(self) -> anyhow::Result<()> { + match self { + Self::RialtoMillau(arg) => arg.run().await?, + } + Ok(()) + } } /// A `MessagePayload` to encode. #[derive(StructOpt)] pub enum EncodeMessagePayload { - /// Message Payload of Rialto to Millau call. - RialtoToMillau { - #[structopt(flatten)] - payload: RialtoToMillauMessagePayload, - }, - /// Message Payload of Millau to Rialto call. - MillauToRialto { - #[structopt(flatten)] - payload: MillauToRialtoMessagePayload, - }, + #[structopt(flatten)] + RialtoMillau(rialto_millau::EncodeMessagePayload), +} + +impl EncodeMessagePayload { + /// Run the command. + pub async fn run(self) -> anyhow::Result<()> { + match self { + Self::RialtoMillau(arg) => arg.run().await?, + } + Ok(()) + } } /// Estimate Delivery & Dispatch Fee command. #[derive(StructOpt)] pub enum EstimateFee { - /// Estimate fee of Rialto to Millau message. - RialtoToMillau { - #[structopt(flatten)] - rialto: RialtoConnectionParams, - /// 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, - }, - /// Estimate fee of Rialto to Millau message. - MillauToRialto { - #[structopt(flatten)] - millau: MillauConnectionParams, - /// 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, - }, + #[structopt(flatten)] + RialtoMillau(rialto_millau::EstimateFee), +} + +impl EstimateFee { + /// Run the command. + pub async fn run(self) -> anyhow::Result<()> { + match self { + Self::RialtoMillau(arg) => arg.run().await?, + } + Ok(()) + } } /// Given a source chain `AccountId`, derive the corresponding `AccountId` for the target chain. @@ -279,122 +212,18 @@ pub enum EstimateFee { /// since messages sent over the bridge will be able to spend these. #[derive(StructOpt)] pub enum DeriveAccount { - /// Given Rialto AccountId, display corresponding Millau AccountId. - RialtoToMillau { account: AccountId }, - /// Given Millau AccountId, display corresponding Rialto AccountId. - MillauToRialto { account: AccountId }, -} - -/// MessagePayload that can be delivered to message lane pallet on Millau. -#[derive(StructOpt, Debug)] -pub enum MillauToRialtoMessagePayload { - /// Raw, SCALE-encoded `MessagePayload`. - Raw { - /// Hex-encoded SCALE data. - data: Bytes, - }, - /// Construct message to send over the bridge. - Message { - /// Message details. - #[structopt(flatten)] - message: ToRialtoMessage, - /// SS58 encoded account that will send the payload (must have SS58Prefix = 42) - #[structopt(long)] - sender: AccountId, - }, -} - -/// MessagePayload that can be delivered to message lane pallet on Rialto. -#[derive(StructOpt, Debug)] -pub enum RialtoToMillauMessagePayload { - /// Raw, SCALE-encoded `MessagePayload`. - Raw { - /// Hex-encoded SCALE data. - data: Bytes, - }, - /// 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 { - /// Raw bytes for the message - Raw { - /// Raw, SCALE-encoded message - data: Bytes, - }, - /// Make an on-chain remark (comment). - Remark { - /// Remark size. 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_rialto::Balance, - }, - /// A call to the Millau Bridge Message Lane pallet to send a message over the bridge. - MillauSendMessage { - /// 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 message lane pallet. - #[structopt(long)] - payload: Bytes, - /// Declared delivery and dispatch fee in base source-chain currency units. - #[structopt(long)] - fee: bp_rialto::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: Bytes, - }, - /// 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 Message Lane 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 message lane pallet. - #[structopt(long)] - payload: Bytes, - /// Declared delivery and dispatch fee in base source-chain currency units. - #[structopt(long)] - fee: bp_millau::Balance, - }, + #[structopt(flatten)] + RialtoMillau(rialto_millau::DeriveAccount), +} + +impl DeriveAccount { + /// Run the command. + pub async fn run(self) -> anyhow::Result<()> { + match self { + Self::RialtoMillau(arg) => arg.run().await?, + } + Ok(()) + } } arg_enum! { @@ -456,7 +285,7 @@ impl AccountId { /// Lane id. #[derive(Debug)] -pub struct HexLaneId(LaneId); +pub struct HexLaneId(pub LaneId); impl From for LaneId { fn from(lane_id: HexLaneId) -> LaneId { @@ -474,6 +303,31 @@ impl std::str::FromStr for HexLaneId { } } +/// Nicer formatting for raw bytes vectors. +#[derive(Encode, Decode)] +pub struct HexBytes(pub Vec); + +impl std::str::FromStr for HexBytes { + type Err = hex::FromHexError; + + fn from_str(s: &str) -> Result { + Ok(Self(hex::decode(s)?)) + } +} + +impl std::fmt::Debug for HexBytes { + fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(fmt, "0x{}", hex::encode(&self.0)) + } +} + +impl HexBytes { + /// Encode given object and wrap into nicely formatted bytes. + pub fn encode(t: &T) -> Self { + Self(t.encode()) + } +} + /// Prometheus metrics params. #[derive(StructOpt)] pub struct PrometheusParams { @@ -527,6 +381,9 @@ where } } +/// Create chain-specific set of configuration objects: connection parameters, +/// signing parameters and bridge initialisation parameters. +#[macro_export] macro_rules! declare_chain_options { ($chain:ident, $chain_prefix:ident) => { paste::item! { @@ -557,17 +414,14 @@ macro_rules! declare_chain_options { pub struct [<$chain BridgeInitializationParams>] { #[doc = "Hex-encoded " $chain " header to initialize bridge with. If not specified, genesis header is used."] #[structopt(long)] - pub [<$chain_prefix _initial_header>]: Option, + pub [<$chain_prefix _initial_header>]: Option, #[doc = "Hex-encoded " $chain " GRANDPA authorities set to initialize bridge with. If not specified, set from genesis block is used."] #[structopt(long)] - pub [<$chain_prefix _initial_authorities>]: Option, + pub [<$chain_prefix _initial_authorities>]: Option, #[doc = "Id of the " $chain " GRANDPA authorities set to initialize bridge with. If not specified, zero is used."] #[structopt(long)] - pub [<$chain_prefix _initial_authorities_set_id>]: Option, + pub [<$chain_prefix _initial_authorities_set_id>]: Option, } } }; } - -declare_chain_options!(Rialto, rialto); -declare_chain_options!(Millau, millau); diff --git a/bridges/relays/substrate/src/main.rs b/bridges/relays/substrate/src/main.rs index 8cd437027c95c..eaaa9848836e9 100644 --- a/bridges/relays/substrate/src/main.rs +++ b/bridges/relays/substrate/src/main.rs @@ -18,24 +18,7 @@ #![warn(missing_docs)] -use codec::{Decode, Encode}; -use frame_support::weights::{GetDispatchInfo, Weight}; -use pallet_bridge_call_dispatch::{CallOrigin, MessagePayload}; -use relay_kusama_client::Kusama; -use relay_millau_client::{Millau, SigningParams as MillauSigningParams}; -use relay_rialto_client::{Rialto, SigningParams as RialtoSigningParams}; -use relay_substrate_client::{Chain, ConnectionParams, TransactionSignScheme}; use relay_utils::initialize::initialize_relay; -use sp_core::{Bytes, Pair}; -use sp_runtime::traits::IdentifyAccount; -use std::fmt::Debug; - -/// Kusama node client. -pub type KusamaClient = relay_substrate_client::Client; -/// Millau node client. -pub type MillauClient = relay_substrate_client::Client; -/// Rialto node client. -pub type RialtoClient = relay_substrate_client::Client; mod cli; mod finality_pipeline; @@ -44,929 +27,15 @@ mod headers_initialize; mod messages_lane; mod messages_source; mod messages_target; -mod millau_headers_to_rialto; -mod millau_messages_to_rialto; -mod rialto_headers_to_millau; -mod rialto_messages_to_millau; + +mod rialto_millau; fn main() { initialize_relay(); - - let result = async_std::task::block_on(run_command(cli::parse_args())); + let command = cli::parse_args(); + let run = command.run(); + let result = async_std::task::block_on(run); if let Err(error) = result { log::error!(target: "bridge", "Failed to start relay: {}", error); } } - -async fn run_command(command: cli::Command) -> Result<(), String> { - match command { - cli::Command::InitBridge(arg) => run_init_bridge(arg).await, - cli::Command::RelayHeaders(arg) => run_relay_headers(arg).await, - cli::Command::RelayMessages(arg) => run_relay_messages(arg).await, - cli::Command::SendMessage(arg) => run_send_message(arg).await, - cli::Command::EncodeCall(arg) => run_encode_call(arg).await, - cli::Command::EncodeMessagePayload(arg) => run_encode_message_payload(arg).await, - cli::Command::EstimateFee(arg) => run_estimate_fee(arg).await, - cli::Command::DeriveAccount(arg) => run_derive_account(arg).await, - } -} - -async fn run_init_bridge(command: cli::InitBridge) -> Result<(), String> { - match command { - cli::InitBridge::MillauToRialto { - millau, - rialto, - rialto_sign, - millau_bridge_params, - } => { - let millau_client = millau.into_client().await?; - let rialto_client = rialto.into_client().await?; - let rialto_sign = rialto_sign.parse()?; - - let rialto_signer_next_index = rialto_client - .next_account_index(rialto_sign.signer.public().into()) - .await?; - - headers_initialize::initialize( - millau_client, - rialto_client.clone(), - millau_bridge_params.millau_initial_header, - millau_bridge_params.millau_initial_authorities, - millau_bridge_params.millau_initial_authorities_set_id, - move |initialization_data| { - Ok(Bytes( - Rialto::sign_transaction( - *rialto_client.genesis_hash(), - &rialto_sign.signer, - rialto_signer_next_index, - rialto_runtime::SudoCall::sudo(Box::new( - rialto_runtime::FinalityBridgeMillauCall::initialize(initialization_data).into(), - )) - .into(), - ) - .encode(), - )) - }, - ) - .await; - } - cli::InitBridge::RialtoToMillau { - rialto, - millau, - millau_sign, - rialto_bridge_params, - } => { - let rialto_client = rialto.into_client().await?; - let millau_client = millau.into_client().await?; - let millau_sign = millau_sign.parse()?; - let millau_signer_next_index = millau_client - .next_account_index(millau_sign.signer.public().into()) - .await?; - - headers_initialize::initialize( - rialto_client, - millau_client.clone(), - rialto_bridge_params.rialto_initial_header, - rialto_bridge_params.rialto_initial_authorities, - rialto_bridge_params.rialto_initial_authorities_set_id, - move |initialization_data| { - Ok(Bytes( - Millau::sign_transaction( - *millau_client.genesis_hash(), - &millau_sign.signer, - millau_signer_next_index, - millau_runtime::SudoCall::sudo(Box::new( - millau_runtime::FinalityBridgeRialtoCall::initialize(initialization_data).into(), - )) - .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; - } - } - Ok(()) -} - -async fn run_relay_messages(command: cli::RelayMessages) -> Result<(), String> { - match command { - cli::RelayMessages::MillauToRialto { - millau, - millau_sign, - rialto, - rialto_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()?; - - millau_messages_to_rialto::run( - millau_client, - millau_sign, - rialto_client, - rialto_sign, - lane.into(), - prometheus_params.into(), - ); - } - cli::RelayMessages::RialtoToMillau { - rialto, - rialto_sign, - millau, - millau_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()?; - - rialto_messages_to_millau::run( - rialto_client, - rialto_sign, - millau_client, - millau_sign, - lane.into(), - prometheus_params.into(), - ); - } - } - Ok(()) -} - -async fn run_send_message(command: cli::SendMessage) -> Result<(), String> { - match command { - cli::SendMessage::MillauToRialto { - millau, - millau_sign, - rialto_sign, - lane, - message, - dispatch_weight, - fee, - 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()?; - - let payload = - millau_to_rialto_message_payload(&millau_sign, &rialto_sign, &rialto_call, origin, dispatch_weight); - 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, - lane, - payload.clone(), - ) - }) - .await?; - - let millau_call = millau_runtime::Call::BridgeRialtoMessageLane( - millau_runtime::MessageLaneCall::send_message(lane, payload, fee), - ); - - let signed_millau_call = Millau::sign_transaction( - *millau_client.genesis_hash(), - &millau_sign.signer, - millau_client - .next_account_index(millau_sign.signer.public().clone().into()) - .await?, - millau_call, - ) - .encode(); - - log::info!( - target: "bridge", - "Sending message to Rialto. Size: {}. Dispatch weight: {}. Fee: {}", - signed_millau_call.len(), - dispatch_weight, - fee, - ); - log::info!(target: "bridge", "Signed Millau Call: {:?}", HexBytes::encode(&signed_millau_call)); - - millau_client.submit_extrinsic(Bytes(signed_millau_call)).await?; - } - cli::SendMessage::RialtoToMillau { - rialto, - rialto_sign, - millau_sign, - lane, - message, - dispatch_weight, - fee, - 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()?; - - let payload = - rialto_to_millau_message_payload(&rialto_sign, &millau_sign, &millau_call, origin, dispatch_weight); - 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, - lane, - payload.clone(), - ) - }) - .await?; - - let rialto_call = rialto_runtime::Call::BridgeMillauMessageLane( - rialto_runtime::MessageLaneCall::send_message(lane, payload, fee), - ); - - let signed_rialto_call = Rialto::sign_transaction( - *rialto_client.genesis_hash(), - &rialto_sign.signer, - rialto_client - .next_account_index(rialto_sign.signer.public().clone().into()) - .await?, - rialto_call, - ) - .encode(); - - log::info!( - target: "bridge", - "Sending message to Millau. Size: {}. Dispatch weight: {}. Fee: {}", - signed_rialto_call.len(), - dispatch_weight, - fee, - ); - log::info!(target: "bridge", "Signed Rialto Call: {:?}", HexBytes::encode(&signed_rialto_call)); - - rialto_client.submit_extrinsic(Bytes(signed_rialto_call)).await?; - } - } - Ok(()) -} - -async fn run_encode_call(call: cli::EncodeCall) -> Result<(), String> { - match call { - cli::EncodeCall::Rialto { call } => { - let call = call.into_call()?; - - println!("{:?}", HexBytes::encode(&call)); - } - cli::EncodeCall::Millau { call } => { - let call = call.into_call()?; - println!("{:?}", HexBytes::encode(&call)); - } - } - Ok(()) -} - -async fn run_encode_message_payload(call: cli::EncodeMessagePayload) -> Result<(), String> { - match call { - cli::EncodeMessagePayload::RialtoToMillau { payload } => { - let payload = payload.into_payload()?; - - println!("{:?}", HexBytes::encode(&payload)); - } - cli::EncodeMessagePayload::MillauToRialto { payload } => { - let payload = payload.into_payload()?; - - println!("{:?}", HexBytes::encode(&payload)); - } - } - Ok(()) -} - -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()?; - - let fee: Option = estimate_message_delivery_and_dispatch_fee( - &client, - bp_millau::TO_MILLAU_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()?; - - let fee: Option = estimate_message_delivery_and_dispatch_fee( - &client, - bp_rialto::TO_RIALTO_ESTIMATE_MESSAGE_FEE_METHOD, - lane, - payload, - ) - .await?; - - println!("Fee: {:?}", fee); - } - } - - Ok(()) -} - -async fn run_derive_account(cmd: cli::DeriveAccount) -> Result<(), String> { - match cmd { - cli::DeriveAccount::RialtoToMillau { account } => { - let account = account.into_rialto(); - let acc = bp_runtime::SourceAccount::Account(account.clone()); - let id = bp_millau::derive_account_from_rialto_id(acc); - println!( - "{} (Rialto)\n\nCorresponding (derived) account id:\n-> {} (Millau)", - account, id - ) - } - cli::DeriveAccount::MillauToRialto { account } => { - let account = account.into_millau(); - let acc = bp_runtime::SourceAccount::Account(account.clone()); - let id = bp_rialto::derive_account_from_millau_id(acc); - println!( - "{} (Millau)\n\nCorresponding (derived) account id:\n-> {} (Rialto)", - account, id - ) - } - } - - Ok(()) -} - -async fn estimate_message_delivery_and_dispatch_fee( - client: &relay_substrate_client::Client, - estimate_fee_method: &str, - lane: bp_message_lane::LaneId, - payload: P, -) -> Result, relay_substrate_client::Error> { - let encoded_response = client - .state_call(estimate_fee_method.into(), (lane, payload).encode().into(), None) - .await?; - let decoded_response: Option = - Decode::decode(&mut &encoded_response.0[..]).map_err(relay_substrate_client::Error::ResponseParseFailed)?; - Ok(decoded_response) -} - -fn remark_payload(remark_size: Option>, maximal_allowed_size: u32) -> Vec { - match remark_size { - Some(cli::ExplicitOrMaximal::Explicit(remark_size)) => vec![0; remark_size], - Some(cli::ExplicitOrMaximal::Maximal) => vec![0; maximal_allowed_size as _], - None => format!( - "Unix time: {}", - std::time::SystemTime::now() - .duration_since(std::time::SystemTime::UNIX_EPOCH) - .unwrap_or_default() - .as_secs(), - ) - .as_bytes() - .to_vec(), - } -} - -fn message_payload( - spec_version: u32, - weight: Weight, - origin: CallOrigin, - call: &impl Encode, -) -> MessagePayload> -where - SAccountId: Encode + Debug, - TPublic: Encode + Debug, - TSignature: Encode + Debug, -{ - // Display nicely formatted call. - let payload = MessagePayload { - spec_version, - weight, - origin, - call: HexBytes::encode(call), - }; - - log::info!(target: "bridge", "Created Message Payload: {:#?}", payload); - log::info!(target: "bridge", "Encoded Message Payload: {:?}", HexBytes::encode(&payload)); - - // re-pack to return `Vec` - let MessagePayload { - spec_version, - weight, - origin, - call, - } = payload; - MessagePayload { - spec_version, - weight, - origin, - call: call.0, - } -} - -fn rialto_to_millau_message_payload( - rialto_sign: &RialtoSigningParams, - millau_sign: &MillauSigningParams, - millau_call: &millau_runtime::Call, - origin: cli::Origins, - user_specified_dispatch_weight: Option>, -) -> rialto_runtime::millau_messages::ToMillauMessagePayload { - let millau_call_weight = prepare_call_dispatch_weight( - user_specified_dispatch_weight, - cli::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 { - cli::Origins::Source => CallOrigin::SourceAccount(rialto_account_id), - cli::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: cli::Origins, - user_specified_dispatch_weight: Option>, -) -> millau_runtime::rialto_messages::ToRialtoMessagePayload { - let rialto_call_weight = prepare_call_dispatch_weight( - user_specified_dispatch_weight, - cli::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 { - cli::Origins::Source => CallOrigin::SourceAccount(millau_account_id), - cli::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: cli::ExplicitOrMaximal, - maximal_allowed_weight: Weight, -) -> Weight { - match user_specified_dispatch_weight.unwrap_or(weight_from_pre_dispatch_call) { - cli::ExplicitOrMaximal::Explicit(weight) => weight, - cli::ExplicitOrMaximal::Maximal => maximal_allowed_weight, - } -} - -async fn get_fee(fee: Option, f: F) -> Result -where - Fee: Decode, - F: FnOnce() -> R, - R: std::future::Future, E>>, - E: Debug, -{ - match fee { - Some(fee) => Ok(fee), - None => match f().await { - Ok(Some(fee)) => Ok(fee), - Ok(None) => Err("Failed to estimate message fee. Message is too heavy?".into()), - Err(error) => Err(format!("Failed to estimate message fee: {:?}", error)), - }, - } -} - -fn compute_maximal_message_dispatch_weight(maximal_extrinsic_weight: Weight) -> Weight { - bridge_runtime_common::messages::target::maximal_incoming_message_dispatch_weight(maximal_extrinsic_weight) -} - -fn compute_maximal_message_arguments_size( - maximal_source_extrinsic_size: u32, - maximal_target_extrinsic_size: u32, -) -> u32 { - // assume that both signed extensions and other arguments fit 1KB - let service_tx_bytes_on_source_chain = 1024; - let maximal_source_extrinsic_size = maximal_source_extrinsic_size - service_tx_bytes_on_source_chain; - let maximal_call_size = - bridge_runtime_common::messages::target::maximal_incoming_message_size(maximal_target_extrinsic_size); - let maximal_call_size = if maximal_call_size > maximal_source_extrinsic_size { - maximal_source_extrinsic_size - } else { - maximal_call_size - }; - - // bytes in Call encoding that are used to encode everything except arguments - let service_bytes = 1 + 1 + 4; - maximal_call_size - service_bytes -} - -impl crate::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, sender } => { - let spec_version = rialto_runtime::VERSION.spec_version; - let origin = CallOrigin::SourceAccount(sender.into_millau()); - let call = message.into_call()?; - let weight = call.get_dispatch_info().weight; - - Ok(message_payload(spec_version, weight, origin, &call)) - } - } - } -} - -impl crate::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, sender } => { - let spec_version = millau_runtime::VERSION.spec_version; - let origin = CallOrigin::SourceAccount(sender.into_rialto()); - let call = message.into_call()?; - let weight = call.get_dispatch_info().weight; - - Ok(message_payload(spec_version, weight, origin, &call)) - } - } - } -} - -impl crate::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 crate::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 crate::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, - }) - .await - } -} -impl crate::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, - }) - .await - } -} - -impl crate::cli::ToRialtoMessage { - /// Convert CLI call request into runtime `Call` instance. - pub fn into_call(self) -> Result { - let call = match self { - cli::ToRialtoMessage::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 { recipient, amount } => { - let recipient = recipient.into_rialto(); - rialto_runtime::Call::Balances(rialto_runtime::BalancesCall::transfer(recipient, amount)) - } - cli::ToRialtoMessage::MillauSendMessage { lane, payload, fee } => { - let payload = cli::RialtoToMillauMessagePayload::Raw { data: payload }.into_payload()?; - let lane = lane.into(); - rialto_runtime::Call::BridgeMillauMessageLane(rialto_runtime::MessageLaneCall::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 crate::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 } => { - millau_runtime::Call::System(millau_runtime::SystemCall::remark(remark_payload( - remark_size, - compute_maximal_message_arguments_size( - bp_rialto::max_extrinsic_size(), - bp_millau::max_extrinsic_size(), - ), - ))) - } - cli::ToMillauMessage::Transfer { recipient, amount } => { - let recipient = recipient.into_millau(); - millau_runtime::Call::Balances(millau_runtime::BalancesCall::transfer(recipient, amount)) - } - cli::ToMillauMessage::RialtoSendMessage { lane, payload, fee } => { - let payload = cli::MillauToRialtoMessagePayload::Raw { data: payload }.into_payload()?; - let lane = lane.into(); - millau_runtime::Call::BridgeRialtoMessageLane(millau_runtime::MessageLaneCall::send_message( - lane, payload, fee, - )) - } - }; - - log::info!(target: "bridge", "Generated Millau call: {:#?}", call); - log::info!(target: "bridge", "Weight of Millau call: {}", call.get_dispatch_info().weight); - log::info!(target: "bridge", "Encoded Millau call: {:?}", HexBytes::encode(&call)); - - Ok(call) - } -} - -/// Nicer formatting for raw bytes vectors. -#[derive(Encode, Decode)] -struct HexBytes(Vec); - -impl Debug for HexBytes { - fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result { - write!(fmt, "0x{}", hex::encode(&self.0)) - } -} - -impl HexBytes { - /// Encode given object and wrap into nicely formatted bytes. - pub fn encode(t: &T) -> Self { - Self(t.encode()) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use bp_message_lane::source_chain::TargetHeaderChain; - use sp_core::Pair; - use sp_runtime::traits::{IdentifyAccount, Verify}; - - #[test] - fn millau_signature_is_valid_on_rialto() { - let millau_sign = relay_millau_client::SigningParams::from_suri("//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_account_id: bp_millau::AccountId = millau_public.into_account(); - - let digest = millau_runtime::rialto_account_ownership_digest( - &call, - millau_account_id, - rialto_runtime::VERSION.spec_version, - ); - - let rialto_signer = relay_rialto_client::SigningParams::from_suri("//Dave", None).unwrap(); - let signature = rialto_signer.signer.sign(&digest); - - assert!(signature.verify(&digest[..], &rialto_signer.signer.public())); - } - - #[test] - fn rialto_signature_is_valid_on_millau() { - let rialto_sign = relay_rialto_client::SigningParams::from_suri("//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_account_id: bp_rialto::AccountId = rialto_public.into_account(); - - let digest = rialto_runtime::millau_account_ownership_digest( - &call, - rialto_account_id, - millau_runtime::VERSION.spec_version, - ); - - let millau_signer = relay_millau_client::SigningParams::from_suri("//Dave", None).unwrap(); - let signature = millau_signer.signer.sign(&digest); - - assert!(signature.verify(&digest[..], &millau_signer.signer.public())); - } - - #[test] - fn maximal_rialto_to_millau_message_arguments_size_is_computed_correctly() { - use rialto_runtime::millau_messages::Millau; - - let maximal_remark_size = - compute_maximal_message_arguments_size(bp_rialto::max_extrinsic_size(), bp_millau::max_extrinsic_size()); - - let call: millau_runtime::Call = millau_runtime::SystemCall::remark(vec![42; maximal_remark_size as _]).into(); - let payload = message_payload( - Default::default(), - call.get_dispatch_info().weight, - pallet_bridge_call_dispatch::CallOrigin::SourceRoot, - &call, - ); - assert_eq!(Millau::verify_message(&payload), Ok(())); - - let call: millau_runtime::Call = - millau_runtime::SystemCall::remark(vec![42; (maximal_remark_size + 1) as _]).into(); - let payload = message_payload( - Default::default(), - call.get_dispatch_info().weight, - pallet_bridge_call_dispatch::CallOrigin::SourceRoot, - &call, - ); - assert!(Millau::verify_message(&payload).is_err()); - } - - #[test] - fn maximal_size_remark_to_rialto_is_generated_correctly() { - assert!( - bridge_runtime_common::messages::target::maximal_incoming_message_size( - bp_rialto::max_extrinsic_size() - ) > bp_millau::max_extrinsic_size(), - "We can't actually send maximal messages to Rialto from Millau, because Millau extrinsics can't be that large", - ) - } - - #[test] - fn maximal_rialto_to_millau_message_dispatch_weight_is_computed_correctly() { - use rialto_runtime::millau_messages::Millau; - - let maximal_dispatch_weight = compute_maximal_message_dispatch_weight(bp_millau::max_extrinsic_weight()); - let call: millau_runtime::Call = rialto_runtime::SystemCall::remark(vec![]).into(); - - let payload = message_payload( - Default::default(), - maximal_dispatch_weight, - pallet_bridge_call_dispatch::CallOrigin::SourceRoot, - &call, - ); - assert_eq!(Millau::verify_message(&payload), Ok(())); - - let payload = message_payload( - Default::default(), - maximal_dispatch_weight + 1, - pallet_bridge_call_dispatch::CallOrigin::SourceRoot, - &call, - ); - assert!(Millau::verify_message(&payload).is_err()); - } - - #[test] - fn maximal_weight_fill_block_to_rialto_is_generated_correctly() { - use millau_runtime::rialto_messages::Rialto; - - let maximal_dispatch_weight = compute_maximal_message_dispatch_weight(bp_rialto::max_extrinsic_weight()); - let call: rialto_runtime::Call = millau_runtime::SystemCall::remark(vec![]).into(); - - let payload = message_payload( - Default::default(), - maximal_dispatch_weight, - pallet_bridge_call_dispatch::CallOrigin::SourceRoot, - &call, - ); - assert_eq!(Rialto::verify_message(&payload), Ok(())); - - let payload = message_payload( - Default::default(), - maximal_dispatch_weight + 1, - pallet_bridge_call_dispatch::CallOrigin::SourceRoot, - &call, - ); - assert!(Rialto::verify_message(&payload).is_err()); - } - - #[test] - fn rialto_tx_extra_bytes_constant_is_correct() { - let rialto_call = rialto_runtime::Call::System(rialto_runtime::SystemCall::remark(vec![])); - let rialto_tx = Rialto::sign_transaction( - Default::default(), - &sp_keyring::AccountKeyring::Alice.pair(), - 0, - rialto_call.clone(), - ); - let extra_bytes_in_transaction = rialto_tx.encode().len() - rialto_call.encode().len(); - assert!( - bp_rialto::TX_EXTRA_BYTES as usize >= extra_bytes_in_transaction, - "Hardcoded number of extra bytes in Rialto transaction {} is lower than actual value: {}", - bp_rialto::TX_EXTRA_BYTES, - extra_bytes_in_transaction, - ); - } - - #[test] - fn millau_tx_extra_bytes_constant_is_correct() { - let millau_call = millau_runtime::Call::System(millau_runtime::SystemCall::remark(vec![])); - let millau_tx = Millau::sign_transaction( - Default::default(), - &sp_keyring::AccountKeyring::Alice.pair(), - 0, - millau_call.clone(), - ); - let extra_bytes_in_transaction = millau_tx.encode().len() - millau_call.encode().len(); - assert!( - bp_millau::TX_EXTRA_BYTES as usize >= extra_bytes_in_transaction, - "Hardcoded number of extra bytes in Millau transaction {} is lower than actual value: {}", - bp_millau::TX_EXTRA_BYTES, - extra_bytes_in_transaction, - ); - } -} diff --git a/bridges/relays/substrate/src/rialto_millau/cli.rs b/bridges/relays/substrate/src/rialto_millau/cli.rs new file mode 100644 index 0000000000000..6ef5625921e32 --- /dev/null +++ b/bridges/relays/substrate/src/rialto_millau/cli.rs @@ -0,0 +1,423 @@ +// Copyright 2019-2020 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 . + +//! Deal with CLI args of Rialto <> Millau relay. + +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, + }, +} + +impl RelayHeaders { + /// Run the command. + pub async fn run(self) -> anyhow::Result<()> { + super::run_relay_headers(self).await.map_err(format_err)?; + Ok(()) + } +} + +/// Start message relayer process. +#[derive(StructOpt)] +pub enum RelayMessages { + /// Serve given lane of Millau -> Rialto messages. + MillauToRialto { + #[structopt(flatten)] + millau: MillauConnectionParams, + #[structopt(flatten)] + millau_sign: MillauSigningParams, + #[structopt(flatten)] + rialto: RialtoConnectionParams, + #[structopt(flatten)] + rialto_sign: RialtoSigningParams, + #[structopt(flatten)] + prometheus_params: PrometheusParams, + /// Hex-encoded lane id that should be served by the relay. Defaults to `00000000`. + #[structopt(long, default_value = "00000000")] + lane: HexLaneId, + }, + /// Serve given lane of Rialto -> Millau messages. + RialtoToMillau { + #[structopt(flatten)] + rialto: RialtoConnectionParams, + #[structopt(flatten)] + rialto_sign: RialtoSigningParams, + #[structopt(flatten)] + millau: MillauConnectionParams, + #[structopt(flatten)] + millau_sign: MillauSigningParams, + #[structopt(flatten)] + prometheus_params: PrometheusParams, + /// Hex-encoded lane id that should be served by the relay. Defaults to `00000000`. + #[structopt(long, default_value = "00000000")] + lane: HexLaneId, + }, +} + +impl RelayMessages { + /// Run the command. + pub async fn run(self) -> anyhow::Result<()> { + super::run_relay_messages(self).await.map_err(format_err)?; + Ok(()) + } +} + +/// 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, + #[structopt(flatten)] + millau_bridge_params: MillauBridgeInitializationParams, + }, + /// Initialize Rialto headers bridge in Millau. + RialtoToMillau { + #[structopt(flatten)] + rialto: RialtoConnectionParams, + #[structopt(flatten)] + millau: MillauConnectionParams, + #[structopt(flatten)] + millau_sign: MillauSigningParams, + #[structopt(flatten)] + rialto_bridge_params: RialtoBridgeInitializationParams, + }, +} + +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. +#[derive(StructOpt)] +pub enum SendMessage { + /// Submit message to given Millau -> Rialto lane. + MillauToRialto { + #[structopt(flatten)] + millau: MillauConnectionParams, + #[structopt(flatten)] + millau_sign: MillauSigningParams, + #[structopt(flatten)] + rialto_sign: RialtoSigningParams, + /// Hex-encoded lane id. Defaults to `00000000`. + #[structopt(long, default_value = "00000000")] + lane: HexLaneId, + /// Dispatch weight of the message. If not passed, determined automatically. + #[structopt(long)] + dispatch_weight: Option>, + /// Delivery and dispatch fee in source chain base currency units. If not passed, determined automatically. + #[structopt(long)] + fee: Option, + /// Message type. + #[structopt(subcommand)] + message: ToRialtoMessage, + /// The origin to use when dispatching the message on the target chain. Defaults to + /// `SourceAccount`. + #[structopt(long, possible_values = &Origins::variants(), default_value = "Source")] + origin: Origins, + }, + /// Submit message to given Rialto -> Millau lane. + RialtoToMillau { + #[structopt(flatten)] + rialto: RialtoConnectionParams, + #[structopt(flatten)] + rialto_sign: RialtoSigningParams, + #[structopt(flatten)] + millau_sign: MillauSigningParams, + /// Hex-encoded lane id. Defaults to `00000000`. + #[structopt(long, default_value = "00000000")] + lane: HexLaneId, + /// Dispatch weight of the message. If not passed, determined automatically. + #[structopt(long)] + dispatch_weight: Option>, + /// Delivery and dispatch fee in source chain base currency units. If not passed, determined automatically. + #[structopt(long)] + fee: Option, + /// Message type. + #[structopt(subcommand)] + message: ToMillauMessage, + /// The origin to use when dispatching the message on the target chain. Defaults to + /// `SourceAccount`. + #[structopt(long, possible_values = &Origins::variants(), default_value = "Source")] + origin: Origins, + }, +} + +impl SendMessage { + /// Run the command. + pub async fn run(self) -> anyhow::Result<()> { + super::run_send_message(self).await.map_err(format_err)?; + Ok(()) + } +} + +/// A call to encode. +#[derive(StructOpt)] +pub enum EncodeCall { + /// Encode Rialto's Call. + Rialto { + #[structopt(flatten)] + call: ToRialtoMessage, + }, + /// Encode Millau's Call. + Millau { + #[structopt(flatten)] + call: ToMillauMessage, + }, +} + +impl EncodeCall { + /// Run the command. + pub async fn run(self) -> anyhow::Result<()> { + super::run_encode_call(self).await.map_err(format_err)?; + Ok(()) + } +} + +/// A `MessagePayload` to encode. +#[derive(StructOpt)] +pub enum EncodeMessagePayload { + /// Message Payload of Rialto to Millau call. + RialtoToMillau { + #[structopt(flatten)] + payload: RialtoToMillauMessagePayload, + }, + /// Message Payload of Millau to Rialto call. + MillauToRialto { + #[structopt(flatten)] + payload: MillauToRialtoMessagePayload, + }, +} + +impl EncodeMessagePayload { + /// Run the command. + pub async fn run(self) -> anyhow::Result<()> { + super::run_encode_message_payload(self).await.map_err(format_err)?; + Ok(()) + } +} + +/// Estimate Delivery & Dispatch Fee command. +#[derive(StructOpt)] +pub enum EstimateFee { + /// Estimate fee of Rialto to Millau message. + RialtoToMillau { + #[structopt(flatten)] + rialto: RialtoConnectionParams, + /// 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, + }, + /// Estimate fee of Rialto to Millau message. + MillauToRialto { + #[structopt(flatten)] + millau: MillauConnectionParams, + /// 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, + }, +} + +impl EstimateFee { + /// Run the command. + pub async fn run(self) -> anyhow::Result<()> { + super::run_estimate_fee(self).await.map_err(format_err)?; + Ok(()) + } +} + +/// Given a source chain `AccountId`, derive the corresponding `AccountId` for the target chain. +/// +/// The (derived) target chain `AccountId` is going to be used as dispatch origin of the call +/// 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. +#[derive(StructOpt)] +pub enum DeriveAccount { + /// Given Rialto AccountId, display corresponding Millau AccountId. + RialtoToMillau { account: AccountId }, + /// Given Millau AccountId, display corresponding Rialto AccountId. + MillauToRialto { account: AccountId }, +} + +impl DeriveAccount { + /// Run the command. + pub async fn run(self) -> anyhow::Result<()> { + super::run_derive_account(self).await.map_err(format_err)?; + Ok(()) + } +} + +fn format_err(err: String) -> anyhow::Error { + anyhow::anyhow!(err) +} + +/// MessagePayload that can be delivered to message lane pallet on Millau. +#[derive(StructOpt, Debug)] +pub enum MillauToRialtoMessagePayload { + /// Raw, SCALE-encoded `MessagePayload`. + Raw { + /// Hex-encoded SCALE data. + data: HexBytes, + }, + /// Construct message to send over the bridge. + Message { + /// Message details. + #[structopt(flatten)] + message: ToRialtoMessage, + /// SS58 encoded account that will send the payload (must have SS58Prefix = 42) + #[structopt(long)] + sender: AccountId, + }, +} + +/// MessagePayload that can be delivered to message lane pallet on Rialto. +#[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 { + /// Raw bytes for the message + Raw { + /// Raw, SCALE-encoded message + data: HexBytes, + }, + /// Make an on-chain remark (comment). + Remark { + /// Remark size. 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_rialto::Balance, + }, + /// A call to the Millau Bridge Message Lane pallet to send a message over the bridge. + MillauSendMessage { + /// 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 message lane pallet. + #[structopt(long)] + payload: HexBytes, + /// Declared delivery and dispatch fee in base source-chain currency units. + #[structopt(long)] + fee: bp_rialto::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 Message Lane 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 message lane 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); diff --git a/bridges/relays/substrate/src/millau_headers_to_rialto.rs b/bridges/relays/substrate/src/rialto_millau/millau_headers_to_rialto.rs similarity index 95% rename from bridges/relays/substrate/src/millau_headers_to_rialto.rs rename to bridges/relays/substrate/src/rialto_millau/millau_headers_to_rialto.rs index f84eee03a9fd0..de03fead20144 100644 --- a/bridges/relays/substrate/src/millau_headers_to_rialto.rs +++ b/bridges/relays/substrate/src/rialto_millau/millau_headers_to_rialto.rs @@ -16,10 +16,8 @@ //! Millau-to-Rialto headers sync entrypoint. -use crate::{ - finality_pipeline::{SubstrateFinalitySyncPipeline, SubstrateFinalityToSubstrate}, - MillauClient, RialtoClient, -}; +use super::{MillauClient, RialtoClient}; +use crate::finality_pipeline::{SubstrateFinalitySyncPipeline, SubstrateFinalityToSubstrate}; use async_trait::async_trait; use relay_millau_client::{Millau, SyncHeader as MillauSyncHeader}; diff --git a/bridges/relays/substrate/src/millau_messages_to_rialto.rs b/bridges/relays/substrate/src/rialto_millau/millau_messages_to_rialto.rs similarity index 99% rename from bridges/relays/substrate/src/millau_messages_to_rialto.rs rename to bridges/relays/substrate/src/rialto_millau/millau_messages_to_rialto.rs index f3dfdadf9a38d..84664e4572bba 100644 --- a/bridges/relays/substrate/src/millau_messages_to_rialto.rs +++ b/bridges/relays/substrate/src/rialto_millau/millau_messages_to_rialto.rs @@ -16,10 +16,10 @@ //! Millau-to-Rialto messages sync entrypoint. +use super::{MillauClient, RialtoClient}; use crate::messages_lane::{select_delivery_transaction_limits, SubstrateMessageLane, SubstrateMessageLaneToSubstrate}; use crate::messages_source::SubstrateMessagesSource; use crate::messages_target::SubstrateMessagesTarget; -use crate::{MillauClient, RialtoClient}; use async_trait::async_trait; use bp_message_lane::{LaneId, MessageNonce}; diff --git a/bridges/relays/substrate/src/rialto_millau/mod.rs b/bridges/relays/substrate/src/rialto_millau/mod.rs new file mode 100644 index 0000000000000..756a034974565 --- /dev/null +++ b/bridges/relays/substrate/src/rialto_millau/mod.rs @@ -0,0 +1,922 @@ +// Copyright 2019-2020 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 . + +//! Rialto <> Millau Bridge commands. + +pub mod cli; +pub mod millau_headers_to_rialto; +pub mod millau_messages_to_rialto; +pub mod rialto_headers_to_millau; +pub mod rialto_messages_to_millau; + +/// Millau node client. +pub type MillauClient = relay_substrate_client::Client; +/// Rialto node client. +pub type RialtoClient = relay_substrate_client::Client; + +use crate::cli::{ExplicitOrMaximal, HexBytes, Origins}; +use codec::{Decode, Encode}; +use frame_support::weights::{GetDispatchInfo, Weight}; +use pallet_bridge_call_dispatch::{CallOrigin, MessagePayload}; +use relay_millau_client::{Millau, SigningParams as MillauSigningParams}; +use relay_rialto_client::{Rialto, SigningParams as RialtoSigningParams}; +use relay_substrate_client::{Chain, ConnectionParams, TransactionSignScheme}; +use sp_core::{Bytes, Pair}; +use sp_runtime::traits::IdentifyAccount; +use std::fmt::Debug; + +async fn run_init_bridge(command: cli::InitBridge) -> Result<(), String> { + match command { + cli::InitBridge::MillauToRialto { + millau, + rialto, + rialto_sign, + millau_bridge_params, + } => { + let millau_client = millau.into_client().await?; + let rialto_client = rialto.into_client().await?; + let rialto_sign = rialto_sign.parse()?; + + let rialto_signer_next_index = rialto_client + .next_account_index(rialto_sign.signer.public().into()) + .await?; + + crate::headers_initialize::initialize( + millau_client, + rialto_client.clone(), + millau_bridge_params.millau_initial_header, + millau_bridge_params.millau_initial_authorities, + millau_bridge_params.millau_initial_authorities_set_id, + move |initialization_data| { + Ok(Bytes( + Rialto::sign_transaction( + *rialto_client.genesis_hash(), + &rialto_sign.signer, + rialto_signer_next_index, + rialto_runtime::SudoCall::sudo(Box::new( + rialto_runtime::FinalityBridgeMillauCall::initialize(initialization_data).into(), + )) + .into(), + ) + .encode(), + )) + }, + ) + .await; + } + cli::InitBridge::RialtoToMillau { + rialto, + millau, + millau_sign, + rialto_bridge_params, + } => { + let rialto_client = rialto.into_client().await?; + let millau_client = millau.into_client().await?; + let millau_sign = millau_sign.parse()?; + let millau_signer_next_index = millau_client + .next_account_index(millau_sign.signer.public().into()) + .await?; + + crate::headers_initialize::initialize( + rialto_client, + millau_client.clone(), + rialto_bridge_params.rialto_initial_header, + rialto_bridge_params.rialto_initial_authorities, + rialto_bridge_params.rialto_initial_authorities_set_id, + move |initialization_data| { + Ok(Bytes( + Millau::sign_transaction( + *millau_client.genesis_hash(), + &millau_sign.signer, + millau_signer_next_index, + millau_runtime::SudoCall::sudo(Box::new( + millau_runtime::FinalityBridgeRialtoCall::initialize(initialization_data).into(), + )) + .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; + } + } + Ok(()) +} + +async fn run_relay_messages(command: cli::RelayMessages) -> Result<(), String> { + match command { + cli::RelayMessages::MillauToRialto { + millau, + millau_sign, + rialto, + rialto_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()?; + + millau_messages_to_rialto::run( + millau_client, + millau_sign, + rialto_client, + rialto_sign, + lane.into(), + prometheus_params.into(), + ); + } + cli::RelayMessages::RialtoToMillau { + rialto, + rialto_sign, + millau, + millau_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()?; + + rialto_messages_to_millau::run( + rialto_client, + rialto_sign, + millau_client, + millau_sign, + lane.into(), + prometheus_params.into(), + ); + } + } + Ok(()) +} + +async fn run_send_message(command: cli::SendMessage) -> Result<(), String> { + match command { + cli::SendMessage::MillauToRialto { + millau, + millau_sign, + rialto_sign, + lane, + message, + dispatch_weight, + fee, + 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()?; + + let payload = + millau_to_rialto_message_payload(&millau_sign, &rialto_sign, &rialto_call, origin, dispatch_weight); + 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, + lane, + payload.clone(), + ) + }) + .await?; + + let millau_call = millau_runtime::Call::BridgeRialtoMessageLane( + millau_runtime::MessageLaneCall::send_message(lane, payload, fee), + ); + + let signed_millau_call = Millau::sign_transaction( + *millau_client.genesis_hash(), + &millau_sign.signer, + millau_client + .next_account_index(millau_sign.signer.public().clone().into()) + .await?, + millau_call, + ) + .encode(); + + log::info!( + target: "bridge", + "Sending message to Rialto. Size: {}. Dispatch weight: {}. Fee: {}", + signed_millau_call.len(), + dispatch_weight, + fee, + ); + log::info!(target: "bridge", "Signed Millau Call: {:?}", HexBytes::encode(&signed_millau_call)); + + millau_client.submit_extrinsic(Bytes(signed_millau_call)).await?; + } + cli::SendMessage::RialtoToMillau { + rialto, + rialto_sign, + millau_sign, + lane, + message, + dispatch_weight, + fee, + 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()?; + + let payload = + rialto_to_millau_message_payload(&rialto_sign, &millau_sign, &millau_call, origin, dispatch_weight); + 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, + lane, + payload.clone(), + ) + }) + .await?; + + let rialto_call = rialto_runtime::Call::BridgeMillauMessageLane( + rialto_runtime::MessageLaneCall::send_message(lane, payload, fee), + ); + + let signed_rialto_call = Rialto::sign_transaction( + *rialto_client.genesis_hash(), + &rialto_sign.signer, + rialto_client + .next_account_index(rialto_sign.signer.public().clone().into()) + .await?, + rialto_call, + ) + .encode(); + + log::info!( + target: "bridge", + "Sending message to Millau. Size: {}. Dispatch weight: {}. Fee: {}", + signed_rialto_call.len(), + dispatch_weight, + fee, + ); + log::info!(target: "bridge", "Signed Rialto Call: {:?}", HexBytes::encode(&signed_rialto_call)); + + rialto_client.submit_extrinsic(Bytes(signed_rialto_call)).await?; + } + } + Ok(()) +} + +async fn run_encode_call(call: cli::EncodeCall) -> Result<(), String> { + match call { + cli::EncodeCall::Rialto { call } => { + let call = call.into_call()?; + + println!("{:?}", HexBytes::encode(&call)); + } + cli::EncodeCall::Millau { call } => { + let call = call.into_call()?; + println!("{:?}", HexBytes::encode(&call)); + } + } + Ok(()) +} + +async fn run_encode_message_payload(call: cli::EncodeMessagePayload) -> Result<(), String> { + match call { + cli::EncodeMessagePayload::RialtoToMillau { payload } => { + let payload = payload.into_payload()?; + + println!("{:?}", HexBytes::encode(&payload)); + } + cli::EncodeMessagePayload::MillauToRialto { payload } => { + let payload = payload.into_payload()?; + + println!("{:?}", HexBytes::encode(&payload)); + } + } + Ok(()) +} + +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()?; + + let fee: Option = estimate_message_delivery_and_dispatch_fee( + &client, + bp_millau::TO_MILLAU_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()?; + + let fee: Option = estimate_message_delivery_and_dispatch_fee( + &client, + bp_rialto::TO_RIALTO_ESTIMATE_MESSAGE_FEE_METHOD, + lane, + payload, + ) + .await?; + + println!("Fee: {:?}", fee); + } + } + + Ok(()) +} + +async fn run_derive_account(cmd: cli::DeriveAccount) -> Result<(), String> { + match cmd { + cli::DeriveAccount::RialtoToMillau { account } => { + let account = account.into_rialto(); + let acc = bp_runtime::SourceAccount::Account(account.clone()); + let id = bp_millau::derive_account_from_rialto_id(acc); + println!( + "{} (Rialto)\n\nCorresponding (derived) account id:\n-> {} (Millau)", + account, id + ) + } + cli::DeriveAccount::MillauToRialto { account } => { + let account = account.into_millau(); + let acc = bp_runtime::SourceAccount::Account(account.clone()); + let id = bp_rialto::derive_account_from_millau_id(acc); + println!( + "{} (Millau)\n\nCorresponding (derived) account id:\n-> {} (Rialto)", + account, id + ) + } + } + + Ok(()) +} + +async fn estimate_message_delivery_and_dispatch_fee( + client: &relay_substrate_client::Client, + estimate_fee_method: &str, + lane: bp_message_lane::LaneId, + payload: P, +) -> Result, relay_substrate_client::Error> { + let encoded_response = client + .state_call(estimate_fee_method.into(), (lane, payload).encode().into(), None) + .await?; + let decoded_response: Option = + Decode::decode(&mut &encoded_response.0[..]).map_err(relay_substrate_client::Error::ResponseParseFailed)?; + Ok(decoded_response) +} + +fn remark_payload(remark_size: Option>, maximal_allowed_size: u32) -> Vec { + match remark_size { + Some(ExplicitOrMaximal::Explicit(remark_size)) => vec![0; remark_size], + Some(ExplicitOrMaximal::Maximal) => vec![0; maximal_allowed_size as _], + None => format!( + "Unix time: {}", + std::time::SystemTime::now() + .duration_since(std::time::SystemTime::UNIX_EPOCH) + .unwrap_or_default() + .as_secs(), + ) + .as_bytes() + .to_vec(), + } +} + +fn message_payload( + spec_version: u32, + weight: Weight, + origin: CallOrigin, + call: &impl Encode, +) -> MessagePayload> +where + SAccountId: Encode + Debug, + TPublic: Encode + Debug, + TSignature: Encode + Debug, +{ + // Display nicely formatted call. + let payload = MessagePayload { + spec_version, + weight, + origin, + call: HexBytes::encode(call), + }; + + log::info!(target: "bridge", "Created Message Payload: {:#?}", payload); + log::info!(target: "bridge", "Encoded Message Payload: {:?}", HexBytes::encode(&payload)); + + // re-pack to return `Vec` + let MessagePayload { + spec_version, + weight, + origin, + call, + } = payload; + MessagePayload { + spec_version, + weight, + origin, + call: call.0, + } +} + +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, + maximal_allowed_weight: Weight, +) -> Weight { + match user_specified_dispatch_weight.unwrap_or(weight_from_pre_dispatch_call) { + ExplicitOrMaximal::Explicit(weight) => weight, + ExplicitOrMaximal::Maximal => maximal_allowed_weight, + } +} + +async fn get_fee(fee: Option, f: F) -> Result +where + Fee: Decode, + F: FnOnce() -> R, + R: std::future::Future, E>>, + E: Debug, +{ + match fee { + Some(fee) => Ok(fee), + None => match f().await { + Ok(Some(fee)) => Ok(fee), + Ok(None) => Err("Failed to estimate message fee. Message is too heavy?".into()), + Err(error) => Err(format!("Failed to estimate message fee: {:?}", error)), + }, + } +} + +fn compute_maximal_message_dispatch_weight(maximal_extrinsic_weight: Weight) -> Weight { + bridge_runtime_common::messages::target::maximal_incoming_message_dispatch_weight(maximal_extrinsic_weight) +} + +fn compute_maximal_message_arguments_size( + maximal_source_extrinsic_size: u32, + maximal_target_extrinsic_size: u32, +) -> u32 { + // assume that both signed extensions and other arguments fit 1KB + let service_tx_bytes_on_source_chain = 1024; + let maximal_source_extrinsic_size = maximal_source_extrinsic_size - service_tx_bytes_on_source_chain; + let maximal_call_size = + bridge_runtime_common::messages::target::maximal_incoming_message_size(maximal_target_extrinsic_size); + let maximal_call_size = if maximal_call_size > maximal_source_extrinsic_size { + maximal_source_extrinsic_size + } else { + maximal_call_size + }; + + // bytes in Call encoding that are used to encode everything except arguments + let service_bytes = 1 + 1 + 4; + 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, sender } => { + let spec_version = rialto_runtime::VERSION.spec_version; + let origin = CallOrigin::SourceAccount(sender.into_millau()); + let call = message.into_call()?; + let weight = call.get_dispatch_info().weight; + + Ok(message_payload(spec_version, weight, origin, &call)) + } + } + } +} + +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, sender } => { + let spec_version = millau_runtime::VERSION.spec_version; + let origin = CallOrigin::SourceAccount(sender.into_rialto()); + let call = message.into_call()?; + let weight = call.get_dispatch_info().weight; + + Ok(message_payload(spec_version, weight, origin, &call)) + } + } + } +} + +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, + }) + .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, + }) + .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 } => { + 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 { recipient, amount } => { + let recipient = recipient.into_rialto(); + rialto_runtime::Call::Balances(rialto_runtime::BalancesCall::transfer(recipient, amount)) + } + cli::ToRialtoMessage::MillauSendMessage { lane, payload, fee } => { + let payload = cli::RialtoToMillauMessagePayload::Raw { data: payload }.into_payload()?; + let lane = lane.into(); + rialto_runtime::Call::BridgeMillauMessageLane(rialto_runtime::MessageLaneCall::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 } => { + millau_runtime::Call::System(millau_runtime::SystemCall::remark(remark_payload( + remark_size, + compute_maximal_message_arguments_size( + bp_rialto::max_extrinsic_size(), + bp_millau::max_extrinsic_size(), + ), + ))) + } + cli::ToMillauMessage::Transfer { recipient, amount } => { + let recipient = recipient.into_millau(); + millau_runtime::Call::Balances(millau_runtime::BalancesCall::transfer(recipient, amount)) + } + cli::ToMillauMessage::RialtoSendMessage { lane, payload, fee } => { + let payload = cli::MillauToRialtoMessagePayload::Raw { data: payload }.into_payload()?; + let lane = lane.into(); + millau_runtime::Call::BridgeRialtoMessageLane(millau_runtime::MessageLaneCall::send_message( + lane, payload, fee, + )) + } + }; + + log::info!(target: "bridge", "Generated Millau call: {:#?}", call); + log::info!(target: "bridge", "Weight of Millau call: {}", call.get_dispatch_info().weight); + log::info!(target: "bridge", "Encoded Millau call: {:?}", HexBytes::encode(&call)); + + Ok(call) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use bp_message_lane::source_chain::TargetHeaderChain; + use sp_core::Pair; + use sp_runtime::traits::{IdentifyAccount, Verify}; + + #[test] + fn millau_signature_is_valid_on_rialto() { + let millau_sign = relay_millau_client::SigningParams::from_suri("//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_account_id: bp_millau::AccountId = millau_public.into_account(); + + let digest = millau_runtime::rialto_account_ownership_digest( + &call, + millau_account_id, + rialto_runtime::VERSION.spec_version, + ); + + let rialto_signer = relay_rialto_client::SigningParams::from_suri("//Dave", None).unwrap(); + let signature = rialto_signer.signer.sign(&digest); + + assert!(signature.verify(&digest[..], &rialto_signer.signer.public())); + } + + #[test] + fn rialto_signature_is_valid_on_millau() { + let rialto_sign = relay_rialto_client::SigningParams::from_suri("//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_account_id: bp_rialto::AccountId = rialto_public.into_account(); + + let digest = rialto_runtime::millau_account_ownership_digest( + &call, + rialto_account_id, + millau_runtime::VERSION.spec_version, + ); + + let millau_signer = relay_millau_client::SigningParams::from_suri("//Dave", None).unwrap(); + let signature = millau_signer.signer.sign(&digest); + + assert!(signature.verify(&digest[..], &millau_signer.signer.public())); + } + + #[test] + fn maximal_rialto_to_millau_message_arguments_size_is_computed_correctly() { + use rialto_runtime::millau_messages::Millau; + + let maximal_remark_size = + compute_maximal_message_arguments_size(bp_rialto::max_extrinsic_size(), bp_millau::max_extrinsic_size()); + + let call: millau_runtime::Call = millau_runtime::SystemCall::remark(vec![42; maximal_remark_size as _]).into(); + let payload = message_payload( + Default::default(), + call.get_dispatch_info().weight, + pallet_bridge_call_dispatch::CallOrigin::SourceRoot, + &call, + ); + assert_eq!(Millau::verify_message(&payload), Ok(())); + + let call: millau_runtime::Call = + millau_runtime::SystemCall::remark(vec![42; (maximal_remark_size + 1) as _]).into(); + let payload = message_payload( + Default::default(), + call.get_dispatch_info().weight, + pallet_bridge_call_dispatch::CallOrigin::SourceRoot, + &call, + ); + assert!(Millau::verify_message(&payload).is_err()); + } + + #[test] + fn maximal_size_remark_to_rialto_is_generated_correctly() { + assert!( + bridge_runtime_common::messages::target::maximal_incoming_message_size( + bp_rialto::max_extrinsic_size() + ) > bp_millau::max_extrinsic_size(), + "We can't actually send maximal messages to Rialto from Millau, because Millau extrinsics can't be that large", + ) + } + + #[test] + fn maximal_rialto_to_millau_message_dispatch_weight_is_computed_correctly() { + use rialto_runtime::millau_messages::Millau; + + let maximal_dispatch_weight = compute_maximal_message_dispatch_weight(bp_millau::max_extrinsic_weight()); + let call: millau_runtime::Call = rialto_runtime::SystemCall::remark(vec![]).into(); + + let payload = message_payload( + Default::default(), + maximal_dispatch_weight, + pallet_bridge_call_dispatch::CallOrigin::SourceRoot, + &call, + ); + assert_eq!(Millau::verify_message(&payload), Ok(())); + + let payload = message_payload( + Default::default(), + maximal_dispatch_weight + 1, + pallet_bridge_call_dispatch::CallOrigin::SourceRoot, + &call, + ); + assert!(Millau::verify_message(&payload).is_err()); + } + + #[test] + fn maximal_weight_fill_block_to_rialto_is_generated_correctly() { + use millau_runtime::rialto_messages::Rialto; + + let maximal_dispatch_weight = compute_maximal_message_dispatch_weight(bp_rialto::max_extrinsic_weight()); + let call: rialto_runtime::Call = millau_runtime::SystemCall::remark(vec![]).into(); + + let payload = message_payload( + Default::default(), + maximal_dispatch_weight, + pallet_bridge_call_dispatch::CallOrigin::SourceRoot, + &call, + ); + assert_eq!(Rialto::verify_message(&payload), Ok(())); + + let payload = message_payload( + Default::default(), + maximal_dispatch_weight + 1, + pallet_bridge_call_dispatch::CallOrigin::SourceRoot, + &call, + ); + assert!(Rialto::verify_message(&payload).is_err()); + } + + #[test] + fn rialto_tx_extra_bytes_constant_is_correct() { + let rialto_call = rialto_runtime::Call::System(rialto_runtime::SystemCall::remark(vec![])); + let rialto_tx = Rialto::sign_transaction( + Default::default(), + &sp_keyring::AccountKeyring::Alice.pair(), + 0, + rialto_call.clone(), + ); + let extra_bytes_in_transaction = rialto_tx.encode().len() - rialto_call.encode().len(); + assert!( + bp_rialto::TX_EXTRA_BYTES as usize >= extra_bytes_in_transaction, + "Hardcoded number of extra bytes in Rialto transaction {} is lower than actual value: {}", + bp_rialto::TX_EXTRA_BYTES, + extra_bytes_in_transaction, + ); + } + + #[test] + fn millau_tx_extra_bytes_constant_is_correct() { + let millau_call = millau_runtime::Call::System(millau_runtime::SystemCall::remark(vec![])); + let millau_tx = Millau::sign_transaction( + Default::default(), + &sp_keyring::AccountKeyring::Alice.pair(), + 0, + millau_call.clone(), + ); + let extra_bytes_in_transaction = millau_tx.encode().len() - millau_call.encode().len(); + assert!( + bp_millau::TX_EXTRA_BYTES as usize >= extra_bytes_in_transaction, + "Hardcoded number of extra bytes in Millau transaction {} is lower than actual value: {}", + bp_millau::TX_EXTRA_BYTES, + extra_bytes_in_transaction, + ); + } +} diff --git a/bridges/relays/substrate/src/rialto_headers_to_millau.rs b/bridges/relays/substrate/src/rialto_millau/rialto_headers_to_millau.rs similarity index 95% rename from bridges/relays/substrate/src/rialto_headers_to_millau.rs rename to bridges/relays/substrate/src/rialto_millau/rialto_headers_to_millau.rs index 5a9bbb12133a2..7e9b855afd183 100644 --- a/bridges/relays/substrate/src/rialto_headers_to_millau.rs +++ b/bridges/relays/substrate/src/rialto_millau/rialto_headers_to_millau.rs @@ -16,10 +16,8 @@ //! Rialto-to-Millau headers sync entrypoint. -use crate::{ - finality_pipeline::{SubstrateFinalitySyncPipeline, SubstrateFinalityToSubstrate}, - MillauClient, RialtoClient, -}; +use super::{MillauClient, RialtoClient}; +use crate::finality_pipeline::{SubstrateFinalitySyncPipeline, SubstrateFinalityToSubstrate}; use async_trait::async_trait; use relay_millau_client::{Millau, SigningParams as MillauSigningParams}; diff --git a/bridges/relays/substrate/src/rialto_messages_to_millau.rs b/bridges/relays/substrate/src/rialto_millau/rialto_messages_to_millau.rs similarity index 99% rename from bridges/relays/substrate/src/rialto_messages_to_millau.rs rename to bridges/relays/substrate/src/rialto_millau/rialto_messages_to_millau.rs index 96211bd944f64..3083ce3cbf5d4 100644 --- a/bridges/relays/substrate/src/rialto_messages_to_millau.rs +++ b/bridges/relays/substrate/src/rialto_millau/rialto_messages_to_millau.rs @@ -16,10 +16,10 @@ //! Rialto-to-Millau messages sync entrypoint. +use super::{MillauClient, RialtoClient}; use crate::messages_lane::{select_delivery_transaction_limits, SubstrateMessageLane, SubstrateMessageLaneToSubstrate}; use crate::messages_source::SubstrateMessagesSource; use crate::messages_target::SubstrateMessagesTarget; -use crate::{MillauClient, RialtoClient}; use async_trait::async_trait; use bp_message_lane::{LaneId, MessageNonce};