From 3feabe7cd669a53e8a95a3bee8673ea804e6c521 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Tue, 13 Apr 2021 12:37:08 +0200 Subject: [PATCH] CLI: Send Message (#886) * Send Message WiP * It compiles. * Add tests. * Use common macro. * Nicer balance display. * Get rid of redundant send_message_call function. * Fix clippy. Co-authored-by: Svyatoslav Nikolsky --- bridges/relays/bin-substrate/Cargo.toml | 2 + .../relays/bin-substrate/src/cli/bridge.rs | 18 ++ .../bin-substrate/src/cli/init_bridge.rs | 6 +- bridges/relays/bin-substrate/src/cli/mod.rs | 41 +-- .../bin-substrate/src/cli/relay_headers.rs | 8 +- .../bin-substrate/src/cli/relay_messages.rs | 8 +- .../bin-substrate/src/cli/send_message.rs | 274 +++++++++++++++++ .../bin-substrate/src/rialto_millau/cli.rs | 70 +---- .../bin-substrate/src/rialto_millau/mod.rs | 277 +----------------- 9 files changed, 336 insertions(+), 368 deletions(-) create mode 100644 bridges/relays/bin-substrate/src/cli/send_message.rs diff --git a/bridges/relays/bin-substrate/Cargo.toml b/bridges/relays/bin-substrate/Cargo.toml index 8942bf8130953..1a281a6d5861a 100644 --- a/bridges/relays/bin-substrate/Cargo.toml +++ b/bridges/relays/bin-substrate/Cargo.toml @@ -13,6 +13,7 @@ codec = { package = "parity-scale-codec", version = "2.0.0" } futures = "0.3.12" hex = "0.4" log = "0.4.14" +num-format = "0.4" num-traits = "0.2" paste = "1.0" structopt = "0.3" @@ -56,3 +57,4 @@ sp-version = { git = "https://github.com/paritytech/substrate", branch = "master [dev-dependencies] sp-keyring = { git = "https://github.com/paritytech/substrate", branch = "master" } +hex-literal = "0.3" diff --git a/bridges/relays/bin-substrate/src/cli/bridge.rs b/bridges/relays/bin-substrate/src/cli/bridge.rs index a962aa674c7a6..2184903e013e7 100644 --- a/bridges/relays/bin-substrate/src/cli/bridge.rs +++ b/bridges/relays/bin-substrate/src/cli/bridge.rs @@ -51,12 +51,21 @@ macro_rules! select_full_bridge { #[allow(dead_code)] type Target = relay_rialto_client::Rialto; + // Derive-account #[allow(unused_imports)] use bp_millau::derive_account_from_rialto_id as derive_account; + // Relay-messages #[allow(unused_imports)] use crate::rialto_millau::millau_messages_to_rialto::run as relay_messages; + // Send-message + #[allow(unused_imports)] + use bp_millau::TO_MILLAU_ESTIMATE_MESSAGE_FEE_METHOD as ESTIMATE_MESSAGE_FEE_METHOD; + // Send-message + #[allow(unused_imports)] + use millau_runtime::rialto_account_ownership_digest as account_ownership_digest; + $generic } FullBridge::RialtoToMillau => { @@ -64,12 +73,21 @@ macro_rules! select_full_bridge { #[allow(dead_code)] type Target = relay_millau_client::Millau; + // Derive-account #[allow(unused_imports)] use bp_rialto::derive_account_from_millau_id as derive_account; + // Relay-messages #[allow(unused_imports)] use crate::rialto_millau::rialto_messages_to_millau::run as relay_messages; + // Send-message + #[allow(unused_imports)] + use bp_rialto::TO_RIALTO_ESTIMATE_MESSAGE_FEE_METHOD as ESTIMATE_MESSAGE_FEE_METHOD; + // Send-message + #[allow(unused_imports)] + use rialto_runtime::millau_account_ownership_digest as account_ownership_digest; + $generic } } diff --git a/bridges/relays/bin-substrate/src/cli/init_bridge.rs b/bridges/relays/bin-substrate/src/cli/init_bridge.rs index 4a073cfa1ddc5..a9923e71e9216 100644 --- a/bridges/relays/bin-substrate/src/cli/init_bridge.rs +++ b/bridges/relays/bin-substrate/src/cli/init_bridge.rs @@ -108,9 +108,9 @@ impl InitBridge { /// Run the command. pub async fn run(self) -> anyhow::Result<()> { select_bridge!(self.bridge, { - let source_client = self.source.into_client::().await?; - let target_client = self.target.into_client::().await?; - let target_sign = self.target_sign.into_keypair::()?; + let source_client = self.source.to_client::().await?; + let target_client = self.target.to_client::().await?; + let target_sign = self.target_sign.to_keypair::()?; crate::headers_initialize::initialize( source_client, diff --git a/bridges/relays/bin-substrate/src/cli/mod.rs b/bridges/relays/bin-substrate/src/cli/mod.rs index e291f7247020a..960e85ea92ae9 100644 --- a/bridges/relays/bin-substrate/src/cli/mod.rs +++ b/bridges/relays/bin-substrate/src/cli/mod.rs @@ -33,6 +33,7 @@ mod derive_account; mod init_bridge; mod relay_headers; mod relay_messages; +mod send_message; /// Parse relay CLI args. pub fn parse_args() -> Command { @@ -62,7 +63,7 @@ pub enum Command { /// Allows interacting with the bridge by sending messages over `Messages` component. /// The message is being sent to the source chain, delivered to the target chain and dispatched /// there. - SendMessage(SendMessage), + SendMessage(send_message::SendMessage), /// Generate SCALE-encoded `Call` for choosen network. /// /// The call can be used either as message payload or can be wrapped into a transaction @@ -96,23 +97,6 @@ impl Command { } } -/// Send bridge message. -#[derive(StructOpt)] -pub enum SendMessage { - #[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(()) - } -} - /// Estimate Delivery & Dispatch Fee command. #[derive(StructOpt)] pub enum EstimateFee { @@ -143,9 +127,16 @@ arg_enum! { } /// Generic balance type. -#[derive(Debug)] +#[derive(Debug, Clone, Copy)] pub struct Balance(pub u128); +impl std::fmt::Display for Balance { + fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result { + use num_format::{Locale, ToFormattedString}; + write!(fmt, "{}", self.0.to_formatted_string(&Locale::en)) + } +} + impl std::str::FromStr for Balance { type Err = ::Err; @@ -251,7 +242,7 @@ pub trait CliChain: relay_substrate_client::Chain { } /// Lane id. -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct HexLaneId(pub LaneId); impl From for LaneId { @@ -330,7 +321,7 @@ impl From for relay_utils::metrics::MetricsParams { } /// Either explicit or maximal allowed value. -#[derive(Debug)] +#[derive(Debug, Clone)] pub enum ExplicitOrMaximal { /// User has explicitly specified argument value. Explicit(V), @@ -388,7 +379,7 @@ macro_rules! declare_chain_options { impl [<$chain SigningParams>] { /// Parse signing params into chain-specific KeyPair. - pub fn into_keypair(self) -> anyhow::Result { + pub fn to_keypair(&self) -> anyhow::Result { use sp_core::crypto::Pair; Chain::KeyPair::from_string( &self.[<$chain_prefix _signer>], @@ -399,11 +390,11 @@ macro_rules! declare_chain_options { impl [<$chain ConnectionParams>] { /// Convert connection params into Substrate client. - pub async fn into_client( - self, + pub async fn to_client( + &self, ) -> anyhow::Result> { Ok(relay_substrate_client::Client::new(relay_substrate_client::ConnectionParams { - host: self.[<$chain_prefix _host>], + host: self.[<$chain_prefix _host>].clone(), port: self.[<$chain_prefix _port>], secure: self.[<$chain_prefix _secure>], }) diff --git a/bridges/relays/bin-substrate/src/cli/relay_headers.rs b/bridges/relays/bin-substrate/src/cli/relay_headers.rs index 44b9b70d2b993..a60bbe344d6eb 100644 --- a/bridges/relays/bin-substrate/src/cli/relay_headers.rs +++ b/bridges/relays/bin-substrate/src/cli/relay_headers.rs @@ -59,12 +59,14 @@ macro_rules! select_bridge { type Source = relay_rialto_client::Rialto; type Target = relay_millau_client::Millau; type Finality = crate::rialto_millau::rialto_headers_to_millau::RialtoFinalityToMillau; + $generic } RelayHeadersBridge::WestendToMillau => { type Source = relay_westend_client::Westend; type Target = relay_millau_client::Millau; type Finality = crate::rialto_millau::westend_headers_to_millau::WestendFinalityToMillau; + $generic } } @@ -75,9 +77,9 @@ impl RelayHeaders { /// Run the command. pub async fn run(self) -> anyhow::Result<()> { select_bridge!(self.bridge, { - let source_client = self.source.into_client::().await?; - let target_client = self.target.into_client::().await?; - let target_sign = self.target_sign.into_keypair::()?; + let source_client = self.source.to_client::().await?; + let target_client = self.target.to_client::().await?; + let target_sign = self.target_sign.to_keypair::()?; let metrics_params = Finality::customize_metrics(self.prometheus_params.into())?; crate::finality_pipeline::run( diff --git a/bridges/relays/bin-substrate/src/cli/relay_messages.rs b/bridges/relays/bin-substrate/src/cli/relay_messages.rs index feedea66ef6ab..0e863f25c7a6c 100644 --- a/bridges/relays/bin-substrate/src/cli/relay_messages.rs +++ b/bridges/relays/bin-substrate/src/cli/relay_messages.rs @@ -47,10 +47,10 @@ impl RelayMessages { /// Run the command. pub async fn run(self) -> anyhow::Result<()> { select_full_bridge!(self.bridge, { - let source_client = self.source.into_client::().await?; - let source_sign = self.source_sign.into_keypair::()?; - let target_client = self.target.into_client::().await?; - let target_sign = self.target_sign.into_keypair::()?; + let source_client = self.source.to_client::().await?; + let source_sign = self.source_sign.to_keypair::()?; + let target_client = self.target.to_client::().await?; + let target_sign = self.target_sign.to_keypair::()?; relay_messages( source_client, diff --git a/bridges/relays/bin-substrate/src/cli/send_message.rs b/bridges/relays/bin-substrate/src/cli/send_message.rs new file mode 100644 index 0000000000000..e6ab7dcfa7f02 --- /dev/null +++ b/bridges/relays/bin-substrate/src/cli/send_message.rs @@ -0,0 +1,274 @@ +// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// This file is part of Parity Bridges Common. + +// Parity Bridges Common is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity Bridges Common is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity Bridges Common. If not, see . + +use crate::cli::bridge::FullBridge; +use crate::cli::encode_call::{self, CliEncodeCall}; +use crate::cli::{ + Balance, CliChain, ExplicitOrMaximal, HexBytes, HexLaneId, Origins, SourceConnectionParams, SourceSigningParams, + TargetSigningParams, +}; +use codec::Encode; +use frame_support::{dispatch::GetDispatchInfo, weights::Weight}; +use pallet_bridge_dispatch::{CallOrigin, MessagePayload}; +use relay_substrate_client::{Chain, TransactionSignScheme}; +use sp_core::{Bytes, Pair}; +use sp_runtime::{traits::IdentifyAccount, AccountId32, MultiSignature, MultiSigner}; +use structopt::StructOpt; + +/// Send bridge message. +#[derive(StructOpt)] +pub struct SendMessage { + /// A bridge instance to encode call for. + #[structopt(possible_values = &FullBridge::variants(), case_insensitive = true)] + bridge: FullBridge, + #[structopt(flatten)] + source: SourceConnectionParams, + #[structopt(flatten)] + source_sign: SourceSigningParams, + // TODO [#885] Move TargetSign to origins + #[structopt(flatten)] + target_sign: TargetSigningParams, + /// 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: crate::cli::encode_call::Call, + /// The origin to use when dispatching the message on the target chain. Defaults to + /// `SourceAccount`. + #[structopt(long, possible_values = &Origins::variants(), default_value = "Source")] + origin: Origins, +} + +impl SendMessage { + pub fn encode_payload( + &mut self, + ) -> anyhow::Result>> { + crate::select_full_bridge!(self.bridge, { + let SendMessage { + source_sign, + target_sign, + ref mut message, + dispatch_weight, + origin, + bridge, + .. + } = self; + + let source_sign = source_sign.to_keypair::()?; + let target_sign = target_sign.to_keypair::()?; + + encode_call::preprocess_call::(message, bridge.bridge_instance_index()); + let target_call = Target::encode_call(&message)?; + + let payload = { + let target_call_weight = prepare_call_dispatch_weight( + dispatch_weight, + ExplicitOrMaximal::Explicit(target_call.get_dispatch_info().weight), + crate::rialto_millau::compute_maximal_message_dispatch_weight(Target::max_extrinsic_weight()), + ); + let source_sender_public: MultiSigner = source_sign.public().into(); + let source_account_id = source_sender_public.into_account(); + + crate::rialto_millau::message_payload( + Target::RUNTIME_VERSION.spec_version, + target_call_weight, + match origin { + Origins::Source => CallOrigin::SourceAccount(source_account_id), + Origins::Target => { + let digest = account_ownership_digest( + &target_call, + source_account_id.clone(), + Target::RUNTIME_VERSION.spec_version, + ); + let target_origin_public = target_sign.public(); + let digest_signature = target_sign.sign(&digest); + CallOrigin::TargetAccount( + source_account_id, + target_origin_public.into(), + digest_signature.into(), + ) + } + }, + &target_call, + ) + }; + Ok(payload) + }) + } + + /// Run the command. + pub async fn run(mut self) -> anyhow::Result<()> { + crate::select_full_bridge!(self.bridge, { + let payload = self.encode_payload()?; + + let source_client = self.source.to_client::().await?; + let source_sign = self.source_sign.to_keypair::()?; + + let lane = self.lane.clone().into(); + let fee = match self.fee { + Some(fee) => fee, + None => crate::rialto_millau::estimate_message_delivery_and_dispatch_fee::< + ::NativeBalance, + _, + _, + >(&source_client, ESTIMATE_MESSAGE_FEE_METHOD, lane, payload.clone()) + .await? + .map(|v| Balance(v as _)) + .ok_or_else(|| anyhow::format_err!("Failed to estimate message fee. Message is too heavy?"))?, + }; + let dispatch_weight = payload.weight; + let send_message_call = Source::encode_call(&encode_call::Call::BridgeSendMessage { + bridge_instance_index: self.bridge.bridge_instance_index(), + lane: self.lane, + payload: HexBytes::encode(&payload), + fee, + })?; + + source_client + .submit_signed_extrinsic(source_sign.public().into(), |transaction_nonce| { + let signed_source_call = Source::sign_transaction( + *source_client.genesis_hash(), + &source_sign, + transaction_nonce, + send_message_call, + ) + .encode(); + + log::info!( + target: "bridge", + "Sending message to {}. Size: {}. Dispatch weight: {}. Fee: {}", + Target::NAME, + signed_source_call.len(), + dispatch_weight, + fee, + ); + log::info!( + target: "bridge", + "Signed {} Call: {:?}", + Source::NAME, + HexBytes::encode(&signed_source_call) + ); + + Bytes(signed_source_call) + }) + .await?; + }); + + Ok(()) + } +} + +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 + .clone() + .unwrap_or(weight_from_pre_dispatch_call) + { + ExplicitOrMaximal::Explicit(weight) => weight, + ExplicitOrMaximal::Maximal => maximal_allowed_weight, + } +} + +#[cfg(test)] +mod tests { + use super::*; + use hex_literal::hex; + + #[test] + fn send_remark_rialto_to_millau() { + // given + let mut send_message = SendMessage::from_iter(vec![ + "send-message", + "RialtoToMillau", + "--source-port", + "1234", + "--source-signer", + "//Alice", + "--target-signer", + "//Bob", + "remark", + "--remark-payload", + "1234", + ]); + + // when + let payload = send_message.encode_payload().unwrap(); + + // then + assert_eq!( + payload, + MessagePayload { + spec_version: relay_millau_client::Millau::RUNTIME_VERSION.spec_version, + weight: 1345000, + origin: CallOrigin::SourceAccount(sp_keyring::AccountKeyring::Alice.to_account_id()), + call: hex!("0401081234").to_vec(), + } + ); + } + + #[test] + fn send_remark_millau_to_rialto() { + // given + let mut send_message = SendMessage::from_iter(vec![ + "send-message", + "MillauToRialto", + "--source-port", + "1234", + "--source-signer", + "//Alice", + "--origin", + "Target", + "--target-signer", + "//Bob", + "remark", + "--remark-payload", + "1234", + ]); + + // when + let payload = send_message.encode_payload().unwrap(); + + // then + // Since signatures are randomized we extract it from here and only check the rest. + let signature = match payload.origin { + CallOrigin::TargetAccount(_, _, ref sig) => sig.clone(), + _ => panic!("Unexpected `CallOrigin`: {:?}", payload), + }; + assert_eq!( + payload, + MessagePayload { + spec_version: relay_millau_client::Millau::RUNTIME_VERSION.spec_version, + weight: 1345000, + origin: CallOrigin::TargetAccount( + sp_keyring::AccountKeyring::Alice.to_account_id(), + sp_keyring::AccountKeyring::Bob.into(), + signature, + ), + call: hex!("0701081234").to_vec(), + } + ); + } +} diff --git a/bridges/relays/bin-substrate/src/rialto_millau/cli.rs b/bridges/relays/bin-substrate/src/rialto_millau/cli.rs index 4c92ec1773841..841f5427baf4d 100644 --- a/bridges/relays/bin-substrate/src/rialto_millau/cli.rs +++ b/bridges/relays/bin-substrate/src/rialto_millau/cli.rs @@ -16,77 +16,9 @@ //! Deal with CLI args of Rialto <> Millau relay. -use frame_support::weights::Weight; use structopt::StructOpt; -use crate::cli::{ - Balance, ExplicitOrMaximal, HexLaneId, Origins, SourceConnectionParams, SourceSigningParams, TargetSigningParams, -}; - -/// Send bridge message. -/// -/// TODO [#855] Move to separate module. -#[derive(StructOpt)] -pub enum SendMessage { - /// Submit message to given Millau -> Rialto lane. - MillauToRialto { - #[structopt(flatten)] - source: SourceConnectionParams, - #[structopt(flatten)] - source_sign: SourceSigningParams, - #[structopt(flatten)] - target_sign: TargetSigningParams, - /// 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: crate::cli::encode_call::Call, - /// The origin to use when dispatching the message on the target chain. Defaults to - /// `SourceAccount`. - #[structopt(long, possible_values = &Origins::variants(), default_value = "Source")] - origin: Origins, - }, - /// Submit message to given Rialto -> Millau lane. - RialtoToMillau { - #[structopt(flatten)] - source: SourceConnectionParams, - #[structopt(flatten)] - source_sign: SourceSigningParams, - #[structopt(flatten)] - target_sign: TargetSigningParams, - /// 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: crate::cli::encode_call::Call, - /// The origin to use when dispatching the message on the target chain. Defaults to - /// `SourceAccount`. - #[structopt(long, possible_values = &Origins::variants(), default_value = "Source")] - 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(()) - } -} +use crate::cli::{HexLaneId, SourceConnectionParams}; /// Estimate Delivery & Dispatch Fee command. /// diff --git a/bridges/relays/bin-substrate/src/rialto_millau/mod.rs b/bridges/relays/bin-substrate/src/rialto_millau/mod.rs index d6e49ccf2cc2e..6b61653ae3170 100644 --- a/bridges/relays/bin-substrate/src/rialto_millau/mod.rs +++ b/bridges/relays/bin-substrate/src/rialto_millau/mod.rs @@ -29,244 +29,20 @@ pub type MillauClient = relay_substrate_client::Client; pub type RialtoClient = relay_substrate_client::Client; use crate::cli::{ - bridge::{MILLAU_TO_RIALTO_INDEX, RIALTO_TO_MILLAU_INDEX}, + bridge, encode_call::{self, Call, CliEncodeCall}, - encode_message, CliChain, ExplicitOrMaximal, HexBytes, Origins, + encode_message, CliChain, HexBytes, }; use codec::{Decode, Encode}; use frame_support::weights::{GetDispatchInfo, Weight}; use pallet_bridge_dispatch::{CallOrigin, MessagePayload}; use relay_millau_client::Millau; use relay_rialto_client::Rialto; -use relay_substrate_client::{Chain, TransactionSignScheme}; +use relay_substrate_client::Chain; use relay_westend_client::Westend; -use sp_core::{Bytes, Pair}; -use sp_runtime::{traits::IdentifyAccount, MultiSigner}; use sp_version::RuntimeVersion; use std::fmt::Debug; -async fn run_send_message(command: cli::SendMessage) -> Result<(), String> { - match command { - cli::SendMessage::MillauToRialto { - source, - source_sign, - target_sign, - lane, - mut message, - dispatch_weight, - fee, - origin, - .. - } => { - type Source = Millau; - type Target = Rialto; - - let account_ownership_digest = |target_call, source_account_id| { - millau_runtime::rialto_account_ownership_digest( - &target_call, - source_account_id, - Target::RUNTIME_VERSION.spec_version, - ) - }; - let estimate_message_fee_method = bp_rialto::TO_RIALTO_ESTIMATE_MESSAGE_FEE_METHOD; - let fee = fee.map(|x| x.cast()); - let send_message_call = |lane, payload, fee| { - millau_runtime::Call::BridgeRialtoMessages(millau_runtime::MessagesCall::send_message( - lane, payload, fee, - )) - }; - - let source_client = source.into_client::().await.map_err(format_err)?; - let source_sign = source_sign.into_keypair::().map_err(format_err)?; - let target_sign = target_sign.into_keypair::().map_err(format_err)?; - - encode_call::preprocess_call::(&mut message, MILLAU_TO_RIALTO_INDEX); - let target_call = Target::encode_call(&message).map_err(|e| e.to_string())?; - - let payload = { - let target_call_weight = prepare_call_dispatch_weight( - dispatch_weight, - ExplicitOrMaximal::Explicit(target_call.get_dispatch_info().weight), - compute_maximal_message_dispatch_weight(Target::max_extrinsic_weight()), - ); - let source_sender_public: MultiSigner = source_sign.public().into(); - let source_account_id = source_sender_public.into_account(); - - message_payload( - Target::RUNTIME_VERSION.spec_version, - target_call_weight, - match origin { - Origins::Source => CallOrigin::SourceAccount(source_account_id), - Origins::Target => { - let digest = account_ownership_digest(&target_call, source_account_id.clone()); - let target_origin_public = target_sign.public(); - let digest_signature = target_sign.sign(&digest); - CallOrigin::TargetAccount( - source_account_id, - target_origin_public.into(), - digest_signature.into(), - ) - } - }, - &target_call, - ) - }; - let dispatch_weight = payload.weight; - - let lane = lane.into(); - let fee = get_fee(fee, || { - estimate_message_delivery_and_dispatch_fee( - &source_client, - estimate_message_fee_method, - lane, - payload.clone(), - ) - }) - .await?; - - source_client - .submit_signed_extrinsic(source_sign.public().into(), |transaction_nonce| { - let send_message_call = send_message_call(lane, payload, fee); - - let signed_source_call = Source::sign_transaction( - *source_client.genesis_hash(), - &source_sign, - transaction_nonce, - send_message_call, - ) - .encode(); - - log::info!( - target: "bridge", - "Sending message to {}. Size: {}. Dispatch weight: {}. Fee: {}", - Target::NAME, - signed_source_call.len(), - dispatch_weight, - fee, - ); - log::info!( - target: "bridge", - "Signed {} Call: {:?}", - Source::NAME, - HexBytes::encode(&signed_source_call) - ); - - Bytes(signed_source_call) - }) - .await?; - } - cli::SendMessage::RialtoToMillau { - source, - source_sign, - target_sign, - lane, - mut message, - dispatch_weight, - fee, - origin, - .. - } => { - type Source = Rialto; - type Target = Millau; - - let account_ownership_digest = |target_call, source_account_id| { - rialto_runtime::millau_account_ownership_digest( - &target_call, - source_account_id, - Target::RUNTIME_VERSION.spec_version, - ) - }; - let estimate_message_fee_method = bp_millau::TO_MILLAU_ESTIMATE_MESSAGE_FEE_METHOD; - let fee = fee.map(|x| x.0); - let send_message_call = |lane, payload, fee| { - rialto_runtime::Call::BridgeMillauMessages(rialto_runtime::MessagesCall::send_message( - lane, payload, fee, - )) - }; - - let source_client = source.into_client::().await.map_err(format_err)?; - let source_sign = source_sign.into_keypair::().map_err(format_err)?; - let target_sign = target_sign.into_keypair::().map_err(format_err)?; - - encode_call::preprocess_call::(&mut message, RIALTO_TO_MILLAU_INDEX); - let target_call = Target::encode_call(&message).map_err(|e| e.to_string())?; - - let payload = { - let target_call_weight = prepare_call_dispatch_weight( - dispatch_weight, - ExplicitOrMaximal::Explicit(target_call.get_dispatch_info().weight), - compute_maximal_message_dispatch_weight(Target::max_extrinsic_weight()), - ); - let source_sender_public: MultiSigner = source_sign.public().into(); - let source_account_id = source_sender_public.into_account(); - - message_payload( - Target::RUNTIME_VERSION.spec_version, - target_call_weight, - match origin { - Origins::Source => CallOrigin::SourceAccount(source_account_id), - Origins::Target => { - let digest = account_ownership_digest(&target_call, source_account_id.clone()); - let target_origin_public = target_sign.public(); - let digest_signature = target_sign.sign(&digest); - CallOrigin::TargetAccount( - source_account_id, - target_origin_public.into(), - digest_signature.into(), - ) - } - }, - &target_call, - ) - }; - let dispatch_weight = payload.weight; - - let lane = lane.into(); - let fee = get_fee(fee, || { - estimate_message_delivery_and_dispatch_fee( - &source_client, - estimate_message_fee_method, - lane, - payload.clone(), - ) - }) - .await?; - - source_client - .submit_signed_extrinsic(source_sign.public().into(), |transaction_nonce| { - let send_message_call = send_message_call(lane, payload, fee); - - let signed_source_call = Source::sign_transaction( - *source_client.genesis_hash(), - &source_sign, - transaction_nonce, - send_message_call, - ) - .encode(); - - log::info!( - target: "bridge", - "Sending message to {}. Size: {}. Dispatch weight: {}. Fee: {}", - Target::NAME, - signed_source_call.len(), - dispatch_weight, - fee, - ); - log::info!( - target: "bridge", - "Signed {} Call: {:?}", - Source::NAME, - HexBytes::encode(&signed_source_call) - ); - - Bytes(signed_source_call) - }) - .await?; - } - } - Ok(()) -} - async fn run_estimate_fee(cmd: cli::EstimateFee) -> Result<(), String> { match cmd { cli::EstimateFee::RialtoToMillau { source, lane, payload } => { @@ -275,7 +51,7 @@ async fn run_estimate_fee(cmd: cli::EstimateFee) -> Result<(), String> { let estimate_message_fee_method = bp_millau::TO_MILLAU_ESTIMATE_MESSAGE_FEE_METHOD; - let source_client = source.into_client::().await.map_err(format_err)?; + let source_client = source.to_client::().await.map_err(format_err)?; let lane = lane.into(); let payload = Source::encode_message(payload)?; @@ -291,7 +67,7 @@ async fn run_estimate_fee(cmd: cli::EstimateFee) -> Result<(), String> { let estimate_message_fee_method = bp_rialto::TO_RIALTO_ESTIMATE_MESSAGE_FEE_METHOD; - let source_client = source.into_client::().await.map_err(format_err)?; + let source_client = source.to_client::().await.map_err(format_err)?; let lane = lane.into(); let payload = Source::encode_message(payload)?; @@ -306,7 +82,7 @@ async fn run_estimate_fee(cmd: cli::EstimateFee) -> Result<(), String> { Ok(()) } -async fn estimate_message_delivery_and_dispatch_fee( +pub(crate) async fn estimate_message_delivery_and_dispatch_fee( client: &relay_substrate_client::Client, estimate_fee_method: &str, lane: bp_messages::LaneId, @@ -320,7 +96,7 @@ async fn estimate_message_delivery_and_dispatch_fee( +pub(crate) fn message_payload( spec_version: u32, weight: Weight, origin: CallOrigin, @@ -357,35 +133,7 @@ where } } -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 { +pub(crate) fn compute_maximal_message_dispatch_weight(maximal_extrinsic_weight: Weight) -> Weight { bridge_runtime_common::messages::target::maximal_incoming_message_dispatch_weight(maximal_extrinsic_weight) } @@ -409,7 +157,7 @@ impl CliEncodeCall for Millau { fee, bridge_instance_index, } => match *bridge_instance_index { - MILLAU_TO_RIALTO_INDEX => { + bridge::MILLAU_TO_RIALTO_INDEX => { let payload = Decode::decode(&mut &*payload.0)?; millau_runtime::Call::BridgeRialtoMessages(millau_runtime::MessagesCall::send_message( lane.0, @@ -452,7 +200,7 @@ impl CliChain for Millau { sender.enforce_chain::(); let spec_version = Target::RUNTIME_VERSION.spec_version; let origin = CallOrigin::SourceAccount(sender.raw_id()); - encode_call::preprocess_call::(&mut call, MILLAU_TO_RIALTO_INDEX); + encode_call::preprocess_call::(&mut call, bridge::MILLAU_TO_RIALTO_INDEX); let call = Target::encode_call(&call).map_err(|e| e.to_string())?; let weight = call.get_dispatch_info().weight; @@ -482,7 +230,7 @@ impl CliEncodeCall for Rialto { fee, bridge_instance_index, } => match *bridge_instance_index { - RIALTO_TO_MILLAU_INDEX => { + bridge::RIALTO_TO_MILLAU_INDEX => { let payload = Decode::decode(&mut &*payload.0)?; rialto_runtime::Call::BridgeMillauMessages(rialto_runtime::MessagesCall::send_message( lane.0, payload, fee.0, @@ -522,7 +270,7 @@ impl CliChain for Rialto { sender.enforce_chain::(); let spec_version = Target::RUNTIME_VERSION.spec_version; let origin = CallOrigin::SourceAccount(sender.raw_id()); - encode_call::preprocess_call::(&mut call, RIALTO_TO_MILLAU_INDEX); + encode_call::preprocess_call::(&mut call, bridge::RIALTO_TO_MILLAU_INDEX); let call = Target::encode_call(&call).map_err(|e| e.to_string())?; let weight = call.get_dispatch_info().weight; @@ -559,6 +307,7 @@ fn format_err(e: anyhow::Error) -> String { mod tests { use super::*; use bp_messages::source_chain::TargetHeaderChain; + use relay_substrate_client::TransactionSignScheme; use sp_core::Pair; use sp_runtime::traits::{IdentifyAccount, Verify};