From 7e6a0f100e4ec191dd9193dea3071b7dd2e17799 Mon Sep 17 00:00:00 2001 From: Svyatoslav Nikolsky Date: Mon, 6 Sep 2021 12:04:33 +0300 Subject: [PATCH] Fix delivery transaction estimation used by rational relayer (#1109) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix delivery transaction estimation in greedy relayer * fixed typo * improve logging * improve logging * fmt * fix compilation * fmt * Update relays/lib-substrate-relay/src/messages_target.rs Co-authored-by: Tomasz Drwięga * review Co-authored-by: Tomasz Drwięga --- bridges/bin/millau/runtime/src/lib.rs | 2 +- bridges/bin/rialto/runtime/src/lib.rs | 2 +- bridges/primitives/chain-kusama/Cargo.toml | 5 + bridges/primitives/chain-kusama/src/lib.rs | 19 ++ bridges/primitives/chain-millau/src/lib.rs | 5 +- bridges/primitives/chain-polkadot/Cargo.toml | 4 + bridges/primitives/chain-polkadot/src/lib.rs | 19 ++ bridges/primitives/chain-rialto/src/lib.rs | 5 +- bridges/primitives/chain-rococo/src/lib.rs | 9 +- bridges/primitives/chain-westend/Cargo.toml | 5 + bridges/primitives/chain-westend/src/lib.rs | 19 ++ bridges/primitives/chain-wococo/src/lib.rs | 2 +- .../src/chains/millau_messages_to_rialto.rs | 3 + .../src/chains/rialto_messages_to_millau.rs | 3 + .../src/chains/rococo_messages_to_wococo.rs | 3 + .../src/chains/wococo_messages_to_rococo.rs | 3 + .../bin-substrate/src/cli/send_message.rs | 3 +- bridges/relays/client-kusama/src/lib.rs | 1 + bridges/relays/client-millau/src/lib.rs | 1 + bridges/relays/client-polkadot/src/lib.rs | 1 + bridges/relays/client-rialto/src/lib.rs | 1 + bridges/relays/client-rococo/src/lib.rs | 1 + bridges/relays/client-substrate/src/chain.rs | 7 +- bridges/relays/client-substrate/src/client.rs | 25 +- bridges/relays/client-substrate/src/guard.rs | 1 + bridges/relays/client-substrate/src/lib.rs | 4 +- bridges/relays/client-westend/src/lib.rs | 1 + bridges/relays/client-wococo/src/lib.rs | 1 + bridges/relays/lib-substrate-relay/Cargo.toml | 7 +- .../lib-substrate-relay/src/messages_lane.rs | 7 + .../src/messages_source.rs | 30 ++- .../src/messages_target.rs | 241 ++++++++++++++++-- .../src/on_demand_headers.rs | 6 +- .../relays/messages/src/message_lane_loop.rs | 2 + .../messages/src/message_race_delivery.rs | 14 +- 35 files changed, 391 insertions(+), 71 deletions(-) diff --git a/bridges/bin/millau/runtime/src/lib.rs b/bridges/bin/millau/runtime/src/lib.rs index 9bbdf3a937249..1eb77ed75ea63 100644 --- a/bridges/bin/millau/runtime/src/lib.rs +++ b/bridges/bin/millau/runtime/src/lib.rs @@ -282,7 +282,7 @@ parameter_types! { impl pallet_transaction_payment::Config for Runtime { type OnChargeTransaction = pallet_transaction_payment::CurrencyAdapter; type TransactionByteFee = TransactionByteFee; - type WeightToFee = IdentityFee; + type WeightToFee = bp_millau::WeightToFee; type FeeMultiplierUpdate = pallet_transaction_payment::TargetedFeeAdjustment< Runtime, TargetBlockFullness, diff --git a/bridges/bin/rialto/runtime/src/lib.rs b/bridges/bin/rialto/runtime/src/lib.rs index 2899d18d14027..c13c0d78a1b40 100644 --- a/bridges/bin/rialto/runtime/src/lib.rs +++ b/bridges/bin/rialto/runtime/src/lib.rs @@ -414,7 +414,7 @@ parameter_types! { impl pallet_transaction_payment::Config for Runtime { type OnChargeTransaction = pallet_transaction_payment::CurrencyAdapter; type TransactionByteFee = TransactionByteFee; - type WeightToFee = IdentityFee; + type WeightToFee = bp_rialto::WeightToFee; type FeeMultiplierUpdate = pallet_transaction_payment::TargetedFeeAdjustment< Runtime, TargetBlockFullness, diff --git a/bridges/primitives/chain-kusama/Cargo.toml b/bridges/primitives/chain-kusama/Cargo.toml index 70ff3b844df07..33102ea4f8871 100644 --- a/bridges/primitives/chain-kusama/Cargo.toml +++ b/bridges/primitives/chain-kusama/Cargo.toml @@ -7,13 +7,17 @@ edition = "2018" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" [dependencies] +smallvec = "1.6" # Bridge Dependencies + bp-messages = { path = "../messages", default-features = false } bp-polkadot-core = { path = "../polkadot-core", default-features = false } bp-runtime = { path = "../runtime", default-features = false } # Substrate Based Dependencies + +frame-support = { git = "https://github.com/paritytech/substrate", branch = "master" , default-features = false } sp-api = { git = "https://github.com/paritytech/substrate", branch = "master" , default-features = false } sp-std = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } @@ -23,6 +27,7 @@ std = [ "bp-messages/std", "bp-polkadot-core/std", "bp-runtime/std", + "frame-support/std", "sp-api/std", "sp-std/std", ] diff --git a/bridges/primitives/chain-kusama/src/lib.rs b/bridges/primitives/chain-kusama/src/lib.rs index e5ab47259e54c..59bb486c90064 100644 --- a/bridges/primitives/chain-kusama/src/lib.rs +++ b/bridges/primitives/chain-kusama/src/lib.rs @@ -21,6 +21,7 @@ #![allow(clippy::unnecessary_mut_passed)] use bp_messages::{LaneId, MessageDetails, MessageNonce, UnrewardedRelayersState}; +use frame_support::weights::{WeightToFeeCoefficient, WeightToFeeCoefficients, WeightToFeePolynomial}; use sp_std::prelude::*; pub use bp_polkadot_core::*; @@ -28,6 +29,24 @@ pub use bp_polkadot_core::*; /// Kusama Chain pub type Kusama = PolkadotLike; +// NOTE: This needs to be kept up to date with the Kusama runtime found in the Polkadot repo. +pub struct WeightToFee; +impl WeightToFeePolynomial for WeightToFee { + type Balance = Balance; + fn polynomial() -> WeightToFeeCoefficients { + const CENTS: Balance = 1_000_000_000_000 / 30_000; + // in Kusama, extrinsic base weight (smallest non-zero weight) is mapped to 1/10 CENT: + let p = CENTS; + let q = 10 * Balance::from(ExtrinsicBaseWeight::get()); + smallvec::smallvec![WeightToFeeCoefficient { + degree: 1, + negative: false, + coeff_frac: Perbill::from_rational(p % q, q), + coeff_integer: p / q, + }] + } +} + // We use this to get the account on Kusama (target) which is derived from Polkadot's (source) // account. pub fn derive_account_from_polkadot_id(id: bp_runtime::SourceAccount) -> AccountId { diff --git a/bridges/primitives/chain-millau/src/lib.rs b/bridges/primitives/chain-millau/src/lib.rs index 34d59ce2ef9a0..cb732bccfa055 100644 --- a/bridges/primitives/chain-millau/src/lib.rs +++ b/bridges/primitives/chain-millau/src/lib.rs @@ -25,7 +25,7 @@ mod millau_hash; use bp_messages::{LaneId, MessageDetails, MessageNonce, UnrewardedRelayersState}; use bp_runtime::Chain; use frame_support::{ - weights::{constants::WEIGHT_PER_SECOND, DispatchClass, Weight}, + weights::{constants::WEIGHT_PER_SECOND, DispatchClass, IdentityFee, Weight}, Parameter, RuntimeDebug, }; use frame_system::limits; @@ -149,6 +149,9 @@ pub type AccountSigner = MultiSigner; /// Balance of an account. pub type Balance = u64; +/// Weight-to-Fee type used by Millau. +pub type WeightToFee = IdentityFee; + /// Millau chain. #[derive(RuntimeDebug)] pub struct Millau; diff --git a/bridges/primitives/chain-polkadot/Cargo.toml b/bridges/primitives/chain-polkadot/Cargo.toml index 22ded41b9145c..4d3be2ae477d7 100644 --- a/bridges/primitives/chain-polkadot/Cargo.toml +++ b/bridges/primitives/chain-polkadot/Cargo.toml @@ -7,14 +7,17 @@ edition = "2018" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" [dependencies] +smallvec = "1.6" # Bridge Dependencies + bp-messages = { path = "../messages", default-features = false } bp-polkadot-core = { path = "../polkadot-core", default-features = false } bp-runtime = { path = "../runtime", default-features = false } # Substrate Based Dependencies +frame-support = { git = "https://github.com/paritytech/substrate", branch = "master" , default-features = false } sp-api = { git = "https://github.com/paritytech/substrate", branch = "master" , default-features = false } sp-std = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } @@ -24,6 +27,7 @@ std = [ "bp-messages/std", "bp-polkadot-core/std", "bp-runtime/std", + "frame-support/std", "sp-api/std", "sp-std/std", ] diff --git a/bridges/primitives/chain-polkadot/src/lib.rs b/bridges/primitives/chain-polkadot/src/lib.rs index b0ba77c66ffc3..17c80e82b22c2 100644 --- a/bridges/primitives/chain-polkadot/src/lib.rs +++ b/bridges/primitives/chain-polkadot/src/lib.rs @@ -21,6 +21,7 @@ #![allow(clippy::unnecessary_mut_passed)] use bp_messages::{LaneId, MessageDetails, MessageNonce, UnrewardedRelayersState}; +use frame_support::weights::{WeightToFeeCoefficient, WeightToFeeCoefficients, WeightToFeePolynomial}; use sp_std::prelude::*; pub use bp_polkadot_core::*; @@ -28,6 +29,24 @@ pub use bp_polkadot_core::*; /// Polkadot Chain pub type Polkadot = PolkadotLike; +// NOTE: This needs to be kept up to date with the Polkadot runtime found in the Polkadot repo. +pub struct WeightToFee; +impl WeightToFeePolynomial for WeightToFee { + type Balance = Balance; + fn polynomial() -> WeightToFeeCoefficients { + const CENTS: Balance = 10_000_000_000 / 100; + // in Polkadot, extrinsic base weight (smallest non-zero weight) is mapped to 1/10 CENT: + let p = CENTS; + let q = 10 * Balance::from(ExtrinsicBaseWeight::get()); + smallvec::smallvec![WeightToFeeCoefficient { + degree: 1, + negative: false, + coeff_frac: Perbill::from_rational(p % q, q), + coeff_integer: p / q, + }] + } +} + // We use this to get the account on Polkadot (target) which is derived from Kusama's (source) // account. pub fn derive_account_from_kusama_id(id: bp_runtime::SourceAccount) -> AccountId { diff --git a/bridges/primitives/chain-rialto/src/lib.rs b/bridges/primitives/chain-rialto/src/lib.rs index 57fe5d4bfa542..3c57b701b7166 100644 --- a/bridges/primitives/chain-rialto/src/lib.rs +++ b/bridges/primitives/chain-rialto/src/lib.rs @@ -23,7 +23,7 @@ use bp_messages::{LaneId, MessageDetails, MessageNonce, UnrewardedRelayersState}; use bp_runtime::Chain; use frame_support::{ - weights::{constants::WEIGHT_PER_SECOND, DispatchClass, Weight}, + weights::{constants::WEIGHT_PER_SECOND, DispatchClass, IdentityFee, Weight}, Parameter, RuntimeDebug, }; use frame_system::limits; @@ -148,6 +148,9 @@ pub type Balance = u128; /// An instant or duration in time. pub type Moment = u64; +/// Weight-to-Fee type used by Rialto. +pub type WeightToFee = IdentityFee; + /// Rialto chain. #[derive(RuntimeDebug)] pub struct Rialto; diff --git a/bridges/primitives/chain-rococo/src/lib.rs b/bridges/primitives/chain-rococo/src/lib.rs index 2d5769a39c2f3..ce58e7ec9ab02 100644 --- a/bridges/primitives/chain-rococo/src/lib.rs +++ b/bridges/primitives/chain-rococo/src/lib.rs @@ -21,7 +21,7 @@ #![allow(clippy::unnecessary_mut_passed)] use bp_messages::{LaneId, MessageDetails, MessageNonce, UnrewardedRelayersState}; -use frame_support::weights::{WeightToFeeCoefficient, WeightToFeeCoefficients, WeightToFeePolynomial}; +use frame_support::weights::{Weight, WeightToFeeCoefficient, WeightToFeeCoefficients, WeightToFeePolynomial}; use sp_std::prelude::*; use sp_version::RuntimeVersion; @@ -97,6 +97,13 @@ pub const FROM_ROCOCO_LATEST_CONFIRMED_NONCE_METHOD: &str = "FromRococoInboundLa /// Name of the `FromRococoInboundLaneApi::unrewarded_relayers_state` runtime method. pub const FROM_ROCOCO_UNREWARDED_RELAYERS_STATE: &str = "FromRococoInboundLaneApi_unrewarded_relayers_state"; +/// Weight of pay-dispatch-fee operation for inbound messages at Rococo chain. +/// +/// This value corresponds to the result of `pallet_bridge_messages::WeightInfoExt::pay_inbound_dispatch_fee_overhead()` +/// call for your chain. Don't put too much reserve there, because it is used to **decrease** +/// `DEFAULT_MESSAGE_DELIVERY_TX_WEIGHT` cost. So putting large reserve would make delivery transactions cheaper. +pub const PAY_INBOUND_DISPATCH_FEE_WEIGHT: Weight = 600_000_000; + sp_api::decl_runtime_apis! { /// API for querying information about the finalized Rococo headers. /// diff --git a/bridges/primitives/chain-westend/Cargo.toml b/bridges/primitives/chain-westend/Cargo.toml index 42a9e67a7174f..2fb8df091f557 100644 --- a/bridges/primitives/chain-westend/Cargo.toml +++ b/bridges/primitives/chain-westend/Cargo.toml @@ -8,14 +8,18 @@ license = "GPL-3.0-or-later WITH Classpath-exception-2.0" [dependencies] parity-scale-codec = { version = "2.2.0", default-features = false, features = ["derive"] } +smallvec = "1.6" # Bridge Dependencies + bp-header-chain = { path = "../header-chain", default-features = false } bp-messages = { path = "../messages", default-features = false } bp-polkadot-core = { path = "../polkadot-core", default-features = false } bp-runtime = { path = "../runtime", default-features = false } # Substrate Based Dependencies + +frame-support = { git = "https://github.com/paritytech/substrate", branch = "master" , default-features = false } sp-api = { git = "https://github.com/paritytech/substrate", branch = "master" , default-features = false } sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } sp-std = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } @@ -28,6 +32,7 @@ std = [ "bp-messages/std", "bp-polkadot-core/std", "bp-runtime/std", + "frame-support/std", "parity-scale-codec/std", "sp-api/std", "sp-runtime/std", diff --git a/bridges/primitives/chain-westend/src/lib.rs b/bridges/primitives/chain-westend/src/lib.rs index 4f8b9cccf4c75..595c41e443e59 100644 --- a/bridges/primitives/chain-westend/src/lib.rs +++ b/bridges/primitives/chain-westend/src/lib.rs @@ -22,6 +22,7 @@ use bp_messages::{LaneId, MessageDetails, MessageNonce, UnrewardedRelayersState}; use bp_runtime::Chain; +use frame_support::weights::{WeightToFeeCoefficient, WeightToFeeCoefficients, WeightToFeePolynomial}; use sp_std::prelude::*; use sp_version::RuntimeVersion; @@ -30,6 +31,24 @@ pub use bp_polkadot_core::*; /// Westend Chain pub type Westend = PolkadotLike; +// NOTE: This needs to be kept up to date with the Westend runtime found in the Polkadot repo. +pub struct WeightToFee; +impl WeightToFeePolynomial for WeightToFee { + type Balance = Balance; + fn polynomial() -> WeightToFeeCoefficients { + const CENTS: Balance = 1_000_000_000_000 / 1_000; + // in Westend, extrinsic base weight (smallest non-zero weight) is mapped to 1/10 CENT: + let p = CENTS; + let q = 10 * Balance::from(ExtrinsicBaseWeight::get()); + smallvec::smallvec![WeightToFeeCoefficient { + degree: 1, + negative: false, + coeff_frac: Perbill::from_rational(p % q, q), + coeff_integer: p / q, + }] + } +} + pub type UncheckedExtrinsic = bp_polkadot_core::UncheckedExtrinsic; // NOTE: This needs to be kept up to date with the Westend runtime found in the Polkadot repo. diff --git a/bridges/primitives/chain-wococo/src/lib.rs b/bridges/primitives/chain-wococo/src/lib.rs index b846e00321fd0..f962973d6c1c8 100644 --- a/bridges/primitives/chain-wococo/src/lib.rs +++ b/bridges/primitives/chain-wococo/src/lib.rs @@ -25,7 +25,7 @@ use sp_std::prelude::*; pub use bp_polkadot_core::*; // Rococo runtime = Wococo runtime -pub use bp_rococo::{WeightToFee, SESSION_LENGTH, VERSION}; +pub use bp_rococo::{WeightToFee, PAY_INBOUND_DISPATCH_FEE_WEIGHT, SESSION_LENGTH, VERSION}; /// Wococo Chain pub type Wococo = PolkadotLike; diff --git a/bridges/relays/bin-substrate/src/chains/millau_messages_to_rialto.rs b/bridges/relays/bin-substrate/src/chains/millau_messages_to_rialto.rs index 4195e452d9e0d..51eb4e961b68a 100644 --- a/bridges/relays/bin-substrate/src/chains/millau_messages_to_rialto.rs +++ b/bridges/relays/bin-substrate/src/chains/millau_messages_to_rialto.rs @@ -24,6 +24,7 @@ use sp_core::{Bytes, Pair}; use bp_messages::MessageNonce; use bridge_runtime_common::messages::target::FromBridgedChainMessagesProof; +use frame_support::weights::Weight; use messages_relay::message_lane::MessageLane; use relay_millau_client::{HeaderId as MillauHeaderId, Millau, SigningParams as MillauSigningParams}; use relay_rialto_client::{HeaderId as RialtoHeaderId, Rialto, SigningParams as RialtoSigningParams}; @@ -64,6 +65,8 @@ impl SubstrateMessageLane for MillauMessagesToRialto { const MESSAGE_PALLET_NAME_AT_SOURCE: &'static str = bp_millau::WITH_RIALTO_MESSAGES_PALLET_NAME; const MESSAGE_PALLET_NAME_AT_TARGET: &'static str = bp_rialto::WITH_MILLAU_MESSAGES_PALLET_NAME; + const PAY_INBOUND_DISPATCH_FEE_WEIGHT_AT_TARGET_CHAIN: Weight = bp_rialto::PAY_INBOUND_DISPATCH_FEE_WEIGHT; + type SourceChain = Millau; type TargetChain = Rialto; diff --git a/bridges/relays/bin-substrate/src/chains/rialto_messages_to_millau.rs b/bridges/relays/bin-substrate/src/chains/rialto_messages_to_millau.rs index 6fc7ee5b0828c..0ced49a0a3146 100644 --- a/bridges/relays/bin-substrate/src/chains/rialto_messages_to_millau.rs +++ b/bridges/relays/bin-substrate/src/chains/rialto_messages_to_millau.rs @@ -24,6 +24,7 @@ use sp_core::{Bytes, Pair}; use bp_messages::MessageNonce; use bridge_runtime_common::messages::target::FromBridgedChainMessagesProof; +use frame_support::weights::Weight; use messages_relay::message_lane::MessageLane; use relay_millau_client::{HeaderId as MillauHeaderId, Millau, SigningParams as MillauSigningParams}; use relay_rialto_client::{HeaderId as RialtoHeaderId, Rialto, SigningParams as RialtoSigningParams}; @@ -64,6 +65,8 @@ impl SubstrateMessageLane for RialtoMessagesToMillau { const MESSAGE_PALLET_NAME_AT_SOURCE: &'static str = bp_rialto::WITH_MILLAU_MESSAGES_PALLET_NAME; const MESSAGE_PALLET_NAME_AT_TARGET: &'static str = bp_millau::WITH_RIALTO_MESSAGES_PALLET_NAME; + const PAY_INBOUND_DISPATCH_FEE_WEIGHT_AT_TARGET_CHAIN: Weight = bp_millau::PAY_INBOUND_DISPATCH_FEE_WEIGHT; + type SourceChain = Rialto; type TargetChain = Millau; diff --git a/bridges/relays/bin-substrate/src/chains/rococo_messages_to_wococo.rs b/bridges/relays/bin-substrate/src/chains/rococo_messages_to_wococo.rs index 9fa06770523e9..51f89c0dbe6df 100644 --- a/bridges/relays/bin-substrate/src/chains/rococo_messages_to_wococo.rs +++ b/bridges/relays/bin-substrate/src/chains/rococo_messages_to_wococo.rs @@ -23,6 +23,7 @@ use sp_core::{Bytes, Pair}; use bp_messages::MessageNonce; use bridge_runtime_common::messages::target::FromBridgedChainMessagesProof; +use frame_support::weights::Weight; use messages_relay::message_lane::MessageLane; use relay_rococo_client::{HeaderId as RococoHeaderId, Rococo, SigningParams as RococoSigningParams}; use relay_substrate_client::{Chain, Client, TransactionSignScheme}; @@ -63,6 +64,8 @@ impl SubstrateMessageLane for RococoMessagesToWococo { const MESSAGE_PALLET_NAME_AT_SOURCE: &'static str = bp_rococo::WITH_WOCOCO_MESSAGES_PALLET_NAME; const MESSAGE_PALLET_NAME_AT_TARGET: &'static str = bp_wococo::WITH_ROCOCO_MESSAGES_PALLET_NAME; + const PAY_INBOUND_DISPATCH_FEE_WEIGHT_AT_TARGET_CHAIN: Weight = bp_wococo::PAY_INBOUND_DISPATCH_FEE_WEIGHT; + type SourceChain = Rococo; type TargetChain = Wococo; diff --git a/bridges/relays/bin-substrate/src/chains/wococo_messages_to_rococo.rs b/bridges/relays/bin-substrate/src/chains/wococo_messages_to_rococo.rs index 6e03d752f0003..9bc13dec1440d 100644 --- a/bridges/relays/bin-substrate/src/chains/wococo_messages_to_rococo.rs +++ b/bridges/relays/bin-substrate/src/chains/wococo_messages_to_rococo.rs @@ -23,6 +23,7 @@ use sp_core::{Bytes, Pair}; use bp_messages::MessageNonce; use bridge_runtime_common::messages::target::FromBridgedChainMessagesProof; +use frame_support::weights::Weight; use messages_relay::message_lane::MessageLane; use relay_rococo_client::{HeaderId as RococoHeaderId, Rococo, SigningParams as RococoSigningParams}; use relay_substrate_client::{Chain, Client, TransactionSignScheme}; @@ -62,6 +63,8 @@ impl SubstrateMessageLane for WococoMessagesToRococo { const MESSAGE_PALLET_NAME_AT_SOURCE: &'static str = bp_wococo::WITH_ROCOCO_MESSAGES_PALLET_NAME; const MESSAGE_PALLET_NAME_AT_TARGET: &'static str = bp_rococo::WITH_WOCOCO_MESSAGES_PALLET_NAME; + const PAY_INBOUND_DISPATCH_FEE_WEIGHT_AT_TARGET_CHAIN: Weight = bp_rococo::PAY_INBOUND_DISPATCH_FEE_WEIGHT; + type SourceChain = Wococo; type TargetChain = Rococo; diff --git a/bridges/relays/bin-substrate/src/cli/send_message.rs b/bridges/relays/bin-substrate/src/cli/send_message.rs index 75c3118eb49f2..5ab6b84c32df5 100644 --- a/bridges/relays/bin-substrate/src/cli/send_message.rs +++ b/bridges/relays/bin-substrate/src/cli/send_message.rs @@ -190,8 +190,9 @@ impl SendMessage { log::info!( target: "bridge", - "Sending message to {}. Size: {}. Dispatch weight: {}. Fee: {}", + "Sending message to {}. Lane: {:?}. Size: {}. Dispatch weight: {}. Fee: {}", Target::NAME, + lane, signed_source_call.len(), dispatch_weight, fee, diff --git a/bridges/relays/client-kusama/src/lib.rs b/bridges/relays/client-kusama/src/lib.rs index 01869fb7b1c4b..0c94e73aecff6 100644 --- a/bridges/relays/client-kusama/src/lib.rs +++ b/bridges/relays/client-kusama/src/lib.rs @@ -44,6 +44,7 @@ impl Chain for Kusama { type SignedBlock = bp_kusama::SignedBlock; type Call = (); type Balance = bp_kusama::Balance; + type WeightToFee = bp_kusama::WeightToFee; } /// Kusama header type used in headers sync. diff --git a/bridges/relays/client-millau/src/lib.rs b/bridges/relays/client-millau/src/lib.rs index ce1ab870141f5..36430dd83dc21 100644 --- a/bridges/relays/client-millau/src/lib.rs +++ b/bridges/relays/client-millau/src/lib.rs @@ -47,6 +47,7 @@ impl Chain for Millau { type SignedBlock = millau_runtime::SignedBlock; type Call = millau_runtime::Call; type Balance = millau_runtime::Balance; + type WeightToFee = bp_millau::WeightToFee; } impl ChainWithBalances for Millau { diff --git a/bridges/relays/client-polkadot/src/lib.rs b/bridges/relays/client-polkadot/src/lib.rs index 04ddce29d091d..dc5564cc17bb5 100644 --- a/bridges/relays/client-polkadot/src/lib.rs +++ b/bridges/relays/client-polkadot/src/lib.rs @@ -44,6 +44,7 @@ impl Chain for Polkadot { type SignedBlock = bp_polkadot::SignedBlock; type Call = (); type Balance = bp_polkadot::Balance; + type WeightToFee = bp_polkadot::WeightToFee; } /// Polkadot header type used in headers sync. diff --git a/bridges/relays/client-rialto/src/lib.rs b/bridges/relays/client-rialto/src/lib.rs index aaa62eea0e7f3..8024ab1fdce56 100644 --- a/bridges/relays/client-rialto/src/lib.rs +++ b/bridges/relays/client-rialto/src/lib.rs @@ -47,6 +47,7 @@ impl Chain for Rialto { type SignedBlock = rialto_runtime::SignedBlock; type Call = rialto_runtime::Call; type Balance = rialto_runtime::Balance; + type WeightToFee = bp_rialto::WeightToFee; } impl ChainWithBalances for Rialto { diff --git a/bridges/relays/client-rococo/src/lib.rs b/bridges/relays/client-rococo/src/lib.rs index 25c10999c66a5..c419610dad05c 100644 --- a/bridges/relays/client-rococo/src/lib.rs +++ b/bridges/relays/client-rococo/src/lib.rs @@ -52,6 +52,7 @@ impl Chain for Rococo { type SignedBlock = bp_rococo::SignedBlock; type Call = crate::runtime::Call; type Balance = bp_rococo::Balance; + type WeightToFee = bp_rococo::WeightToFee; } impl ChainWithBalances for Rococo { diff --git a/bridges/relays/client-substrate/src/chain.rs b/bridges/relays/client-substrate/src/chain.rs index 7bc5f711f0605..81397e2c4ae30 100644 --- a/bridges/relays/client-substrate/src/chain.rs +++ b/bridges/relays/client-substrate/src/chain.rs @@ -15,7 +15,7 @@ // along with Parity Bridges Common. If not, see . use bp_runtime::Chain as ChainBase; -use frame_support::Parameter; +use frame_support::{weights::WeightToFeePolynomial, Parameter}; use jsonrpsee_ws_client::{DeserializeOwned, Serialize}; use num_traits::{Bounded, CheckedSub, SaturatingAdd, Zero}; use sp_core::{storage::StorageKey, Pair}; @@ -77,12 +77,17 @@ pub trait Chain: ChainBase + Clone { + SaturatingAdd + Zero + std::convert::TryFrom; + + /// Type that is used by the chain, to convert from weight to fee. + type WeightToFee: WeightToFeePolynomial; } /// Balance type used by the chain pub type BalanceOf = ::Balance; /// Index type used by the chain pub type IndexOf = ::Index; +/// Weight-to-Fee type used by the chain +pub type WeightToFeeOf = ::WeightToFee; /// Substrate-based chain with `frame_system::Config::AccountData` set to /// the `pallet_balances::AccountData`. diff --git a/bridges/relays/client-substrate/src/client.rs b/bridges/relays/client-substrate/src/client.rs index b63e7f30a6cc2..9fb778651b475 100644 --- a/bridges/relays/client-substrate/src/client.rs +++ b/bridges/relays/client-substrate/src/client.rs @@ -310,23 +310,24 @@ impl Client { } /// Estimate fee that will be spent on given extrinsic. - pub async fn estimate_extrinsic_fee(&self, transaction: Bytes) -> Result { + pub async fn estimate_extrinsic_fee(&self, transaction: Bytes) -> Result> { self.jsonrpsee_execute(move |client| async move { let fee_details = Substrate::::payment_query_fee_details(&*client, transaction, None).await?; let inclusion_fee = fee_details .inclusion_fee - .map(|inclusion_fee| { - InclusionFee { - base_fee: C::Balance::try_from(inclusion_fee.base_fee.into_u256()) - .unwrap_or_else(|_| C::Balance::max_value()), - len_fee: C::Balance::try_from(inclusion_fee.len_fee.into_u256()) - .unwrap_or_else(|_| C::Balance::max_value()), - adjusted_weight_fee: C::Balance::try_from(inclusion_fee.adjusted_weight_fee.into_u256()) - .unwrap_or_else(|_| C::Balance::max_value()), - } - .inclusion_fee() + .map(|inclusion_fee| InclusionFee { + base_fee: C::Balance::try_from(inclusion_fee.base_fee.into_u256()) + .unwrap_or_else(|_| C::Balance::max_value()), + len_fee: C::Balance::try_from(inclusion_fee.len_fee.into_u256()) + .unwrap_or_else(|_| C::Balance::max_value()), + adjusted_weight_fee: C::Balance::try_from(inclusion_fee.adjusted_weight_fee.into_u256()) + .unwrap_or_else(|_| C::Balance::max_value()), }) - .unwrap_or_else(Zero::zero); + .unwrap_or_else(|| InclusionFee { + base_fee: Zero::zero(), + len_fee: Zero::zero(), + adjusted_weight_fee: Zero::zero(), + }); Ok(inclusion_fee) }) .await diff --git a/bridges/relays/client-substrate/src/guard.rs b/bridges/relays/client-substrate/src/guard.rs index 37a7c2aa275c5..f7df7dbb05c5b 100644 --- a/bridges/relays/client-substrate/src/guard.rs +++ b/bridges/relays/client-substrate/src/guard.rs @@ -194,6 +194,7 @@ mod tests { sp_runtime::generic::SignedBlock>; type Call = (); type Balance = u32; + type WeightToFee = frame_support::weights::IdentityFee; } impl ChainWithBalances for TestChain { diff --git a/bridges/relays/client-substrate/src/lib.rs b/bridges/relays/client-substrate/src/lib.rs index 6aa319c036773..be1835df3227d 100644 --- a/bridges/relays/client-substrate/src/lib.rs +++ b/bridges/relays/client-substrate/src/lib.rs @@ -31,7 +31,9 @@ pub mod metrics; use std::time::Duration; -pub use crate::chain::{BalanceOf, BlockWithJustification, Chain, ChainWithBalances, IndexOf, TransactionSignScheme}; +pub use crate::chain::{ + BalanceOf, BlockWithJustification, Chain, ChainWithBalances, IndexOf, TransactionSignScheme, WeightToFeeOf, +}; pub use crate::client::{Client, JustificationsSubscription, OpaqueGrandpaAuthoritiesSet}; pub use crate::error::{Error, Result}; pub use crate::sync_header::SyncHeader; diff --git a/bridges/relays/client-westend/src/lib.rs b/bridges/relays/client-westend/src/lib.rs index fefab00c5615f..b33be7421cf44 100644 --- a/bridges/relays/client-westend/src/lib.rs +++ b/bridges/relays/client-westend/src/lib.rs @@ -50,6 +50,7 @@ impl Chain for Westend { type SignedBlock = bp_westend::SignedBlock; type Call = bp_westend::Call; type Balance = bp_westend::Balance; + type WeightToFee = bp_westend::WeightToFee; } impl ChainWithBalances for Westend { diff --git a/bridges/relays/client-wococo/src/lib.rs b/bridges/relays/client-wococo/src/lib.rs index 4b3bdd7d84d14..03cb4d71563f7 100644 --- a/bridges/relays/client-wococo/src/lib.rs +++ b/bridges/relays/client-wococo/src/lib.rs @@ -52,6 +52,7 @@ impl Chain for Wococo { type SignedBlock = bp_wococo::SignedBlock; type Call = crate::runtime::Call; type Balance = bp_wococo::Balance; + type WeightToFee = bp_wococo::WeightToFee; } impl ChainWithBalances for Wococo { diff --git a/bridges/relays/lib-substrate-relay/Cargo.toml b/bridges/relays/lib-substrate-relay/Cargo.toml index 8a341c45ad62e..7ab81b786b5d0 100644 --- a/bridges/relays/lib-substrate-relay/Cargo.toml +++ b/bridges/relays/lib-substrate-relay/Cargo.toml @@ -40,8 +40,9 @@ sp-finality-grandpa = { git = "https://github.com/paritytech/substrate", branch sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master" } [dev-dependencies] -relay-millau-client = { path = "../client-millau" } -relay-rialto-client = { path = "../client-rialto" } -bp-rialto = { path = "../../primitives/chain-rialto" } bp-millau = { path = "../../primitives/chain-millau" } +bp-rococo = { path = "../../primitives/chain-rococo" } +bp-wococo = { path = "../../primitives/chain-wococo" } +relay-rococo-client = { path = "../client-rococo" } +relay-wococo-client = { path = "../client-wococo" } rialto-runtime = { path = "../../bin/rialto/runtime" } diff --git a/bridges/relays/lib-substrate-relay/src/messages_lane.rs b/bridges/relays/lib-substrate-relay/src/messages_lane.rs index 0b648e8cc8329..4614a50883a02 100644 --- a/bridges/relays/lib-substrate-relay/src/messages_lane.rs +++ b/bridges/relays/lib-substrate-relay/src/messages_lane.rs @@ -88,6 +88,13 @@ pub trait SubstrateMessageLane: 'static + Clone + Send + Sync { /// Name of the messages pallet as it is declared in the `construct_runtime!()` at target chain. const MESSAGE_PALLET_NAME_AT_TARGET: &'static str; + /// Extra weight of the delivery transaction at the target chain, that is paid to cover + /// dispatch fee payment. + /// + /// If dispatch fee is paid at the source chain, then this weight is refunded by the + /// delivery transaction. + const PAY_INBOUND_DISPATCH_FEE_WEIGHT_AT_TARGET_CHAIN: Weight; + /// Source chain. type SourceChain: Chain; /// Target chain. diff --git a/bridges/relays/lib-substrate-relay/src/messages_source.rs b/bridges/relays/lib-substrate-relay/src/messages_source.rs index 9a98b9b1d48c3..d6e92d1e51c4f 100644 --- a/bridges/relays/lib-substrate-relay/src/messages_source.rs +++ b/bridges/relays/lib-substrate-relay/src/messages_source.rs @@ -24,7 +24,6 @@ use crate::on_demand_headers::OnDemandHeadersRelay; use async_trait::async_trait; use bp_messages::{LaneId, MessageNonce, UnrewardedRelayersState}; -use bp_runtime::messages::DispatchFeePayment; use bridge_runtime_common::messages::{ source::FromBridgedChainMessagesDeliveryProof, target::FromBridgedChainMessagesProof, }; @@ -43,7 +42,10 @@ use relay_substrate_client::{ }; use relay_utils::{relay_loop::Client as RelayClient, BlockNumberBase, HeaderId}; use sp_core::Bytes; -use sp_runtime::{traits::Header as HeaderT, DeserializeOwned}; +use sp_runtime::{ + traits::{AtLeast32BitUnsigned, Header as HeaderT}, + DeserializeOwned, +}; use std::ops::RangeInclusive; /// Intermediate message proof returned by the source Substrate node. Includes everything @@ -121,6 +123,7 @@ where >, ::TargetHeaderNumber: Decode, ::TargetHeaderHash: Decode, + ::SourceChainBalance: AtLeast32BitUnsigned, { async fn state(&self) -> Result, SubstrateError> { // we can't continue to deliver confirmations if source node is out of sync, because @@ -264,6 +267,7 @@ where prepare_dummy_messages_delivery_proof::(), )) .await + .map(|fee| fee.inclusion_fee()) .unwrap_or_else(|_| BalanceOf::::max_value()) } } @@ -397,7 +401,7 @@ fn make_message_details_map( dispatch_weight: details.dispatch_weight, size: details.size as _, reward: details.delivery_and_dispatch_fee, - dispatch_fee_payment: DispatchFeePayment::AtSourceChain, + dispatch_fee_payment: details.dispatch_fee_payment, }, ); expected_nonce = details.nonce + 1; @@ -411,12 +415,12 @@ fn make_message_details_map( mod tests { use super::*; use bp_runtime::messages::DispatchFeePayment; - use relay_millau_client::Millau; - use relay_rialto_client::Rialto; + use relay_rococo_client::Rococo; + use relay_wococo_client::Wococo; fn message_details_from_rpc( nonces: RangeInclusive, - ) -> Vec> { + ) -> Vec> { nonces .into_iter() .map(|nonce| bp_messages::MessageDetails { @@ -432,7 +436,7 @@ mod tests { #[test] fn make_message_details_map_succeeds_if_no_messages_are_missing() { assert_eq!( - make_message_details_map::(message_details_from_rpc(1..=3), 1..=3,).unwrap(), + make_message_details_map::(message_details_from_rpc(1..=3), 1..=3,).unwrap(), vec![ ( 1, @@ -470,7 +474,7 @@ mod tests { #[test] fn make_message_details_map_succeeds_if_head_messages_are_missing() { assert_eq!( - make_message_details_map::(message_details_from_rpc(2..=3), 1..=3,).unwrap(), + make_message_details_map::(message_details_from_rpc(2..=3), 1..=3,).unwrap(), vec![ ( 2, @@ -501,7 +505,7 @@ mod tests { let mut message_details_from_rpc = message_details_from_rpc(1..=3); message_details_from_rpc.remove(1); assert!(matches!( - make_message_details_map::(message_details_from_rpc, 1..=3,), + make_message_details_map::(message_details_from_rpc, 1..=3,), Err(SubstrateError::Custom(_)) )); } @@ -509,7 +513,7 @@ mod tests { #[test] fn make_message_details_map_fails_if_tail_messages_are_missing() { assert!(matches!( - make_message_details_map::(message_details_from_rpc(1..=2), 1..=3,), + make_message_details_map::(message_details_from_rpc(1..=2), 1..=3,), Err(SubstrateError::Custom(_)) )); } @@ -517,15 +521,15 @@ mod tests { #[test] fn make_message_details_map_fails_if_all_messages_are_missing() { assert!(matches!( - make_message_details_map::(vec![], 1..=3), + make_message_details_map::(vec![], 1..=3), Err(SubstrateError::Custom(_)) )); } #[test] fn prepare_dummy_messages_delivery_proof_works() { - let expected_minimal_size = Rialto::MAXIMAL_ENCODED_ACCOUNT_ID_SIZE + Millau::STORAGE_PROOF_OVERHEAD; - let dummy_proof = prepare_dummy_messages_delivery_proof::(); + let expected_minimal_size = Wococo::MAXIMAL_ENCODED_ACCOUNT_ID_SIZE + Rococo::STORAGE_PROOF_OVERHEAD; + let dummy_proof = prepare_dummy_messages_delivery_proof::(); assert!( dummy_proof.1.encode().len() as u32 > expected_minimal_size, "Expected proof size at least {}. Got: {}", diff --git a/bridges/relays/lib-substrate-relay/src/messages_target.rs b/bridges/relays/lib-substrate-relay/src/messages_target.rs index 8e460769156ad..20eb7a54b383d 100644 --- a/bridges/relays/lib-substrate-relay/src/messages_target.rs +++ b/bridges/relays/lib-substrate-relay/src/messages_target.rs @@ -29,7 +29,7 @@ use bridge_runtime_common::messages::{ source::FromBridgedChainMessagesDeliveryProof, target::FromBridgedChainMessagesProof, }; use codec::{Decode, Encode}; -use frame_support::weights::Weight; +use frame_support::weights::{Weight, WeightToFeePolynomial}; use messages_relay::message_lane::MessageLane; use messages_relay::{ message_lane::{SourceHeaderIdOf, TargetHeaderIdOf}, @@ -37,11 +37,11 @@ use messages_relay::{ }; use num_traits::{Bounded, Zero}; use relay_substrate_client::{ - BalanceOf, BlockNumberOf, Chain, Client, Error as SubstrateError, HashOf, HeaderOf, IndexOf, + BalanceOf, BlockNumberOf, Chain, Client, Error as SubstrateError, HashOf, HeaderOf, IndexOf, WeightToFeeOf, }; use relay_utils::{relay_loop::Client as RelayClient, BlockNumberBase, HeaderId}; use sp_core::Bytes; -use sp_runtime::{DeserializeOwned, FixedPointNumber, FixedU128}; +use sp_runtime::{traits::Saturating, DeserializeOwned, FixedPointNumber, FixedU128}; use std::{convert::TryFrom, ops::RangeInclusive}; /// Message receiving proof returned by the target Substrate node. @@ -118,7 +118,6 @@ where BlockNumberOf: Copy, HeaderOf: DeserializeOwned, BlockNumberOf: BlockNumberBase, - P::MessageLane: MessageLane< MessagesProof = SubstrateMessagesProof, MessagesReceivingProof = SubstrateMessagesReceivingProof, @@ -244,6 +243,7 @@ where async fn estimate_delivery_transaction_in_source_tokens( &self, nonces: RangeInclusive, + total_prepaid_nonces: MessageNonce, total_dispatch_weight: Weight, total_size: u32, ) -> Result<::SourceChainBalance, SubstrateError> { @@ -258,27 +258,88 @@ where P::SourceChain::NAME, )) })?; + + // Prepare 'dummy' delivery transaction - we only care about its length and dispatch weight. + let delivery_tx = self.lane.make_messages_delivery_transaction( + Zero::zero(), + HeaderId(Default::default(), Default::default()), + nonces.clone(), + prepare_dummy_messages_proof::(nonces.clone(), total_dispatch_weight, total_size), + ); + let delivery_tx_fee = self.client.estimate_extrinsic_fee(delivery_tx).await?; + let inclusion_fee_in_target_tokens = delivery_tx_fee.inclusion_fee(); + + // The pre-dispatch cost of delivery transaction includes additional fee to cover dispatch fee payment + // (Currency::transfer in regular deployment). But if message dispatch has already been paid + // at the Source chain, the delivery transaction will refund relayer with this additional cost. + // But `estimate_extrinsic_fee` obviously just returns pre-dispatch cost of the transaction. So + // if transaction delivers prepaid message, then it may happen that pre-dispatch cost is larger + // than reward and `Rational` relayer will refuse to deliver this message. + // + // The most obvious solution would be to deduct total weight of dispatch fee payments from the + // `total_dispatch_weight` and use regular `estimate_extrinsic_fee` call. But what if + // `total_dispatch_weight` is less than total dispatch fee payments weight? Weight is strictly + // positive, so we can't use this option. + // + // Instead we'll be directly using `WeightToFee` and `NextFeeMultiplier` of the Target chain. + // This requires more knowledge of the Target chain, but seems there's no better way to solve + // this now. + let expected_refund_in_target_tokens = if total_prepaid_nonces != 0 { + const WEIGHT_DIFFERENCE: Weight = 100; + + let larger_dispatch_weight = total_dispatch_weight.saturating_add(WEIGHT_DIFFERENCE); + let larger_delivery_tx_fee = self + .client + .estimate_extrinsic_fee(self.lane.make_messages_delivery_transaction( + Zero::zero(), + HeaderId(Default::default(), Default::default()), + nonces.clone(), + prepare_dummy_messages_proof::(nonces.clone(), larger_dispatch_weight, total_size), + )) + .await?; + + compute_prepaid_messages_refund::

( + total_prepaid_nonces, + compute_fee_multiplier::( + delivery_tx_fee.adjusted_weight_fee, + total_dispatch_weight, + larger_delivery_tx_fee.adjusted_weight_fee, + larger_dispatch_weight, + ), + ) + } else { + Zero::zero() + }; + + let delivery_fee_in_source_tokens = convert_target_tokens_to_source_tokens::( + FixedU128::from_float(conversion_rate), + inclusion_fee_in_target_tokens.saturating_sub(expected_refund_in_target_tokens), + ); + log::trace!( target: "bridge", - "Using conversion rate {} when converting from {} tokens to {} tokens", - conversion_rate, - P::TargetChain::NAME, - P::SourceChain::NAME, + "Estimated {} -> {} messages delivery transaction.\n\t\ + Total nonces: {:?}\n\t\ + Prepaid messages: {}\n\t\ + Total messages size: {}\n\t\ + Total messages dispatch weight: {}\n\t\ + Inclusion fee (in {1} tokens): {:?}\n\t\ + Expected refund (in {1} tokens): {:?}\n\t\ + {1} -> {0} conversion rate: {:?}\n\t\ + Expected delivery tx fee (in {0} tokens): {:?}", + P::SourceChain::NAME, + P::TargetChain::NAME, + nonces, + total_prepaid_nonces, + total_size, + total_dispatch_weight, + inclusion_fee_in_target_tokens, + expected_refund_in_target_tokens, + conversion_rate, + delivery_fee_in_source_tokens, ); - Ok( - convert_target_tokens_to_source_tokens::( - FixedU128::from_float(conversion_rate), - self.client - .estimate_extrinsic_fee(self.lane.make_messages_delivery_transaction( - Zero::zero(), - HeaderId(Default::default(), Default::default()), - nonces.clone(), - prepare_dummy_messages_proof::(nonces, total_dispatch_weight, total_size), - )) - .await - .unwrap_or_else(|_| ::Balance::max_value()), - ), - ) + + Ok(delivery_fee_in_source_tokens) } } @@ -316,17 +377,110 @@ where .unwrap_or_else(|_| SC::Balance::max_value()) } +/// Compute fee multiplier that is used by the chain, given couple of fees for transactions +/// that are only differ in dispatch weights. +/// +/// This function assumes that standard transaction payment pallet is used by the chain. +/// The only fee component that depends on dispatch weight is the `adjusted_weight_fee`. +/// +/// **WARNING**: this functions will only be accurate if weight-to-fee conversion function +/// is linear. For non-linear polynomials the error will grow with `weight_difference` growth. +/// So better to use smaller differences. +fn compute_fee_multiplier( + smaller_adjusted_weight_fee: BalanceOf, + smaller_tx_weight: Weight, + larger_adjusted_weight_fee: BalanceOf, + larger_tx_weight: Weight, +) -> FixedU128 { + let adjusted_weight_fee_difference = larger_adjusted_weight_fee.saturating_sub(smaller_adjusted_weight_fee); + let smaller_tx_unadjusted_weight_fee = WeightToFeeOf::::calc(&smaller_tx_weight); + let larger_tx_unadjusted_weight_fee = WeightToFeeOf::::calc(&larger_tx_weight); + FixedU128::saturating_from_rational( + adjusted_weight_fee_difference, + larger_tx_unadjusted_weight_fee.saturating_sub(smaller_tx_unadjusted_weight_fee), + ) +} + +/// Compute fee that will be refunded to the relayer because dispatch of `total_prepaid_nonces` +/// messages has been paid at the source chain. +fn compute_prepaid_messages_refund( + total_prepaid_nonces: MessageNonce, + fee_multiplier: FixedU128, +) -> BalanceOf { + fee_multiplier.saturating_mul_int(WeightToFeeOf::::calc( + &P::PAY_INBOUND_DISPATCH_FEE_WEIGHT_AT_TARGET_CHAIN.saturating_mul(total_prepaid_nonces), + )) +} + #[cfg(test)] mod tests { use super::*; - use relay_millau_client::Millau; - use relay_rialto_client::Rialto; + use relay_rococo_client::{Rococo, SigningParams as RococoSigningParams}; + use relay_wococo_client::{SigningParams as WococoSigningParams, Wococo}; + + #[derive(Clone)] + struct TestSubstrateMessageLane; + + impl SubstrateMessageLane for TestSubstrateMessageLane { + type MessageLane = crate::messages_lane::SubstrateMessageLaneToSubstrate< + Rococo, + RococoSigningParams, + Wococo, + WococoSigningParams, + >; + + const OUTBOUND_LANE_MESSAGE_DETAILS_METHOD: &'static str = ""; + const OUTBOUND_LANE_LATEST_GENERATED_NONCE_METHOD: &'static str = ""; + const OUTBOUND_LANE_LATEST_RECEIVED_NONCE_METHOD: &'static str = ""; + + const INBOUND_LANE_LATEST_RECEIVED_NONCE_METHOD: &'static str = ""; + const INBOUND_LANE_LATEST_CONFIRMED_NONCE_METHOD: &'static str = ""; + const INBOUND_LANE_UNREWARDED_RELAYERS_STATE: &'static str = ""; + + const BEST_FINALIZED_SOURCE_HEADER_ID_AT_TARGET: &'static str = ""; + const BEST_FINALIZED_TARGET_HEADER_ID_AT_SOURCE: &'static str = ""; + + const MESSAGE_PALLET_NAME_AT_SOURCE: &'static str = ""; + const MESSAGE_PALLET_NAME_AT_TARGET: &'static str = ""; + + const PAY_INBOUND_DISPATCH_FEE_WEIGHT_AT_TARGET_CHAIN: Weight = 100_000; + + type SourceChain = Rococo; + type TargetChain = Wococo; + + fn source_transactions_author(&self) -> bp_rococo::AccountId { + unreachable!() + } + + fn make_messages_receiving_proof_transaction( + &self, + _transaction_nonce: ::Index, + _generated_at_block: TargetHeaderIdOf, + _proof: ::MessagesReceivingProof, + ) -> Bytes { + unreachable!() + } + + fn target_transactions_author(&self) -> bp_wococo::AccountId { + unreachable!() + } + + fn make_messages_delivery_transaction( + &self, + _transaction_nonce: ::Index, + _generated_at_header: SourceHeaderIdOf, + _nonces: RangeInclusive, + _proof: ::MessagesProof, + ) -> Bytes { + unreachable!() + } + } #[test] fn prepare_dummy_messages_proof_works() { const DISPATCH_WEIGHT: Weight = 1_000_000; const SIZE: u32 = 1_000; - let dummy_proof = prepare_dummy_messages_proof::(1..=10, DISPATCH_WEIGHT, SIZE); + let dummy_proof = prepare_dummy_messages_proof::(1..=10, DISPATCH_WEIGHT, SIZE); assert_eq!(dummy_proof.0, DISPATCH_WEIGHT); assert!( dummy_proof.1.encode().len() as u32 > SIZE, @@ -339,16 +493,47 @@ mod tests { #[test] fn convert_target_tokens_to_source_tokens_works() { assert_eq!( - convert_target_tokens_to_source_tokens::((150, 100).into(), 1_000), + convert_target_tokens_to_source_tokens::((150, 100).into(), 1_000), 1_500 ); assert_eq!( - convert_target_tokens_to_source_tokens::((50, 100).into(), 1_000), + convert_target_tokens_to_source_tokens::((50, 100).into(), 1_000), 500 ); assert_eq!( - convert_target_tokens_to_source_tokens::((100, 100).into(), 1_000), + convert_target_tokens_to_source_tokens::((100, 100).into(), 1_000), 1_000 ); } + + #[test] + fn compute_fee_multiplier_returns_sane_results() { + let multiplier = FixedU128::saturating_from_rational(1, 1000); + + let smaller_weight = 1_000_000; + let smaller_adjusted_weight_fee = multiplier.saturating_mul_int(WeightToFeeOf::::calc(&smaller_weight)); + + let larger_weight = smaller_weight + 200_000; + let larger_adjusted_weight_fee = multiplier.saturating_mul_int(WeightToFeeOf::::calc(&larger_weight)); + + assert_eq!( + compute_fee_multiplier::( + smaller_adjusted_weight_fee, + smaller_weight, + larger_adjusted_weight_fee, + larger_weight, + ), + multiplier, + ); + } + + #[test] + fn compute_prepaid_messages_refund_returns_sane_results() { + assert!( + compute_prepaid_messages_refund::( + 10, + FixedU128::saturating_from_rational(110, 100), + ) > (10 * TestSubstrateMessageLane::PAY_INBOUND_DISPATCH_FEE_WEIGHT_AT_TARGET_CHAIN).into() + ); + } } diff --git a/bridges/relays/lib-substrate-relay/src/on_demand_headers.rs b/bridges/relays/lib-substrate-relay/src/on_demand_headers.rs index 2f8441dbfc986..8973d4fe3ec08 100644 --- a/bridges/relays/lib-substrate-relay/src/on_demand_headers.rs +++ b/bridges/relays/lib-substrate-relay/src/on_demand_headers.rs @@ -420,10 +420,10 @@ fn on_demand_headers_relay_name() -> Str mod tests { use super::*; - type TestChain = relay_millau_client::Millau; + type TestChain = relay_rococo_client::Rococo; - const AT_SOURCE: Option = Some(10); - const AT_TARGET: Option = Some(1); + const AT_SOURCE: Option = Some(10); + const AT_TARGET: Option = Some(1); #[async_std::test] async fn mandatory_headers_scan_range_selects_range_if_too_many_headers_are_missing() { diff --git a/bridges/relays/messages/src/message_lane_loop.rs b/bridges/relays/messages/src/message_lane_loop.rs index 84b0c72408dfa..049b6e7b5f799 100644 --- a/bridges/relays/messages/src/message_lane_loop.rs +++ b/bridges/relays/messages/src/message_lane_loop.rs @@ -210,6 +210,7 @@ pub trait TargetClient: RelayClient { async fn estimate_delivery_transaction_in_source_tokens( &self, nonces: RangeInclusive, + total_prepaid_nonces: MessageNonce, total_dispatch_weight: Weight, total_size: u32, ) -> Result; @@ -773,6 +774,7 @@ pub(crate) mod tests { async fn estimate_delivery_transaction_in_source_tokens( &self, nonces: RangeInclusive, + _total_prepaid_nonces: MessageNonce, total_dispatch_weight: Weight, total_size: u32, ) -> Result { diff --git a/bridges/relays/messages/src/message_race_delivery.rs b/bridges/relays/messages/src/message_race_delivery.rs index 2e94bbee8b1c4..8a5f8d7df260d 100644 --- a/bridges/relays/messages/src/message_race_delivery.rs +++ b/bridges/relays/messages/src/message_race_delivery.rs @@ -561,6 +561,7 @@ async fn select_nonces_for_delivery_transaction( let mut selected_weight: Weight = 0; let mut selected_unpaid_weight: Weight = 0; + let mut selected_prepaid_nonces = 0; let mut selected_size: u32 = 0; let mut selected_count: MessageNonce = 0; let mut selected_reward = P::SourceChainBalance::zero(); @@ -570,6 +571,8 @@ async fn select_nonces_for_delivery_transaction( let mut total_confirmations_cost = P::SourceChainBalance::zero(); let mut total_cost = P::SourceChainBalance::zero(); + let hard_selected_begin_nonce = nonces_queue[nonces_queue_range.start].1.begin(); + // technically, multiple confirmations will be delivered in a single transaction, // meaning less loses for relayer. But here we don't know the final relayer yet, so // we're adding a separate transaction for every message. Normally, this cost is covered @@ -637,8 +640,12 @@ async fn select_nonces_for_delivery_transaction( // dispatch origin account AND reward is not covering this fee. // // So in the latter case we're not adding the dispatch weight to the delivery transaction weight. + let mut new_selected_prepaid_nonces = selected_prepaid_nonces; let new_selected_unpaid_weight = match details.dispatch_fee_payment { - DispatchFeePayment::AtSourceChain => selected_unpaid_weight.saturating_add(details.dispatch_weight), + DispatchFeePayment::AtSourceChain => { + new_selected_prepaid_nonces += 1; + selected_unpaid_weight.saturating_add(details.dispatch_weight) + } DispatchFeePayment::AtTargetChain => selected_unpaid_weight, }; @@ -651,7 +658,8 @@ async fn select_nonces_for_delivery_transaction( RelayerMode::Rational => { let delivery_transaction_cost = lane_target_client .estimate_delivery_transaction_in_source_tokens( - 0..=(new_selected_count as MessageNonce - 1), + hard_selected_begin_nonce..=(hard_selected_begin_nonce + index as MessageNonce), + new_selected_prepaid_nonces, new_selected_unpaid_weight, new_selected_size as u32, ) @@ -711,11 +719,11 @@ async fn select_nonces_for_delivery_transaction( hard_selected_count = index + 1; selected_weight = new_selected_weight; selected_unpaid_weight = new_selected_unpaid_weight; + selected_prepaid_nonces = new_selected_prepaid_nonces; selected_size = new_selected_size; selected_count = new_selected_count; } - let hard_selected_begin_nonce = nonces_queue[nonces_queue_range.start].1.begin(); if hard_selected_count != soft_selected_count { let hard_selected_end_nonce = hard_selected_begin_nonce + hard_selected_count as MessageNonce - 1; let soft_selected_begin_nonce = hard_selected_begin_nonce;