diff --git a/bin/millau/runtime/src/lib.rs b/bin/millau/runtime/src/lib.rs index 982a58fd728b..b7a294900580 100644 --- a/bin/millau/runtime/src/lib.rs +++ b/bin/millau/runtime/src/lib.rs @@ -30,6 +30,9 @@ include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); pub mod rialto_messages; +use crate::rialto_messages::{ToRialtoMessagePayload, WithRialtoMessageBridge}; + +use bridge_runtime_common::messages::{source::estimate_message_dispatch_and_delivery_fee, MessageBridge}; use codec::Decode; use pallet_grandpa::{fg_primitives, AuthorityId as GrandpaId, AuthorityList as GrandpaAuthorityList}; use sp_api::impl_runtime_apis; @@ -532,7 +535,17 @@ impl_runtime_apis! { } } - impl bp_rialto::ToRialtoOutboundLaneApi for Runtime { + impl bp_rialto::ToRialtoOutboundLaneApi for Runtime { + fn estimate_message_delivery_and_dispatch_fee( + _lane_id: bp_message_lane::LaneId, + payload: ToRialtoMessagePayload, + ) -> Option { + estimate_message_dispatch_and_delivery_fee::( + &payload, + WithRialtoMessageBridge::RELAYER_FEE_PERCENT, + ).ok() + } + fn messages_dispatch_weight( lane: bp_message_lane::LaneId, begin: bp_message_lane::MessageNonce, diff --git a/bin/millau/runtime/src/rialto_messages.rs b/bin/millau/runtime/src/rialto_messages.rs index b5e1cc0fdb07..cf3e6511801c 100644 --- a/bin/millau/runtime/src/rialto_messages.rs +++ b/bin/millau/runtime/src/rialto_messages.rs @@ -124,9 +124,9 @@ impl MessageBridge for WithRialtoMessageBridge { ::WeightToFee::calc(&weight) as _ } - fn this_balance_to_bridged_balance(this_balance: bp_millau::Balance) -> bp_rialto::Balance { + fn bridged_balance_to_this_balance(bridged_balance: bp_rialto::Balance) -> bp_millau::Balance { // 1:1 conversion that will probably change in the future - this_balance as _ + bridged_balance as _ } } diff --git a/bin/rialto/runtime/src/lib.rs b/bin/rialto/runtime/src/lib.rs index 33e4972d0593..6a7562c5913c 100644 --- a/bin/rialto/runtime/src/lib.rs +++ b/bin/rialto/runtime/src/lib.rs @@ -36,6 +36,9 @@ pub mod kovan; pub mod millau_messages; pub mod rialto_poa; +use crate::millau_messages::{ToMillauMessagePayload, WithMillauMessageBridge}; + +use bridge_runtime_common::messages::{source::estimate_message_dispatch_and_delivery_fee, MessageBridge}; use codec::Decode; use pallet_grandpa::{fg_primitives, AuthorityId as GrandpaId, AuthorityList as GrandpaAuthorityList}; use sp_api::impl_runtime_apis; @@ -695,7 +698,17 @@ impl_runtime_apis! { } } - impl bp_millau::ToMillauOutboundLaneApi for Runtime { + impl bp_millau::ToMillauOutboundLaneApi for Runtime { + fn estimate_message_delivery_and_dispatch_fee( + _lane_id: bp_message_lane::LaneId, + payload: ToMillauMessagePayload, + ) -> Option { + estimate_message_dispatch_and_delivery_fee::( + &payload, + WithMillauMessageBridge::RELAYER_FEE_PERCENT, + ).ok() + } + fn messages_dispatch_weight( lane: bp_message_lane::LaneId, begin: bp_message_lane::MessageNonce, diff --git a/bin/rialto/runtime/src/millau_messages.rs b/bin/rialto/runtime/src/millau_messages.rs index 33d254e9b5e4..85b06c35af34 100644 --- a/bin/rialto/runtime/src/millau_messages.rs +++ b/bin/rialto/runtime/src/millau_messages.rs @@ -125,9 +125,9 @@ impl MessageBridge for WithMillauMessageBridge { ::WeightToFee::calc(&weight) as _ } - fn this_balance_to_bridged_balance(this_balance: bp_rialto::Balance) -> bp_millau::Balance { + fn bridged_balance_to_this_balance(bridged_balance: bp_millau::Balance) -> bp_rialto::Balance { // 1:1 conversion that will probably change in the future - this_balance as _ + bridged_balance as _ } } diff --git a/bin/runtime-common/src/messages.rs b/bin/runtime-common/src/messages.rs index 30c6a1f7d1c2..503dcaeddf77 100644 --- a/bin/runtime-common/src/messages.rs +++ b/bin/runtime-common/src/messages.rs @@ -81,8 +81,8 @@ pub trait MessageBridge { /// Convert weight of the Bridged chain to the fee (paid in Balance) of the Bridged chain. fn bridged_weight_to_bridged_balance(weight: WeightOf>) -> BalanceOf>; - /// Convert This chain Balance into Bridged chain Balance. - fn this_balance_to_bridged_balance(this_balance: BalanceOf>) -> BalanceOf>; + /// Convert Bridged chain Balance into This chain Balance. + fn bridged_balance_to_this_balance(bridged_balance: BalanceOf>) -> BalanceOf>; } /// Chain that has `message-lane` and `call-dispatch` modules. @@ -170,12 +170,11 @@ pub mod source { // `CallDispatch`, so we verify the message accordingly. pallet_bridge_call_dispatch::verify_message_origin(submitter, payload).map_err(|_| BAD_ORIGIN)?; - let minimal_fee_in_bridged_tokens = + let minimal_fee_in_this_tokens = estimate_message_dispatch_and_delivery_fee::(payload, B::RELAYER_FEE_PERCENT)?; // compare with actual fee paid - let actual_fee_in_bridged_tokens = B::this_balance_to_bridged_balance(*delivery_and_dispatch_fee); - if actual_fee_in_bridged_tokens < minimal_fee_in_bridged_tokens { + if *delivery_and_dispatch_fee < minimal_fee_in_this_tokens { return Err(TOO_LOW_FEE); } @@ -225,22 +224,22 @@ pub mod source { pub fn estimate_message_dispatch_and_delivery_fee( payload: &FromThisChainMessagePayload, relayer_fee_percent: u32, - ) -> Result>, &'static str> { + ) -> Result>, &'static str> { // the fee (in Bridged tokens) of all transactions that are made on the Bridged chain let delivery_fee = B::bridged_weight_to_bridged_balance(B::weight_of_delivery_transaction()); let dispatch_fee = B::bridged_weight_to_bridged_balance(payload.weight.into()); let reward_confirmation_fee = B::bridged_weight_to_bridged_balance(B::weight_of_reward_confirmation_transaction_on_target_chain()); - // the fee (in Bridged tokens) of all transactions that are made on This chain - let delivery_confirmation_fee = B::this_balance_to_bridged_balance(B::this_weight_to_this_balance( - B::weight_of_delivery_confirmation_transaction_on_this_chain(), - )); + // the fee (in This tokens) of all transactions that are made on This chain + let delivery_confirmation_fee = + B::this_weight_to_this_balance(B::weight_of_delivery_confirmation_transaction_on_this_chain()); - // minimal fee (in Bridged tokens) is a sum of all required fees + // minimal fee (in This tokens) is a sum of all required fees let minimal_fee = delivery_fee .checked_add(&dispatch_fee) .and_then(|fee| fee.checked_add(&reward_confirmation_fee)) + .map(B::bridged_balance_to_this_balance) .and_then(|fee| fee.checked_add(&delivery_confirmation_fee)); // before returning, add extra fee that is paid to the relayer (relayer interest) @@ -563,7 +562,7 @@ mod tests { const REWARD_CONFIRMATION_TRANSACTION_WEIGHT: Weight = 100; const THIS_CHAIN_WEIGHT_TO_BALANCE_RATE: Weight = 2; const BRIDGED_CHAIN_WEIGHT_TO_BALANCE_RATE: Weight = 4; - const THIS_CHAIN_TO_BRIDGED_CHAIN_BALANCE_RATE: u32 = 6; + const BRIDGED_CHAIN_TO_THIS_CHAIN_BALANCE_RATE: u32 = 6; const BRIDGED_CHAIN_MAX_EXTRINSIC_WEIGHT: Weight = 2048; const BRIDGED_CHAIN_MAX_EXTRINSIC_SIZE: u32 = 1024; @@ -606,8 +605,8 @@ mod tests { BridgedChainBalance(weight as u32 * BRIDGED_CHAIN_WEIGHT_TO_BALANCE_RATE as u32) } - fn this_balance_to_bridged_balance(this_balance: ThisChainBalance) -> BridgedChainBalance { - BridgedChainBalance(this_balance.0 * THIS_CHAIN_TO_BRIDGED_CHAIN_BALANCE_RATE as u32) + fn bridged_balance_to_this_balance(bridged_balance: BridgedChainBalance) -> ThisChainBalance { + ThisChainBalance(bridged_balance.0 * BRIDGED_CHAIN_TO_THIS_CHAIN_BALANCE_RATE as u32) } } @@ -649,7 +648,7 @@ mod tests { unreachable!() } - fn this_balance_to_bridged_balance(_this_balance: BridgedChainBalance) -> ThisChainBalance { + fn bridged_balance_to_this_balance(_this_balance: ThisChainBalance) -> BridgedChainBalance { unreachable!() } } @@ -799,7 +798,7 @@ mod tests { #[test] fn message_fee_is_checked_by_verifier() { - const EXPECTED_MINIMAL_FEE: u32 = 2640; + const EXPECTED_MINIMAL_FEE: u32 = 8140; // payload of the This -> Bridged chain message let payload = source::FromThisChainMessagePayload:: { @@ -815,7 +814,7 @@ mod tests { &payload, OnThisChainBridge::RELAYER_FEE_PERCENT, ), - Ok(BridgedChainBalance(EXPECTED_MINIMAL_FEE)), + Ok(ThisChainBalance(EXPECTED_MINIMAL_FEE)), ); // and now check that the verifier checks the fee diff --git a/deployments/bridges/rialto-millau/entrypoints/relay-messages-to-millau-generator-entrypoint.sh b/deployments/bridges/rialto-millau/entrypoints/relay-messages-to-millau-generator-entrypoint.sh index 1f41f00ad2cf..35c45ac7e804 100755 --- a/deployments/bridges/rialto-millau/entrypoints/relay-messages-to-millau-generator-entrypoint.sh +++ b/deployments/bridges/rialto-millau/entrypoints/relay-messages-to-millau-generator-entrypoint.sh @@ -31,7 +31,6 @@ do echo "Sending Remark from Rialto to Millau using Target Origin" $SEND_MESSAGE \ --lane $MESSAGE_LANE \ - --fee 100000000 \ --origin Target \ remark @@ -39,7 +38,6 @@ do echo "Sending Transfer from Rialto to Millau using Target Origin" $SEND_MESSAGE \ --lane $MESSAGE_LANE \ - --fee 1000000000 \ --origin Target \ transfer \ --amount 1000000000 \ @@ -49,7 +47,6 @@ do echo "Sending Remark from Rialto to Millau using Source Origin" $SEND_MESSAGE \ --lane $MESSAGE_LANE \ - --fee 100000000 \ --origin Source \ remark @@ -57,7 +54,6 @@ do echo "Sending Transfer from Rialto to Millau using Source Origin" $SEND_MESSAGE \ --lane $MESSAGE_LANE \ - --fee 1000000000 \ --origin Source \ transfer \ --amount 1000000000 \ diff --git a/deployments/bridges/rialto-millau/entrypoints/relay-messages-to-rialto-generator-entrypoint.sh b/deployments/bridges/rialto-millau/entrypoints/relay-messages-to-rialto-generator-entrypoint.sh index 4ff6c2c995d9..6746d998519b 100755 --- a/deployments/bridges/rialto-millau/entrypoints/relay-messages-to-rialto-generator-entrypoint.sh +++ b/deployments/bridges/rialto-millau/entrypoints/relay-messages-to-rialto-generator-entrypoint.sh @@ -31,7 +31,6 @@ do echo "Sending Remark from Millau to Rialto using Target Origin" $SEND_MESSAGE \ --lane $MESSAGE_LANE \ - --fee 100000000 \ --origin Target \ remark @@ -39,7 +38,6 @@ do echo "Sending Transfer from Millau to Rialto using Target Origin" $SEND_MESSAGE \ --lane $MESSAGE_LANE \ - --fee 1000000000 \ --origin Target \ transfer \ --amount 1000000000 \ @@ -49,7 +47,6 @@ do echo "Sending Remark from Millau to Rialto using Source Origin" $SEND_MESSAGE \ --lane $MESSAGE_LANE \ - --fee 100000000 \ --origin Source \ remark @@ -57,7 +54,6 @@ do echo "Sending Transfer from Millau to Rialto using Source Origin" $SEND_MESSAGE \ --lane $MESSAGE_LANE \ - --fee 1000000000 \ --origin Source \ transfer \ --amount 1000000000 \ diff --git a/primitives/millau/src/lib.rs b/primitives/millau/src/lib.rs index daef9abf2fc4..636697847cd4 100644 --- a/primitives/millau/src/lib.rs +++ b/primitives/millau/src/lib.rs @@ -26,7 +26,7 @@ use bp_message_lane::{LaneId, MessageNonce, UnrewardedRelayersState}; use bp_runtime::Chain; use frame_support::{ weights::{constants::WEIGHT_PER_SECOND, DispatchClass, Weight}, - RuntimeDebug, + Parameter, RuntimeDebug, }; use frame_system::limits; use sp_core::Hasher as HasherT; @@ -191,6 +191,9 @@ pub const IS_KNOWN_MILLAU_BLOCK_METHOD: &str = "MillauHeaderApi_is_known_block"; /// Name of the `MillauHeaderApi::incomplete_headers` runtime method. pub const INCOMPLETE_MILLAU_HEADERS_METHOD: &str = "MillauHeaderApi_incomplete_headers"; +/// Name of the `ToMillauOutboundLaneApi::estimate_message_delivery_and_dispatch_fee` runtime method. +pub const TO_MILLAU_ESTIMATE_MESSAGE_FEE_METHOD: &str = + "ToMillauOutboundLaneApi_estimate_message_delivery_and_dispatch_fee"; /// Name of the `ToMillauOutboundLaneApi::messages_dispatch_weight` runtime method. pub const TO_MILLAU_MESSAGES_DISPATCH_WEIGHT_METHOD: &str = "ToMillauOutboundLaneApi_messages_dispatch_weight"; /// Name of the `ToMillauOutboundLaneApi::latest_received_nonce` runtime method. @@ -235,7 +238,20 @@ sp_api::decl_runtime_apis! { /// /// This API is implemented by runtimes that are sending messages to Millau chain, not the /// Millau runtime itself. - pub trait ToMillauOutboundLaneApi { + pub trait ToMillauOutboundLaneApi { + /// Estimate message delivery and dispatch fee that needs to be paid by the sender on + /// this chain. + /// + /// Returns `None` if message is too expensive to be sent to Millau from this chain. + /// + /// Please keep in mind that this method returns lowest message fee required for message + /// to be accepted to the lane. It may be good idea to pay a bit over this price to account + /// future exchange rate changes and guarantee that relayer would deliver your message + /// to the target chain. + fn estimate_message_delivery_and_dispatch_fee( + lane_id: LaneId, + payload: OutboundPayload, + ) -> Option; /// Returns total dispatch weight and encoded payload size of all messages in given inclusive range. /// /// If some (or all) messages are missing from the storage, they'll also will diff --git a/primitives/rialto/src/lib.rs b/primitives/rialto/src/lib.rs index 2b293d70f958..a514254b2256 100644 --- a/primitives/rialto/src/lib.rs +++ b/primitives/rialto/src/lib.rs @@ -24,7 +24,7 @@ use bp_message_lane::{LaneId, MessageNonce, UnrewardedRelayersState}; use bp_runtime::Chain; use frame_support::{ weights::{constants::WEIGHT_PER_SECOND, DispatchClass, Weight}, - RuntimeDebug, + Parameter, RuntimeDebug, }; use frame_system::limits; use sp_core::Hasher as HasherT; @@ -152,6 +152,9 @@ pub const IS_KNOWN_RIALTO_BLOCK_METHOD: &str = "RialtoHeaderApi_is_known_block"; /// Name of the `RialtoHeaderApi::incomplete_headers` runtime method. pub const INCOMPLETE_RIALTO_HEADERS_METHOD: &str = "RialtoHeaderApi_incomplete_headers"; +/// Name of the `ToRialtoOutboundLaneApi::estimate_message_delivery_and_dispatch_fee` runtime method. +pub const TO_RIALTO_ESTIMATE_MESSAGE_FEE_METHOD: &str = + "ToRialtoOutboundLaneApi_estimate_message_delivery_and_dispatch_fee"; /// Name of the `ToRialtoOutboundLaneApi::messages_dispatch_weight` runtime method. pub const TO_RIALTO_MESSAGES_DISPATCH_WEIGHT_METHOD: &str = "ToRialtoOutboundLaneApi_messages_dispatch_weight"; /// Name of the `ToRialtoOutboundLaneApi::latest_generated_nonce` runtime method. @@ -196,7 +199,20 @@ sp_api::decl_runtime_apis! { /// /// This API is implemented by runtimes that are sending messages to Rialto chain, not the /// Rialto runtime itself. - pub trait ToRialtoOutboundLaneApi { + pub trait ToRialtoOutboundLaneApi { + /// Estimate message delivery and dispatch fee that needs to be paid by the sender on + /// this chain. + /// + /// Returns `None` if message is too expensive to be sent to Rialto from this chain. + /// + /// Please keep in mind that this method returns lowest message fee required for message + /// to be accepted to the lane. It may be good idea to pay a bit over this price to account + /// future exchange rate changes and guarantee that relayer would deliver your message + /// to the target chain. + fn estimate_message_delivery_and_dispatch_fee( + lane_id: LaneId, + payload: OutboundPayload, + ) -> Option; /// Returns total dispatch weight and encoded payload size of all messages in given inclusive range. /// /// If some (or all) messages are missing from the storage, they'll also will diff --git a/relays/substrate/src/cli.rs b/relays/substrate/src/cli.rs index 0e7f92001a35..a6dd5ab67b33 100644 --- a/relays/substrate/src/cli.rs +++ b/relays/substrate/src/cli.rs @@ -101,9 +101,9 @@ pub enum Command { /// Hex-encoded lane id. #[structopt(long)] lane: HexLaneId, - /// Delivery and dispatch fee. + /// Delivery and dispatch fee. If not passed, determined automatically. #[structopt(long)] - fee: bp_millau::Balance, + fee: Option, /// Message type. #[structopt(subcommand)] message: ToRialtoMessage, @@ -138,9 +138,9 @@ pub enum Command { /// Hex-encoded lane id. #[structopt(long)] lane: HexLaneId, - /// Delivery and dispatch fee. + /// Delivery and dispatch fee. If not passed, determined automatically. #[structopt(long)] - fee: bp_rialto::Balance, + fee: Option, /// Message type. #[structopt(subcommand)] message: ToMillauMessage, diff --git a/relays/substrate/src/main.rs b/relays/substrate/src/main.rs index a63dc9623ed1..c6b89e7ee1fb 100644 --- a/relays/substrate/src/main.rs +++ b/relays/substrate/src/main.rs @@ -18,13 +18,13 @@ #![warn(missing_docs)] -use codec::Encode; +use codec::{Decode, Encode}; use frame_support::weights::GetDispatchInfo; 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::{ConnectionParams, TransactionSignScheme}; +use relay_substrate_client::{Chain, ConnectionParams, TransactionSignScheme}; use relay_utils::initialize::initialize_relay; use sp_core::{Bytes, Pair}; use sp_runtime::traits::IdentifyAccount; @@ -315,8 +315,27 @@ async fn run_command(command: cli::Command) -> Result<(), String> { } }; + let lane = lane.into(); + let fee = match fee { + Some(fee) => fee, + None => match estimate_message_delivery_and_dispatch_fee( + &millau_client, + bp_rialto::TO_RIALTO_ESTIMATE_MESSAGE_FEE_METHOD, + lane, + payload.clone(), + ) + .await + { + Ok(Some(fee)) => fee, + Ok(None) => return Err("Failed to estimate message fee. Message is too heavy?".into()), + Err(error) => return Err(format!("Failed to estimate message fee: {:?}", error)), + }, + }; + + log::error!(target: "bridge", "Sending message to Rialto. Fee: {}", fee); + let millau_call = millau_runtime::Call::BridgeRialtoMessageLane( - millau_runtime::MessageLaneCall::send_message(lane.into(), payload, fee), + millau_runtime::MessageLaneCall::send_message(lane, payload, fee), ); let signed_millau_call = Millau::sign_transaction( @@ -444,8 +463,27 @@ async fn run_command(command: cli::Command) -> Result<(), String> { } }; + let lane = lane.into(); + let fee = match fee { + Some(fee) => fee, + None => match estimate_message_delivery_and_dispatch_fee( + &rialto_client, + bp_millau::TO_MILLAU_ESTIMATE_MESSAGE_FEE_METHOD, + lane, + payload.clone(), + ) + .await + { + Ok(Some(fee)) => fee, + Ok(None) => return Err("Failed to estimate message fee. Message is too heavy?".into()), + Err(error) => return Err(format!("Failed to estimate message fee: {:?}", error)), + }, + }; + + log::info!(target: "bridge", "Sending message to Millau. Fee: {}", fee); + let rialto_call = rialto_runtime::Call::BridgeMillauMessageLane( - rialto_runtime::MessageLaneCall::send_message(lane.into(), payload, fee), + rialto_runtime::MessageLaneCall::send_message(lane, payload, fee), ); let signed_rialto_call = Rialto::sign_transaction( @@ -465,3 +503,17 @@ async fn run_command(command: cli::Command) -> Result<(), String> { 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) +} diff --git a/scripts/send-message.sh b/scripts/send-message.sh index 4037352e41e1..6cb6d1e8d679 100755 --- a/scripts/send-message.sh +++ b/scripts/send-message.sh @@ -15,7 +15,6 @@ case "$1" in --millau-signer //Dave \ --rialto-signer //Dave \ --lane 00000000 \ - --fee 100000000 \ --origin Target \ remark \ ;; @@ -27,7 +26,6 @@ case "$1" in --millau-signer //Dave \ --rialto-signer //Dave \ --lane 00000000 \ - --fee 1000000000 \ --origin Target \ transfer \ --amount 100000000000000 \