diff --git a/bridges/relays/bin-substrate/src/cli/encode_call.rs b/bridges/relays/bin-substrate/src/cli/encode_call.rs new file mode 100644 index 0000000000000..3afe8d43b9429 --- /dev/null +++ b/bridges/relays/bin-substrate/src/cli/encode_call.rs @@ -0,0 +1,249 @@ +// 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::{AccountId, Balance, CliChain, ExplicitOrMaximal, HexBytes, HexLaneId}; +use frame_support::dispatch::GetDispatchInfo; +use relay_substrate_client::Chain; +use structopt::{clap::arg_enum, StructOpt}; + +/// Encode source chain runtime call. +#[derive(StructOpt)] +pub struct EncodeCall { + /// A bridge instance to encode call for. + #[structopt(possible_values = &EncodeCallBridge::variants(), case_insensitive = true)] + bridge: EncodeCallBridge, + #[structopt(flatten)] + call: Call, +} + +/// All possible messages that may be delivered to generic Substrate chain. +/// +/// Note this enum may be used in the context of both Source (as part of `encode-call`) +/// and Target chain (as part of `encode-message/send-message`). +#[derive(StructOpt, Debug)] +pub enum Call { + /// Raw bytes for the message + Raw { + /// Raw, SCALE-encoded message + data: HexBytes, + }, + /// Make an on-chain remark (comment). + Remark { + /// Explicit remark payload. + #[structopt(long, conflicts_with("remark_size"))] + remark_payload: HexBytes, + /// Remark size. If not passed, small UTF8-encoded string is generated by relay as remark. + #[structopt(long, conflicts_with("remark_payload"))] + remark_size: Option>, + }, + /// Transfer the specified `amount` of native tokens to a particular `recipient`. + Transfer { + /// Address of an account to receive the transfer. + #[structopt(long)] + recipient: AccountId, + /// Amount of target tokens to send in target chain base currency units. + #[structopt(long)] + amount: Balance, + }, + /// A call to the specific Bridge Messages pallet to queue message to be sent over a bridge. + BridgeSendMessage { + /// An index of the bridge instance which represents the expected target chain. + #[structopt(skip = 255)] + bridge_instance_index: u8, + /// Hex-encoded lane id that should be served by the relay. Defaults to `00000000`. + #[structopt(long, default_value = "00000000")] + lane: HexLaneId, + /// Raw SCALE-encoded Message Payload to submit to the messages pallet. + /// + /// This can be obtained by encoding call for the target chain. + #[structopt(long)] + payload: HexBytes, + /// Declared delivery and dispatch fee in base source-chain currency units. + #[structopt(long)] + fee: Balance, + }, +} + +pub trait CliEncodeCall: Chain { + /// Maximal size (in bytes) of any extrinsic (from the runtime). + fn max_extrinsic_size() -> u32; + + /// Encode a CLI call. + fn encode_call(call: &Call) -> anyhow::Result; +} + +arg_enum! { + #[derive(Debug)] + /// Bridge to encode call for. + pub enum EncodeCallBridge { + MillauToRialto, + RialtoToMillau, + } +} + +impl EncodeCallBridge { + fn bridge_instance_index(&self) -> u8 { + match self { + Self::MillauToRialto => MILLAU_TO_RIALTO_INDEX, + Self::RialtoToMillau => RIALTO_TO_MILLAU_INDEX, + } + } +} + +pub const RIALTO_TO_MILLAU_INDEX: u8 = 0; +pub const MILLAU_TO_RIALTO_INDEX: u8 = 0; + +macro_rules! select_bridge { + ($bridge: expr, $generic: tt) => { + match $bridge { + EncodeCallBridge::MillauToRialto => { + type Source = relay_millau_client::Millau; + type Target = relay_rialto_client::Rialto; + + $generic + } + EncodeCallBridge::RialtoToMillau => { + type Source = relay_rialto_client::Rialto; + type Target = relay_millau_client::Millau; + + $generic + } + } + }; +} + +impl EncodeCall { + fn encode(&mut self) -> anyhow::Result { + select_bridge!(self.bridge, { + preprocess_call::(&mut self.call, self.bridge.bridge_instance_index()); + let call = Source::encode_call(&self.call)?; + + let encoded = HexBytes::encode(&call); + + log::info!(target: "bridge", "Generated {} call: {:#?}", Source::NAME, call); + log::info!(target: "bridge", "Weight of {} call: {}", Source::NAME, call.get_dispatch_info().weight); + log::info!(target: "bridge", "Encoded {} call: {:?}", Source::NAME, encoded); + + Ok(encoded) + }) + } + + /// Run the command. + pub async fn run(mut self) -> anyhow::Result<()> { + println!("{:?}", self.encode()?); + Ok(()) + } +} + +/// Prepare the call to be passed to [`CliEncodeCall::encode_call`]. +/// +/// This function will fill in all optional and missing pieces and will make sure that +/// values are converted to bridge-specific ones. +/// +/// Most importantly, the method will fill-in [`bridge_instance_index`] parameter for +/// target-chain specific calls. +pub(crate) fn preprocess_call( + call: &mut Call, + bridge_instance: u8, +) { + match *call { + Call::Raw { .. } => {} + Call::Remark { + ref remark_size, + ref mut remark_payload, + } => { + if remark_payload.0.is_empty() { + *remark_payload = HexBytes(generate_remark_payload( + &remark_size, + compute_maximal_message_arguments_size(Source::max_extrinsic_size(), Target::max_extrinsic_size()), + )); + } + } + Call::Transfer { ref mut recipient, .. } => { + recipient.enforce_chain::(); + } + Call::BridgeSendMessage { + ref mut bridge_instance_index, + .. + } => { + *bridge_instance_index = bridge_instance; + } + }; +} + +fn generate_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(), + } +} + +pub(crate) 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 +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn should_encode_transfer_call() { + // given + let mut encode_call = EncodeCall::from_iter(vec![ + "encode-call", + "RialtoToMillau", + "transfer", + "--amount", + "12345", + "--recipient", + "5sauUXUfPjmwxSgmb3tZ5d6yx24eZX4wWJ2JtVUBaQqFbvEU", + ]); + + // when + let hex = encode_call.encode().unwrap(); + + // then + assert_eq!( + format!("{:?}", hex), + "0x0d00d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27de5c0" + ); + } +} diff --git a/bridges/relays/bin-substrate/src/cli/mod.rs b/bridges/relays/bin-substrate/src/cli/mod.rs index f3f7dfefd9fe3..216b778c21832 100644 --- a/bridges/relays/bin-substrate/src/cli/mod.rs +++ b/bridges/relays/bin-substrate/src/cli/mod.rs @@ -25,6 +25,8 @@ use frame_support::weights::Weight; use sp_runtime::app_crypto::Ss58Codec; use structopt::{clap::arg_enum, StructOpt}; +pub(crate) mod encode_call; + mod derive_account; mod init_bridge; mod relay_headers; @@ -63,7 +65,7 @@ pub enum Command { /// /// The call can be used either as message payload or can be wrapped into a transaction /// and executed on the chain directly. - EncodeCall(EncodeCall), + EncodeCall(encode_call::EncodeCall), /// Generate SCALE-encoded `MessagePayload` object that can be sent over selected bridge. /// /// The `MessagePayload` can be then fed to `Messages::send_message` function and sent over @@ -109,23 +111,6 @@ impl SendMessage { } } -/// A call to encode. -#[derive(StructOpt)] -pub enum EncodeCall { - #[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 { @@ -273,9 +258,6 @@ pub trait CliChain: relay_substrate_client::Chain { /// Numeric value of SS58 format. fn ss58_format() -> u16; - /// Parse CLI call and encode it to be dispatched on this specific chain. - fn encode_call(call: crate::rialto_millau::cli::Call) -> Result; - /// Construct message payload to be sent over the bridge. fn encode_message(message: crate::rialto_millau::cli::MessagePayload) -> Result; @@ -304,7 +286,7 @@ impl std::str::FromStr for HexLaneId { } /// Nicer formatting for raw bytes vectors. -#[derive(Encode, Decode)] +#[derive(Default, Encode, Decode)] pub struct HexBytes(pub Vec); impl std::str::FromStr for HexBytes { @@ -317,7 +299,13 @@ impl std::str::FromStr for HexBytes { impl std::fmt::Debug for HexBytes { fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result { - write!(fmt, "0x{}", hex::encode(&self.0)) + write!(fmt, "0x{}", self) + } +} + +impl std::fmt::Display for HexBytes { + fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(fmt, "{}", hex::encode(&self.0)) } } @@ -470,4 +458,17 @@ mod tests { assert_eq!(actual, expected) } + + #[test] + fn hex_bytes_display_matches_from_str_for_clap() { + // given + let hex = HexBytes(vec![1, 2, 3, 4]); + let display = format!("{}", hex); + + // when + let hex2: HexBytes = display.parse().unwrap(); + + // then + assert_eq!(hex.0, hex2.0); + } } diff --git a/bridges/relays/bin-substrate/src/rialto_millau/cli.rs b/bridges/relays/bin-substrate/src/rialto_millau/cli.rs index 2f11156537364..9e5788b1cb69d 100644 --- a/bridges/relays/bin-substrate/src/rialto_millau/cli.rs +++ b/bridges/relays/bin-substrate/src/rialto_millau/cli.rs @@ -48,7 +48,7 @@ pub enum SendMessage { fee: Option, /// Message type. #[structopt(subcommand)] - message: Call, + 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")] @@ -73,7 +73,7 @@ pub enum SendMessage { fee: Option, /// Message type. #[structopt(subcommand)] - message: Call, + 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")] @@ -89,31 +89,6 @@ impl SendMessage { } } -/// A call to encode. -/// -/// TODO [#855] Move to separate module. -#[derive(StructOpt)] -pub enum EncodeCall { - /// Encode Rialto's Call. - Rialto { - #[structopt(flatten)] - call: Call, - }, - /// Encode Millau's Call. - Millau { - #[structopt(flatten)] - call: Call, - }, -} - -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. /// /// TODO [#855] Move to separate module. @@ -192,50 +167,9 @@ pub enum MessagePayload { Call { /// Message details. #[structopt(flatten)] - call: Call, + call: crate::cli::encode_call::Call, /// SS58 encoded account that will send the payload (must have SS58Prefix = 42) #[structopt(long)] sender: AccountId, }, } - -/// All possible messages that may be delivered to generic Substrate chain. -/// -/// Note this enum may be used in the context of both Source (as part of `encode-call`) -/// and Target chain (as part of `encode-message/send-message`). -#[derive(StructOpt, Debug)] -pub enum Call { - /// 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: Balance, - }, - // TODO [#853] Support multiple bridges. - /// A call to the specific Bridge Messages pallet to queue message to be sent over a bridge. - BridgeSendMessage { - /// Hex-encoded lane id that should be served by the relay. Defaults to `00000000`. - #[structopt(long, default_value = "00000000")] - lane: HexLaneId, - /// Raw SCALE-encoded Message Payload to submit to the messages pallet. - #[structopt(long)] - payload: HexBytes, - /// Declared delivery and dispatch fee in base source-chain currency units. - #[structopt(long)] - fee: Balance, - }, -} diff --git a/bridges/relays/bin-substrate/src/rialto_millau/mod.rs b/bridges/relays/bin-substrate/src/rialto_millau/mod.rs index f039aadef54dd..52f1d5201cdec 100644 --- a/bridges/relays/bin-substrate/src/rialto_millau/mod.rs +++ b/bridges/relays/bin-substrate/src/rialto_millau/mod.rs @@ -28,7 +28,10 @@ pub type MillauClient = relay_substrate_client::Client; /// Rialto node client. pub type RialtoClient = relay_substrate_client::Client; -use crate::cli::{CliChain, ExplicitOrMaximal, HexBytes, Origins}; +use crate::cli::{ + encode_call::{self, Call, CliEncodeCall, MILLAU_TO_RIALTO_INDEX, RIALTO_TO_MILLAU_INDEX}, + CliChain, ExplicitOrMaximal, HexBytes, Origins, +}; use codec::{Decode, Encode}; use frame_support::weights::{GetDispatchInfo, Weight}; use pallet_bridge_dispatch::{CallOrigin, MessagePayload}; @@ -48,7 +51,7 @@ async fn run_send_message(command: cli::SendMessage) -> Result<(), String> { source_sign, target_sign, lane, - message, + mut message, dispatch_weight, fee, origin, @@ -75,7 +78,9 @@ async fn run_send_message(command: cli::SendMessage) -> Result<(), String> { 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)?; - let target_call = Target::encode_call(message)?; + + 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( @@ -154,7 +159,7 @@ async fn run_send_message(command: cli::SendMessage) -> Result<(), String> { source_sign, target_sign, lane, - message, + mut message, dispatch_weight, fee, origin, @@ -181,7 +186,9 @@ async fn run_send_message(command: cli::SendMessage) -> Result<(), String> { 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)?; - let target_call = Target::encode_call(message)?; + + 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( @@ -259,24 +266,6 @@ async fn run_send_message(command: cli::SendMessage) -> Result<(), String> { Ok(()) } -async fn run_encode_call(call: cli::EncodeCall) -> Result<(), String> { - match call { - cli::EncodeCall::Rialto { call } => { - type Source = Rialto; - - let call = Source::encode_call(call)?; - println!("{:?}", HexBytes::encode(&call)); - } - cli::EncodeCall::Millau { call } => { - type Source = Millau; - - let call = Source::encode_call(call)?; - println!("{:?}", HexBytes::encode(&call)); - } - } - Ok(()) -} - async fn run_encode_message_payload(call: cli::EncodeMessagePayload) -> Result<(), String> { match call { cli::EncodeMessagePayload::RialtoToMillau { payload } => { @@ -348,22 +337,6 @@ async fn estimate_message_delivery_and_dispatch_fee>, 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, @@ -433,24 +406,41 @@ fn compute_maximal_message_dispatch_weight(maximal_extrinsic_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 - }; +impl CliEncodeCall for Millau { + fn max_extrinsic_size() -> u32 { + bp_millau::max_extrinsic_size() + } - // bytes in Call encoding that are used to encode everything except arguments - let service_bytes = 1 + 1 + 4; - maximal_call_size - service_bytes + fn encode_call(call: &Call) -> anyhow::Result { + Ok(match call { + Call::Raw { data } => Decode::decode(&mut &*data.0)?, + Call::Remark { remark_payload, .. } => { + millau_runtime::Call::System(millau_runtime::SystemCall::remark(remark_payload.0.clone())) + } + Call::Transfer { recipient, amount } => millau_runtime::Call::Balances( + millau_runtime::BalancesCall::transfer(recipient.raw_id(), amount.cast()), + ), + Call::BridgeSendMessage { + lane, + payload, + fee, + bridge_instance_index, + } => match *bridge_instance_index { + encode_call::MILLAU_TO_RIALTO_INDEX => { + let payload = Decode::decode(&mut &*payload.0)?; + millau_runtime::Call::BridgeRialtoMessages(millau_runtime::MessagesCall::send_message( + lane.0, + payload, + fee.cast(), + )) + } + _ => anyhow::bail!( + "Unsupported target bridge pallet with instance index: {}", + bridge_instance_index + ), + }, + }) + } } impl CliChain for Millau { @@ -467,58 +457,20 @@ impl CliChain for Millau { bp_millau::max_extrinsic_weight() } - fn encode_call(call: cli::Call) -> Result { - let call = match call { - cli::Call::Raw { data } => { - Decode::decode(&mut &*data.0).map_err(|e| format!("Unable to decode message: {:#?}", e))? - } - cli::Call::Remark { remark_size } => { - 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::Call::Transfer { mut recipient, amount } => { - recipient.enforce_chain::(); - let amount = amount.cast(); - millau_runtime::Call::Balances(millau_runtime::BalancesCall::transfer(recipient.raw_id(), amount)) - } - cli::Call::BridgeSendMessage { lane, payload, fee } => { - type Target = Rialto; - - let payload = Target::encode_message(cli::MessagePayload::Raw { data: payload })?; - let lane = lane.into(); - millau_runtime::Call::BridgeRialtoMessages(millau_runtime::MessagesCall::send_message( - lane, - payload, - fee.cast(), - )) - } - }; - - 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) - } - // TODO [#854|#843] support multiple bridges? fn encode_message(message: cli::MessagePayload) -> Result { match message { cli::MessagePayload::Raw { data } => MessagePayload::decode(&mut &*data.0) .map_err(|e| format!("Failed to decode Millau's MessagePayload: {:?}", e)), - cli::MessagePayload::Call { call, mut sender } => { + cli::MessagePayload::Call { mut call, mut sender } => { type Source = Millau; type Target = Rialto; sender.enforce_chain::(); let spec_version = Target::RUNTIME_VERSION.spec_version; let origin = CallOrigin::SourceAccount(sender.raw_id()); - let call = Target::encode_call(call)?; + encode_call::preprocess_call::(&mut call, MILLAU_TO_RIALTO_INDEX); + let call = Target::encode_call(&call).map_err(|e| e.to_string())?; let weight = call.get_dispatch_info().weight; Ok(message_payload(spec_version, weight, origin, &call)) @@ -527,6 +479,41 @@ impl CliChain for Millau { } } +impl CliEncodeCall for Rialto { + fn max_extrinsic_size() -> u32 { + bp_rialto::max_extrinsic_size() + } + + fn encode_call(call: &Call) -> anyhow::Result { + Ok(match call { + Call::Raw { data } => Decode::decode(&mut &*data.0)?, + Call::Remark { remark_payload, .. } => { + rialto_runtime::Call::System(rialto_runtime::SystemCall::remark(remark_payload.0.clone())) + } + Call::Transfer { recipient, amount } => { + rialto_runtime::Call::Balances(rialto_runtime::BalancesCall::transfer(recipient.raw_id(), amount.0)) + } + Call::BridgeSendMessage { + lane, + payload, + fee, + bridge_instance_index, + } => match *bridge_instance_index { + encode_call::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, + )) + } + _ => anyhow::bail!( + "Unsupported target bridge pallet with instance index: {}", + bridge_instance_index + ), + }, + }) + } +} + impl CliChain for Rialto { const RUNTIME_VERSION: RuntimeVersion = rialto_runtime::VERSION; @@ -541,57 +528,19 @@ impl CliChain for Rialto { bp_rialto::max_extrinsic_weight() } - fn encode_call(call: cli::Call) -> Result { - let call = match call { - cli::Call::Raw { data } => { - Decode::decode(&mut &*data.0).map_err(|e| format!("Unable to decode message: {:#?}", e))? - } - cli::Call::Remark { remark_size } => { - rialto_runtime::Call::System(rialto_runtime::SystemCall::remark(remark_payload( - remark_size, - compute_maximal_message_arguments_size( - bp_millau::max_extrinsic_size(), - bp_rialto::max_extrinsic_size(), - ), - ))) - } - cli::Call::Transfer { mut recipient, amount } => { - type Source = Rialto; - - recipient.enforce_chain::(); - let amount = amount.0; - rialto_runtime::Call::Balances(rialto_runtime::BalancesCall::transfer(recipient.raw_id(), amount)) - } - cli::Call::BridgeSendMessage { lane, payload, fee } => { - type Target = Millau; - - let payload = Target::encode_message(cli::MessagePayload::Raw { data: payload })?; - let lane = lane.into(); - rialto_runtime::Call::BridgeMillauMessages(rialto_runtime::MessagesCall::send_message( - lane, payload, fee.0, - )) - } - }; - - log::info!(target: "bridge", "Generated Rialto call: {:#?}", call); - log::info!(target: "bridge", "Weight of Rialto call: {}", call.get_dispatch_info().weight); - log::info!(target: "bridge", "Encoded Rialto call: {:?}", HexBytes::encode(&call)); - - Ok(call) - } - fn encode_message(message: cli::MessagePayload) -> Result { match message { cli::MessagePayload::Raw { data } => MessagePayload::decode(&mut &*data.0) .map_err(|e| format!("Failed to decode Rialto's MessagePayload: {:?}", e)), - cli::MessagePayload::Call { call, mut sender } => { + cli::MessagePayload::Call { mut call, mut sender } => { type Source = Rialto; type Target = Millau; sender.enforce_chain::(); let spec_version = Target::RUNTIME_VERSION.spec_version; let origin = CallOrigin::SourceAccount(sender.raw_id()); - let call = Target::encode_call(call)?; + encode_call::preprocess_call::(&mut call, RIALTO_TO_MILLAU_INDEX); + let call = Target::encode_call(&call).map_err(|e| e.to_string())?; let weight = call.get_dispatch_info().weight; Ok(message_payload(spec_version, weight, origin, &call)) @@ -614,10 +563,6 @@ impl CliChain for Westend { 0 } - fn encode_call(_: cli::Call) -> Result { - Err("Calling into Westend is not supported yet.".into()) - } - fn encode_message(_message: cli::MessagePayload) -> Result { Err("Sending messages from Westend is not yet supported.".into()) } @@ -680,8 +625,10 @@ mod tests { 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 maximal_remark_size = encode_call::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(