Skip to content

Commit

Permalink
CLI: Estimate Fee (paritytech#888)
Browse files Browse the repository at this point in the history
* Move estimate-fee

* Add parsing test.

* Address review comments.

* Fix compilation.

* Move things around.

Co-authored-by: Svyatoslav Nikolsky <[email protected]>
  • Loading branch information
2 people authored and serban300 committed Apr 9, 2024
1 parent 3feabe7 commit 1c22fbd
Show file tree
Hide file tree
Showing 8 changed files with 213 additions and 218 deletions.
11 changes: 6 additions & 5 deletions bridges/relays/bin-substrate/src/cli/bridge.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
use structopt::clap::arg_enum;

arg_enum! {
#[derive(Debug)]
#[derive(Debug, PartialEq, Eq)]
/// Supported full bridges (headers + messages).
pub enum FullBridge {
MillauToRialto,
Expand Down Expand Up @@ -59,9 +59,9 @@ macro_rules! select_full_bridge {
#[allow(unused_imports)]
use crate::rialto_millau::millau_messages_to_rialto::run as relay_messages;

// Send-message
// Send-message / Estimate-fee
#[allow(unused_imports)]
use bp_millau::TO_MILLAU_ESTIMATE_MESSAGE_FEE_METHOD as ESTIMATE_MESSAGE_FEE_METHOD;
use bp_rialto::TO_RIALTO_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;
Expand All @@ -81,9 +81,10 @@ macro_rules! select_full_bridge {
#[allow(unused_imports)]
use crate::rialto_millau::rialto_messages_to_millau::run as relay_messages;

// Send-message
// Send-message / Estimate-fee
#[allow(unused_imports)]
use bp_rialto::TO_RIALTO_ESTIMATE_MESSAGE_FEE_METHOD as ESTIMATE_MESSAGE_FEE_METHOD;
use bp_millau::TO_MILLAU_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;
Expand Down
2 changes: 1 addition & 1 deletion bridges/relays/bin-substrate/src/cli/encode_call.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ pub struct EncodeCall {
///
/// 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)]
#[derive(StructOpt, Debug, PartialEq, Eq)]
pub enum Call {
/// Raw bytes for the message
Raw {
Expand Down
2 changes: 1 addition & 1 deletion bridges/relays/bin-substrate/src/cli/encode_message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ use crate::select_full_bridge;
use structopt::StructOpt;

/// Generic message payload.
#[derive(StructOpt, Debug)]
#[derive(StructOpt, Debug, PartialEq, Eq)]
pub enum MessagePayload {
/// Raw, SCALE-encoded `MessagePayload`.
Raw {
Expand Down
128 changes: 128 additions & 0 deletions bridges/relays/bin-substrate/src/cli/estimate_fee.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
// Copyright 2019-2021 Parity Technologies (UK) Ltd.
// This file is part of Parity Bridges Common.

// Parity Bridges Common is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// Parity Bridges Common is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with Parity Bridges Common. If not, see <http://www.gnu.org/licenses/>.

use crate::cli::bridge::FullBridge;
use crate::cli::{Balance, CliChain, HexBytes, HexLaneId, SourceConnectionParams};
use crate::select_full_bridge;
use codec::{Decode, Encode};
use relay_substrate_client::{Chain, ChainWithBalances};
use structopt::StructOpt;

/// Estimate Delivery & Dispatch Fee command.
#[derive(StructOpt, Debug, PartialEq, Eq)]
pub struct EstimateFee {
/// A bridge instance to encode call for.
#[structopt(possible_values = &FullBridge::variants(), case_insensitive = true)]
bridge: FullBridge,
#[structopt(flatten)]
source: SourceConnectionParams,
/// Hex-encoded id of lane that will be delivering the message.
#[structopt(long, default_value = "00000000")]
lane: HexLaneId,
/// Payload to send over the bridge.
#[structopt(flatten)]
payload: crate::cli::encode_message::MessagePayload,
}

impl EstimateFee {
/// Run the command.
pub async fn run(self) -> anyhow::Result<()> {
let Self {
source,
bridge,
lane,
payload,
} = self;

select_full_bridge!(bridge, {
let source_client = source.to_client::<Source>().await?;
let lane = lane.into();
let payload = Source::encode_message(payload).map_err(|e| anyhow::format_err!("{:?}", e))?;

let fee: <Source as ChainWithBalances>::NativeBalance =
estimate_message_delivery_and_dispatch_fee(&source_client, ESTIMATE_MESSAGE_FEE_METHOD, lane, payload)
.await?;

log::info!(target: "bridge", "Fee: {:?}", Balance(fee as _));
println!("{}", fee);
Ok(())
})
}
}

pub(crate) async fn estimate_message_delivery_and_dispatch_fee<Fee: Decode, C: Chain, P: Encode>(
client: &relay_substrate_client::Client<C>,
estimate_fee_method: &str,
lane: bp_messages::LaneId,
payload: P,
) -> anyhow::Result<Fee> {
let encoded_response = client
.state_call(estimate_fee_method.into(), (lane, payload).encode().into(), None)
.await?;
let decoded_response: Option<Fee> =
Decode::decode(&mut &encoded_response.0[..]).map_err(relay_substrate_client::Error::ResponseParseFailed)?;
let fee = decoded_response
.ok_or_else(|| anyhow::format_err!("Unable to decode fee from: {:?}", HexBytes(encoded_response.to_vec())))?;
Ok(fee)
}

#[cfg(test)]
mod tests {
use super::*;
use crate::cli::encode_call;
use sp_core::crypto::Ss58Codec;

#[test]
fn should_parse_cli_options() {
// given
let alice = sp_keyring::AccountKeyring::Alice.to_account_id().to_ss58check();

// when
let res = EstimateFee::from_iter(vec![
"estimate_fee",
"RialtoToMillau",
"--source-port",
"1234",
"call",
"--sender",
&alice,
"remark",
"--remark-payload",
"1234",
]);

// then
assert_eq!(
res,
EstimateFee {
bridge: FullBridge::RialtoToMillau,
lane: HexLaneId([0, 0, 0, 0]),
source: SourceConnectionParams {
source_host: "127.0.0.1".into(),
source_port: 1234,
source_secure: false,
},
payload: crate::cli::encode_message::MessagePayload::Call {
sender: alice.parse().unwrap(),
call: encode_call::Call::Remark {
remark_payload: Some(HexBytes(vec![0x12, 0x34])),
remark_size: None,
}
}
}
);
}
}
35 changes: 9 additions & 26 deletions bridges/relays/bin-substrate/src/cli/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@

use std::convert::TryInto;

use crate::rialto_millau::cli as rialto_millau;
use bp_messages::LaneId;
use codec::{Decode, Encode};
use frame_support::weights::Weight;
Expand All @@ -28,12 +27,13 @@ use structopt::{clap::arg_enum, StructOpt};
pub(crate) mod bridge;
pub(crate) mod encode_call;
pub(crate) mod encode_message;
pub(crate) mod estimate_fee;
pub(crate) mod send_message;

mod derive_account;
mod init_bridge;
mod relay_headers;
mod relay_messages;
mod send_message;

/// Parse relay CLI args.
pub fn parse_args() -> Command {
Expand Down Expand Up @@ -75,7 +75,7 @@ pub enum Command {
/// the bridge.
EncodeMessage(encode_message::EncodeMessage),
/// Estimate Delivery and Dispatch Fee required for message submission to messages pallet.
EstimateFee(EstimateFee),
EstimateFee(estimate_fee::EstimateFee),
/// Given a source chain `AccountId`, derive the corresponding `AccountId` for the target chain.
DeriveAccount(derive_account::DeriveAccount),
}
Expand All @@ -97,23 +97,6 @@ impl Command {
}
}

/// Estimate Delivery & Dispatch Fee command.
#[derive(StructOpt)]
pub enum EstimateFee {
#[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(())
}
}

arg_enum! {
#[derive(Debug)]
/// The origin to use when dispatching the message on the target chain.
Expand All @@ -127,7 +110,7 @@ arg_enum! {
}

/// Generic balance type.
#[derive(Debug, Clone, Copy)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Balance(pub u128);

impl std::fmt::Display for Balance {
Expand Down Expand Up @@ -242,7 +225,7 @@ pub trait CliChain: relay_substrate_client::Chain {
}

/// Lane id.
#[derive(Debug, Clone)]
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct HexLaneId(pub LaneId);

impl From<HexLaneId> for LaneId {
Expand All @@ -262,7 +245,7 @@ impl std::str::FromStr for HexLaneId {
}

/// Nicer formatting for raw bytes vectors.
#[derive(Default, Encode, Decode)]
#[derive(Default, Encode, Decode, PartialEq, Eq)]
pub struct HexBytes(pub Vec<u8>);

impl std::str::FromStr for HexBytes {
Expand Down Expand Up @@ -321,7 +304,7 @@ impl From<PrometheusParams> for relay_utils::metrics::MetricsParams {
}

/// Either explicit or maximal allowed value.
#[derive(Debug, Clone)]
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ExplicitOrMaximal<V> {
/// User has explicitly specified argument value.
Explicit(V),
Expand Down Expand Up @@ -353,7 +336,7 @@ macro_rules! declare_chain_options {
($chain:ident, $chain_prefix:ident) => {
paste::item! {
#[doc = $chain " connection params."]
#[derive(StructOpt)]
#[derive(StructOpt, Debug, PartialEq, Eq)]
pub struct [<$chain ConnectionParams>] {
#[doc = "Connect to " $chain " node at given host."]
#[structopt(long, default_value = "127.0.0.1")]
Expand All @@ -367,7 +350,7 @@ macro_rules! declare_chain_options {
}

#[doc = $chain " signing params."]
#[derive(StructOpt)]
#[derive(StructOpt, Debug, PartialEq, Eq)]
pub struct [<$chain SigningParams>] {
#[doc = "The SURI of secret key to use when transactions are submitted to the " $chain " node."]
#[structopt(long)]
Expand Down
63 changes: 53 additions & 10 deletions bridges/relays/bin-substrate/src/cli/send_message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

use crate::cli::bridge::FullBridge;
use crate::cli::encode_call::{self, CliEncodeCall};
use crate::cli::estimate_fee::estimate_message_delivery_and_dispatch_fee;
use crate::cli::{
Balance, CliChain, ExplicitOrMaximal, HexBytes, HexLaneId, Origins, SourceConnectionParams, SourceSigningParams,
TargetSigningParams,
Expand All @@ -26,6 +27,7 @@ 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 std::fmt::Debug;
use structopt::StructOpt;

/// Send bridge message.
Expand Down Expand Up @@ -84,12 +86,12 @@ impl SendMessage {
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()),
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(
message_payload(
Target::RUNTIME_VERSION.spec_version,
target_call_weight,
match origin {
Expand Down Expand Up @@ -127,14 +129,14 @@ impl SendMessage {
let lane = self.lane.clone().into();
let fee = match self.fee {
Some(fee) => fee,
None => crate::rialto_millau::estimate_message_delivery_and_dispatch_fee::<
<Source as relay_substrate_client::ChainWithBalances>::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?"))?,
None => Balance(
estimate_message_delivery_and_dispatch_fee::<
<Source as relay_substrate_client::ChainWithBalances>::NativeBalance,
_,
_,
>(&source_client, ESTIMATE_MESSAGE_FEE_METHOD, lane, payload.clone())
.await? as _,
),
};
let dispatch_weight = payload.weight;
let send_message_call = Source::encode_call(&encode_call::Call::BridgeSendMessage {
Expand Down Expand Up @@ -192,6 +194,47 @@ fn prepare_call_dispatch_weight(
}
}

pub(crate) fn message_payload<SAccountId, TPublic, TSignature>(
spec_version: u32,
weight: Weight,
origin: CallOrigin<SAccountId, TPublic, TSignature>,
call: &impl Encode,
) -> MessagePayload<SAccountId, TPublic, TSignature, Vec<u8>>
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<u8>`
let MessagePayload {
spec_version,
weight,
origin,
call,
} = payload;
MessagePayload {
spec_version,
weight,
origin,
call: call.0,
}
}

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)
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down
Loading

0 comments on commit 1c22fbd

Please sign in to comment.