From c4d3cea10ee642c02cf5e5512c4b770742a503d7 Mon Sep 17 00:00:00 2001 From: Svyatoslav Nikolsky Date: Mon, 25 Oct 2021 13:24:48 +0300 Subject: [PATCH] Message transactions mortality (#1191) * transactions mortality in message and complex relays * logging + enable in test deployments * spellcheck * fmt --- bridges/primitives/runtime/src/lib.rs | 19 ++++++----- .../src/chains/kusama_messages_to_polkadot.rs | 32 +++++++++++++++--- .../src/chains/millau_messages_to_rialto.rs | 32 +++++++++++++++--- .../src/chains/polkadot_messages_to_kusama.rs | 32 +++++++++++++++--- .../src/chains/rialto_messages_to_millau.rs | 32 +++++++++++++++--- .../src/chains/rococo_messages_to_wococo.rs | 32 +++++++++++++++--- .../src/chains/wococo_messages_to_rococo.rs | 32 +++++++++++++++--- .../src/cli/relay_headers_and_messages.rs | 4 +++ .../bin-substrate/src/cli/relay_messages.rs | 4 +++ bridges/relays/client-substrate/src/lib.rs | 33 +++++++++++++++++-- bridges/relays/lib-substrate-relay/Cargo.toml | 1 - .../src/finality_pipeline.rs | 16 +++------ .../src/finality_target.rs | 3 +- bridges/relays/lib-substrate-relay/src/lib.rs | 11 +++++++ .../lib-substrate-relay/src/messages_lane.rs | 12 +++++++ .../src/messages_source.rs | 4 ++- .../src/messages_target.rs | 7 +++- .../src/on_demand_headers.rs | 2 +- bridges/relays/utils/Cargo.toml | 4 +++ bridges/relays/utils/src/lib.rs | 5 +-- 20 files changed, 253 insertions(+), 64 deletions(-) diff --git a/bridges/primitives/runtime/src/lib.rs b/bridges/primitives/runtime/src/lib.rs index 9ee15df1a9839..460f1b19dfe3f 100644 --- a/bridges/primitives/runtime/src/lib.rs +++ b/bridges/primitives/runtime/src/lib.rs @@ -69,6 +69,10 @@ pub const ACCOUNT_DERIVATION_PREFIX: &[u8] = b"pallet-bridge/account-derivation/ /// A unique prefix for entropy when generating a cross-chain account ID for the Root account. pub const ROOT_ACCOUNT_DERIVATION_PREFIX: &[u8] = b"pallet-bridge/account-derivation/root"; +/// Generic header Id. +#[derive(RuntimeDebug, Default, Clone, Copy, Eq, Hash, PartialEq)] +pub struct HeaderId(pub Number, pub Hash); + /// Unique identifier of the chain. /// /// In addition to its main function (identifying the chain), this type may also be used to @@ -159,20 +163,17 @@ pub enum TransactionEra { /// Transaction is immortal. Immortal, /// Transaction is valid for a given number of blocks, starting from given block. - Mortal(BlockNumber, BlockHash, u32), + Mortal(HeaderId, u32), } impl, BlockHash: Copy> TransactionEra { /// Prepare transaction era, based on mortality period and current best block number. pub fn new( - best_block_number: BlockNumber, - best_block_hash: BlockHash, + best_block_id: HeaderId, mortality_period: Option, ) -> Self { mortality_period - .map(|mortality_period| { - TransactionEra::Mortal(best_block_number, best_block_hash, mortality_period) - }) + .map(|mortality_period| TransactionEra::Mortal(best_block_id, mortality_period)) .unwrap_or(TransactionEra::Immortal) } @@ -185,8 +186,8 @@ impl, BlockHash: Copy> TransactionEra sp_runtime::generic::Era { match *self { TransactionEra::Immortal => sp_runtime::generic::Era::immortal(), - TransactionEra::Mortal(header_number, _, period) => - sp_runtime::generic::Era::mortal(period as _, header_number.into()), + TransactionEra::Mortal(header_id, period) => + sp_runtime::generic::Era::mortal(period as _, header_id.0.into()), } } @@ -194,7 +195,7 @@ impl, BlockHash: Copy> TransactionEra BlockHash { match *self { TransactionEra::Immortal => genesis_hash, - TransactionEra::Mortal(_, header_hash, _) => header_hash, + TransactionEra::Mortal(header_id, _) => header_id.1, } } } diff --git a/bridges/relays/bin-substrate/src/chains/kusama_messages_to_polkadot.rs b/bridges/relays/bin-substrate/src/chains/kusama_messages_to_polkadot.rs index 40e03ef266847..86e2e22cd9094 100644 --- a/bridges/relays/bin-substrate/src/chains/kusama_messages_to_polkadot.rs +++ b/bridges/relays/bin-substrate/src/chains/kusama_messages_to_polkadot.rs @@ -16,7 +16,7 @@ //! Kusama-to-Polkadot messages sync entrypoint. -use std::{ops::RangeInclusive, time::Duration}; +use std::ops::RangeInclusive; use codec::Encode; use sp_core::{Bytes, Pair}; @@ -41,6 +41,7 @@ use substrate_relay_helper::{ }, messages_source::SubstrateMessagesSource, messages_target::SubstrateMessagesTarget, + STALL_TIMEOUT, }; /// Kusama-to-Polkadot message lane. @@ -91,6 +92,7 @@ impl SubstrateMessageLane for KusamaMessagesToPolkadot { fn make_messages_receiving_proof_transaction( &self, + best_block_id: KusamaHeaderId, transaction_nonce: bp_runtime::IndexOf, _generated_at_block: PolkadotHeaderId, proof: ::MessagesReceivingProof, @@ -106,7 +108,10 @@ impl SubstrateMessageLane for KusamaMessagesToPolkadot { let transaction = Kusama::sign_transaction( genesis_hash, &self.message_lane.source_sign, - relay_substrate_client::TransactionEra::immortal(), + relay_substrate_client::TransactionEra::new( + best_block_id, + self.message_lane.source_transactions_mortality, + ), UnsignedTransaction::new(call, transaction_nonce), ); log::trace!( @@ -125,6 +130,7 @@ impl SubstrateMessageLane for KusamaMessagesToPolkadot { fn make_messages_delivery_transaction( &self, + best_block_id: PolkadotHeaderId, transaction_nonce: bp_runtime::IndexOf, _generated_at_header: KusamaHeaderId, _nonces: RangeInclusive, @@ -146,7 +152,10 @@ impl SubstrateMessageLane for KusamaMessagesToPolkadot { let transaction = Polkadot::sign_transaction( genesis_hash, &self.message_lane.target_sign, - relay_substrate_client::TransactionEra::immortal(), + relay_substrate_client::TransactionEra::new( + best_block_id, + self.message_lane.target_transactions_mortality, + ), UnsignedTransaction::new(call, transaction_nonce), ); log::trace!( @@ -170,7 +179,13 @@ type PolkadotTargetClient = SubstrateMessagesTarget; pub async fn run( params: MessagesRelayParams, ) -> anyhow::Result<()> { - let stall_timeout = Duration::from_secs(5 * 60); + let stall_timeout = relay_substrate_client::bidirectional_transaction_stall_timeout( + params.source_transactions_mortality, + params.target_transactions_mortality, + Kusama::AVERAGE_BLOCK_INTERVAL, + Polkadot::AVERAGE_BLOCK_INTERVAL, + STALL_TIMEOUT, + ); let relayer_id_at_kusama = (*params.source_sign.public().as_array_ref()).into(); let lane_id = params.lane_id; @@ -179,8 +194,10 @@ pub async fn run( message_lane: SubstrateMessageLaneToSubstrate { source_client: source_client.clone(), source_sign: params.source_sign, + source_transactions_mortality: params.source_transactions_mortality, target_client: params.target_client.clone(), target_sign: params.target_sign, + target_transactions_mortality: params.target_transactions_mortality, relayer_id_at_source: relayer_id_at_kusama, }, }; @@ -206,12 +223,17 @@ pub async fn run( Max messages in single transaction: {}\n\t\ Max messages size in single transaction: {}\n\t\ Max messages weight in single transaction: {}\n\t\ - Relayer mode: {:?}", + Relayer mode: {:?}\n\t\ + Tx mortality: {:?}/{:?}\n\t\ + Stall timeout: {:?}", lane.message_lane.relayer_id_at_source, max_messages_in_single_batch, max_messages_size_in_single_batch, max_messages_weight_in_single_batch, params.relayer_mode, + params.source_transactions_mortality, + params.target_transactions_mortality, + stall_timeout, ); let (metrics_params, metrics_values) = add_standalone_metrics( 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 612fd96d0fcaa..570a3449752b3 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 @@ -16,7 +16,7 @@ //! Millau-to-Rialto messages sync entrypoint. -use std::{ops::RangeInclusive, time::Duration}; +use std::ops::RangeInclusive; use codec::Encode; use frame_support::dispatch::GetDispatchInfo; @@ -41,6 +41,7 @@ use substrate_relay_helper::{ }, messages_source::SubstrateMessagesSource, messages_target::SubstrateMessagesTarget, + STALL_TIMEOUT, }; /// Millau-to-Rialto message lane. @@ -89,6 +90,7 @@ impl SubstrateMessageLane for MillauMessagesToRialto { fn make_messages_receiving_proof_transaction( &self, + best_block_id: MillauHeaderId, transaction_nonce: IndexOf, _generated_at_block: RialtoHeaderId, proof: ::MessagesReceivingProof, @@ -102,7 +104,10 @@ impl SubstrateMessageLane for MillauMessagesToRialto { let transaction = Millau::sign_transaction( genesis_hash, &self.message_lane.source_sign, - relay_substrate_client::TransactionEra::immortal(), + relay_substrate_client::TransactionEra::new( + best_block_id, + self.message_lane.source_transactions_mortality, + ), UnsignedTransaction::new(call, transaction_nonce), ); log::trace!( @@ -122,6 +127,7 @@ impl SubstrateMessageLane for MillauMessagesToRialto { fn make_messages_delivery_transaction( &self, + best_block_id: RialtoHeaderId, transaction_nonce: IndexOf, _generated_at_header: MillauHeaderId, _nonces: RangeInclusive, @@ -142,7 +148,10 @@ impl SubstrateMessageLane for MillauMessagesToRialto { let transaction = Rialto::sign_transaction( genesis_hash, &self.message_lane.target_sign, - relay_substrate_client::TransactionEra::immortal(), + relay_substrate_client::TransactionEra::new( + best_block_id, + self.message_lane.target_transactions_mortality, + ), UnsignedTransaction::new(call, transaction_nonce), ); log::trace!( @@ -167,7 +176,13 @@ type RialtoTargetClient = SubstrateMessagesTarget; pub async fn run( params: MessagesRelayParams, ) -> anyhow::Result<()> { - let stall_timeout = Duration::from_secs(5 * 60); + let stall_timeout = relay_substrate_client::bidirectional_transaction_stall_timeout( + params.source_transactions_mortality, + params.target_transactions_mortality, + Millau::AVERAGE_BLOCK_INTERVAL, + Rialto::AVERAGE_BLOCK_INTERVAL, + STALL_TIMEOUT, + ); let relayer_id_at_millau = (*params.source_sign.public().as_array_ref()).into(); let lane_id = params.lane_id; @@ -176,8 +191,10 @@ pub async fn run( message_lane: SubstrateMessageLaneToSubstrate { source_client: source_client.clone(), source_sign: params.source_sign, + source_transactions_mortality: params.source_transactions_mortality, target_client: params.target_client.clone(), target_sign: params.target_sign, + target_transactions_mortality: params.target_transactions_mortality, relayer_id_at_source: relayer_id_at_millau, }, }; @@ -200,12 +217,17 @@ pub async fn run( Max messages in single transaction: {}\n\t\ Max messages size in single transaction: {}\n\t\ Max messages weight in single transaction: {}\n\t\ - Relayer mode: {:?}", + Relayer mode: {:?}\n\t\ + Tx mortality: {:?}/{:?}\n\t\ + Stall timeout: {:?}", lane.message_lane.relayer_id_at_source, max_messages_in_single_batch, max_messages_size_in_single_batch, max_messages_weight_in_single_batch, params.relayer_mode, + params.source_transactions_mortality, + params.target_transactions_mortality, + stall_timeout, ); let (metrics_params, metrics_values) = add_standalone_metrics( diff --git a/bridges/relays/bin-substrate/src/chains/polkadot_messages_to_kusama.rs b/bridges/relays/bin-substrate/src/chains/polkadot_messages_to_kusama.rs index 31e8b710e348e..8af62bc80b1f2 100644 --- a/bridges/relays/bin-substrate/src/chains/polkadot_messages_to_kusama.rs +++ b/bridges/relays/bin-substrate/src/chains/polkadot_messages_to_kusama.rs @@ -16,7 +16,7 @@ //! Polkadot-to-Kusama messages sync entrypoint. -use std::{ops::RangeInclusive, time::Duration}; +use std::ops::RangeInclusive; use codec::Encode; use sp_core::{Bytes, Pair}; @@ -41,6 +41,7 @@ use substrate_relay_helper::{ }, messages_source::SubstrateMessagesSource, messages_target::SubstrateMessagesTarget, + STALL_TIMEOUT, }; /// Polkadot-to-Kusama message lane. @@ -90,6 +91,7 @@ impl SubstrateMessageLane for PolkadotMessagesToKusama { fn make_messages_receiving_proof_transaction( &self, + best_block_id: PolkadotHeaderId, transaction_nonce: bp_runtime::IndexOf, _generated_at_block: KusamaHeaderId, proof: ::MessagesReceivingProof, @@ -105,7 +107,10 @@ impl SubstrateMessageLane for PolkadotMessagesToKusama { let transaction = Polkadot::sign_transaction( genesis_hash, &self.message_lane.source_sign, - relay_substrate_client::TransactionEra::immortal(), + relay_substrate_client::TransactionEra::new( + best_block_id, + self.message_lane.source_transactions_mortality, + ), UnsignedTransaction::new(call, transaction_nonce), ); log::trace!( @@ -124,6 +129,7 @@ impl SubstrateMessageLane for PolkadotMessagesToKusama { fn make_messages_delivery_transaction( &self, + best_block_id: KusamaHeaderId, transaction_nonce: bp_runtime::IndexOf, _generated_at_header: PolkadotHeaderId, _nonces: RangeInclusive, @@ -145,7 +151,10 @@ impl SubstrateMessageLane for PolkadotMessagesToKusama { let transaction = Kusama::sign_transaction( genesis_hash, &self.message_lane.target_sign, - relay_substrate_client::TransactionEra::immortal(), + relay_substrate_client::TransactionEra::new( + best_block_id, + self.message_lane.target_transactions_mortality, + ), UnsignedTransaction::new(call, transaction_nonce), ); log::trace!( @@ -169,7 +178,13 @@ type KusamaTargetClient = SubstrateMessagesTarget; pub async fn run( params: MessagesRelayParams, ) -> anyhow::Result<()> { - let stall_timeout = Duration::from_secs(5 * 60); + let stall_timeout = relay_substrate_client::bidirectional_transaction_stall_timeout( + params.source_transactions_mortality, + params.target_transactions_mortality, + Polkadot::AVERAGE_BLOCK_INTERVAL, + Kusama::AVERAGE_BLOCK_INTERVAL, + STALL_TIMEOUT, + ); let relayer_id_at_polkadot = (*params.source_sign.public().as_array_ref()).into(); let lane_id = params.lane_id; @@ -178,8 +193,10 @@ pub async fn run( message_lane: SubstrateMessageLaneToSubstrate { source_client: source_client.clone(), source_sign: params.source_sign, + source_transactions_mortality: params.source_transactions_mortality, target_client: params.target_client.clone(), target_sign: params.target_sign, + target_transactions_mortality: params.target_transactions_mortality, relayer_id_at_source: relayer_id_at_polkadot, }, }; @@ -205,12 +222,17 @@ pub async fn run( Max messages in single transaction: {}\n\t\ Max messages size in single transaction: {}\n\t\ Max messages weight in single transaction: {}\n\t\ - Relayer mode: {:?}", + Relayer mode: {:?}\n\t\ + Tx mortality: {:?}/{:?}\n\t\ + Stall timeout: {:?}", lane.message_lane.relayer_id_at_source, max_messages_in_single_batch, max_messages_size_in_single_batch, max_messages_weight_in_single_batch, params.relayer_mode, + params.source_transactions_mortality, + params.target_transactions_mortality, + stall_timeout, ); let (metrics_params, metrics_values) = add_standalone_metrics( 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 35f0852dcb67d..f85a5e760e631 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 @@ -16,7 +16,7 @@ //! Rialto-to-Millau messages sync entrypoint. -use std::{ops::RangeInclusive, time::Duration}; +use std::ops::RangeInclusive; use codec::Encode; use frame_support::dispatch::GetDispatchInfo; @@ -41,6 +41,7 @@ use substrate_relay_helper::{ }, messages_source::SubstrateMessagesSource, messages_target::SubstrateMessagesTarget, + STALL_TIMEOUT, }; /// Rialto-to-Millau message lane. @@ -89,6 +90,7 @@ impl SubstrateMessageLane for RialtoMessagesToMillau { fn make_messages_receiving_proof_transaction( &self, + best_block_id: RialtoHeaderId, transaction_nonce: IndexOf, _generated_at_block: MillauHeaderId, proof: ::MessagesReceivingProof, @@ -102,7 +104,10 @@ impl SubstrateMessageLane for RialtoMessagesToMillau { let transaction = Rialto::sign_transaction( genesis_hash, &self.message_lane.source_sign, - relay_substrate_client::TransactionEra::immortal(), + relay_substrate_client::TransactionEra::new( + best_block_id, + self.message_lane.source_transactions_mortality, + ), UnsignedTransaction::new(call, transaction_nonce), ); log::trace!( @@ -122,6 +127,7 @@ impl SubstrateMessageLane for RialtoMessagesToMillau { fn make_messages_delivery_transaction( &self, + best_block_id: MillauHeaderId, transaction_nonce: IndexOf, _generated_at_header: RialtoHeaderId, _nonces: RangeInclusive, @@ -142,7 +148,10 @@ impl SubstrateMessageLane for RialtoMessagesToMillau { let transaction = Millau::sign_transaction( genesis_hash, &self.message_lane.target_sign, - relay_substrate_client::TransactionEra::immortal(), + relay_substrate_client::TransactionEra::new( + best_block_id, + self.message_lane.target_transactions_mortality, + ), UnsignedTransaction::new(call, transaction_nonce), ); log::trace!( @@ -167,7 +176,13 @@ type MillauTargetClient = SubstrateMessagesTarget; pub async fn run( params: MessagesRelayParams, ) -> anyhow::Result<()> { - let stall_timeout = Duration::from_secs(5 * 60); + let stall_timeout = relay_substrate_client::bidirectional_transaction_stall_timeout( + params.source_transactions_mortality, + params.target_transactions_mortality, + Rialto::AVERAGE_BLOCK_INTERVAL, + Millau::AVERAGE_BLOCK_INTERVAL, + STALL_TIMEOUT, + ); let relayer_id_at_rialto = (*params.source_sign.public().as_array_ref()).into(); let lane_id = params.lane_id; @@ -176,8 +191,10 @@ pub async fn run( message_lane: SubstrateMessageLaneToSubstrate { source_client: source_client.clone(), source_sign: params.source_sign, + source_transactions_mortality: params.source_transactions_mortality, target_client: params.target_client.clone(), target_sign: params.target_sign, + target_transactions_mortality: params.target_transactions_mortality, relayer_id_at_source: relayer_id_at_rialto, }, }; @@ -199,12 +216,17 @@ pub async fn run( Max messages in single transaction: {}\n\t\ Max messages size in single transaction: {}\n\t\ Max messages weight in single transaction: {}\n\t\ - Relayer mode: {:?}", + Relayer mode: {:?}\n\t\ + Tx mortality: {:?}/{:?}\n\t\ + Stall timeout: {:?}", lane.message_lane.relayer_id_at_source, max_messages_in_single_batch, max_messages_size_in_single_batch, max_messages_weight_in_single_batch, params.relayer_mode, + params.source_transactions_mortality, + params.target_transactions_mortality, + stall_timeout, ); let (metrics_params, metrics_values) = add_standalone_metrics( 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 65eda19c6ef18..7f9a2eb98f0e0 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 @@ -16,7 +16,7 @@ //! Rococo-to-Wococo messages sync entrypoint. -use std::{ops::RangeInclusive, time::Duration}; +use std::ops::RangeInclusive; use codec::Encode; use sp_core::{Bytes, Pair}; @@ -40,6 +40,7 @@ use substrate_relay_helper::{ }, messages_source::SubstrateMessagesSource, messages_target::SubstrateMessagesTarget, + STALL_TIMEOUT, }; /// Rococo-to-Wococo message lane. @@ -88,6 +89,7 @@ impl SubstrateMessageLane for RococoMessagesToWococo { fn make_messages_receiving_proof_transaction( &self, + best_block_id: RococoHeaderId, transaction_nonce: IndexOf, _generated_at_block: WococoHeaderId, proof: ::MessagesReceivingProof, @@ -103,7 +105,10 @@ impl SubstrateMessageLane for RococoMessagesToWococo { let transaction = Rococo::sign_transaction( genesis_hash, &self.message_lane.source_sign, - relay_substrate_client::TransactionEra::immortal(), + relay_substrate_client::TransactionEra::new( + best_block_id, + self.message_lane.source_transactions_mortality, + ), UnsignedTransaction::new(call, transaction_nonce), ); log::trace!( @@ -122,6 +127,7 @@ impl SubstrateMessageLane for RococoMessagesToWococo { fn make_messages_delivery_transaction( &self, + best_block_id: WococoHeaderId, transaction_nonce: IndexOf, _generated_at_header: RococoHeaderId, _nonces: RangeInclusive, @@ -143,7 +149,10 @@ impl SubstrateMessageLane for RococoMessagesToWococo { let transaction = Wococo::sign_transaction( genesis_hash, &self.message_lane.target_sign, - relay_substrate_client::TransactionEra::immortal(), + relay_substrate_client::TransactionEra::new( + best_block_id, + self.message_lane.target_transactions_mortality, + ), UnsignedTransaction::new(call, transaction_nonce), ); log::trace!( @@ -167,7 +176,13 @@ type WococoTargetClient = SubstrateMessagesTarget; pub async fn run( params: MessagesRelayParams, ) -> anyhow::Result<()> { - let stall_timeout = Duration::from_secs(5 * 60); + let stall_timeout = relay_substrate_client::bidirectional_transaction_stall_timeout( + params.source_transactions_mortality, + params.target_transactions_mortality, + Rococo::AVERAGE_BLOCK_INTERVAL, + Wococo::AVERAGE_BLOCK_INTERVAL, + STALL_TIMEOUT, + ); let relayer_id_at_rococo = (*params.source_sign.public().as_array_ref()).into(); let lane_id = params.lane_id; @@ -176,8 +191,10 @@ pub async fn run( message_lane: SubstrateMessageLaneToSubstrate { source_client: source_client.clone(), source_sign: params.source_sign, + source_transactions_mortality: params.source_transactions_mortality, target_client: params.target_client.clone(), target_sign: params.target_sign, + target_transactions_mortality: params.target_transactions_mortality, relayer_id_at_source: relayer_id_at_rococo, }, }; @@ -203,12 +220,17 @@ pub async fn run( Max messages in single transaction: {}\n\t\ Max messages size in single transaction: {}\n\t\ Max messages weight in single transaction: {}\n\t\ - Relayer mode: {:?}", + Relayer mode: {:?}\n\t\ + Tx mortality: {:?}/{:?}\n\t\ + Stall timeout: {:?}", lane.message_lane.relayer_id_at_source, max_messages_in_single_batch, max_messages_size_in_single_batch, max_messages_weight_in_single_batch, params.relayer_mode, + params.source_transactions_mortality, + params.target_transactions_mortality, + stall_timeout, ); let (metrics_params, metrics_values) = add_standalone_metrics( 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 d380e6c29a4cb..420b946506095 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 @@ -16,7 +16,7 @@ //! Wococo-to-Rococo messages sync entrypoint. -use std::{ops::RangeInclusive, time::Duration}; +use std::ops::RangeInclusive; use codec::Encode; use sp_core::{Bytes, Pair}; @@ -40,6 +40,7 @@ use substrate_relay_helper::{ }, messages_source::SubstrateMessagesSource, messages_target::SubstrateMessagesTarget, + STALL_TIMEOUT, }; /// Wococo-to-Rococo message lane. @@ -87,6 +88,7 @@ impl SubstrateMessageLane for WococoMessagesToRococo { fn make_messages_receiving_proof_transaction( &self, + best_block_id: WococoHeaderId, transaction_nonce: IndexOf, _generated_at_block: RococoHeaderId, proof: ::MessagesReceivingProof, @@ -102,7 +104,10 @@ impl SubstrateMessageLane for WococoMessagesToRococo { let transaction = Wococo::sign_transaction( genesis_hash, &self.message_lane.source_sign, - relay_substrate_client::TransactionEra::immortal(), + relay_substrate_client::TransactionEra::new( + best_block_id, + self.message_lane.source_transactions_mortality, + ), UnsignedTransaction::new(call, transaction_nonce), ); log::trace!( @@ -121,6 +126,7 @@ impl SubstrateMessageLane for WococoMessagesToRococo { fn make_messages_delivery_transaction( &self, + best_block_id: WococoHeaderId, transaction_nonce: IndexOf, _generated_at_header: WococoHeaderId, _nonces: RangeInclusive, @@ -142,7 +148,10 @@ impl SubstrateMessageLane for WococoMessagesToRococo { let transaction = Rococo::sign_transaction( genesis_hash, &self.message_lane.target_sign, - relay_substrate_client::TransactionEra::immortal(), + relay_substrate_client::TransactionEra::new( + best_block_id, + self.message_lane.target_transactions_mortality, + ), UnsignedTransaction::new(call, transaction_nonce), ); log::trace!( @@ -166,7 +175,13 @@ type RococoTargetClient = SubstrateMessagesTarget; pub async fn run( params: MessagesRelayParams, ) -> anyhow::Result<()> { - let stall_timeout = Duration::from_secs(5 * 60); + let stall_timeout = relay_substrate_client::bidirectional_transaction_stall_timeout( + params.source_transactions_mortality, + params.target_transactions_mortality, + Wococo::AVERAGE_BLOCK_INTERVAL, + Rococo::AVERAGE_BLOCK_INTERVAL, + STALL_TIMEOUT, + ); let relayer_id_at_wococo = (*params.source_sign.public().as_array_ref()).into(); let lane_id = params.lane_id; @@ -175,8 +190,10 @@ pub async fn run( message_lane: SubstrateMessageLaneToSubstrate { source_client: source_client.clone(), source_sign: params.source_sign, + source_transactions_mortality: params.source_transactions_mortality, target_client: params.target_client.clone(), target_sign: params.target_sign, + target_transactions_mortality: params.target_transactions_mortality, relayer_id_at_source: relayer_id_at_wococo, }, }; @@ -202,12 +219,17 @@ pub async fn run( Max messages in single transaction: {}\n\t\ Max messages size in single transaction: {}\n\t\ Max messages weight in single transaction: {}\n\t\ - Relayer mode: {:?}", + Relayer mode: {:?}\n\t\ + Tx mortality: {:?}/{:?}\n\t\ + Stall timeout: {:?}", lane.message_lane.relayer_id_at_source, max_messages_in_single_batch, max_messages_size_in_single_batch, max_messages_weight_in_single_batch, params.relayer_mode, + params.source_transactions_mortality, + params.target_transactions_mortality, + stall_timeout, ); let (metrics_params, metrics_values) = add_standalone_metrics( diff --git a/bridges/relays/bin-substrate/src/cli/relay_headers_and_messages.rs b/bridges/relays/bin-substrate/src/cli/relay_headers_and_messages.rs index 303acf3f125d6..92343288ede15 100644 --- a/bridges/relays/bin-substrate/src/cli/relay_headers_and_messages.rs +++ b/bridges/relays/bin-substrate/src/cli/relay_headers_and_messages.rs @@ -512,8 +512,10 @@ impl RelayHeadersAndMessages { let left_to_right_messages = left_to_right_messages(MessagesRelayParams { source_client: left_client.clone(), source_sign: left_sign.clone(), + source_transactions_mortality: left_transactions_mortality.clone(), target_client: right_client.clone(), target_sign: right_sign.clone(), + target_transactions_mortality: right_transactions_mortality.clone(), source_to_target_headers_relay: Some(left_to_right_on_demand_headers.clone()), target_to_source_headers_relay: Some(right_to_left_on_demand_headers.clone()), lane_id: lane, @@ -529,8 +531,10 @@ impl RelayHeadersAndMessages { let right_to_left_messages = right_to_left_messages(MessagesRelayParams { source_client: right_client.clone(), source_sign: right_sign.clone(), + source_transactions_mortality: right_transactions_mortality.clone(), target_client: left_client.clone(), target_sign: left_sign.clone(), + target_transactions_mortality: left_transactions_mortality.clone(), source_to_target_headers_relay: Some(right_to_left_on_demand_headers.clone()), target_to_source_headers_relay: Some(left_to_right_on_demand_headers.clone()), lane_id: lane, diff --git a/bridges/relays/bin-substrate/src/cli/relay_messages.rs b/bridges/relays/bin-substrate/src/cli/relay_messages.rs index 3ccf53348d611..fd6875cc2a0f4 100644 --- a/bridges/relays/bin-substrate/src/cli/relay_messages.rs +++ b/bridges/relays/bin-substrate/src/cli/relay_messages.rs @@ -76,14 +76,18 @@ impl RelayMessages { select_full_bridge!(self.bridge, { let source_client = self.source.to_client::().await?; let source_sign = self.source_sign.to_keypair::()?; + let source_transactions_mortality = self.source_sign.transactions_mortality()?; let target_client = self.target.to_client::().await?; let target_sign = self.target_sign.to_keypair::()?; + let target_transactions_mortality = self.target_sign.transactions_mortality()?; relay_messages(MessagesRelayParams { source_client, source_sign, + source_transactions_mortality, target_client, target_sign, + target_transactions_mortality, source_to_target_headers_relay: None, target_to_source_headers_relay: None, lane_id: self.lane.into(), diff --git a/bridges/relays/client-substrate/src/lib.rs b/bridges/relays/client-substrate/src/lib.rs index 634bdcdca196e..1f6606ea287c3 100644 --- a/bridges/relays/client-substrate/src/lib.rs +++ b/bridges/relays/client-substrate/src/lib.rs @@ -69,13 +69,40 @@ impl Default for ConnectionParams { /// /// Relay considers himself stalled if he has submitted transaction to the node, but it has not /// been mined for this period. -/// -/// Returns `None` if mortality period is `None` pub fn transaction_stall_timeout( mortality_period: Option, average_block_interval: Duration, -) -> Option { + default_stall_timeout: Duration, +) -> Duration { // 1 extra block for transaction to reach the pool && 1 for relayer to awake after it is mined mortality_period .map(|mortality_period| average_block_interval.saturating_mul(mortality_period + 1 + 1)) + .unwrap_or(default_stall_timeout) +} + +/// Returns stall timeout for relay loop that submit transactions to two chains. +/// +/// Bidirectional relay may have two active transactions. Even if one of them has been spoiled, we +/// can't just restart the loop - the other transaction may still be alive and we'll be submitting +/// duplicate transaction, which may result in funds loss. So we'll be selecting maximal mortality +/// for choosing loop stall timeout. +pub fn bidirectional_transaction_stall_timeout( + left_mortality_period: Option, + right_mortality_period: Option, + left_average_block_interval: Duration, + right_average_block_interval: Duration, + default_stall_timeout: Duration, +) -> Duration { + std::cmp::max( + transaction_stall_timeout( + left_mortality_period, + left_average_block_interval, + default_stall_timeout, + ), + transaction_stall_timeout( + right_mortality_period, + right_average_block_interval, + default_stall_timeout, + ), + ) } diff --git a/bridges/relays/lib-substrate-relay/Cargo.toml b/bridges/relays/lib-substrate-relay/Cargo.toml index 5be28bccfb3bb..5bee10856daa3 100644 --- a/bridges/relays/lib-substrate-relay/Cargo.toml +++ b/bridges/relays/lib-substrate-relay/Cargo.toml @@ -32,7 +32,6 @@ pallet-bridge-messages = { path = "../../modules/messages" } bp-runtime = { path = "../../primitives/runtime" } bp-messages = { path = "../../primitives/messages" } - # Substrate Dependencies frame-support = { git = "https://github.com/paritytech/substrate", branch = "master" } diff --git a/bridges/relays/lib-substrate-relay/src/finality_pipeline.rs b/bridges/relays/lib-substrate-relay/src/finality_pipeline.rs index cca9e5196b3ca..cdfbb3354d274 100644 --- a/bridges/relays/lib-substrate-relay/src/finality_pipeline.rs +++ b/bridges/relays/lib-substrate-relay/src/finality_pipeline.rs @@ -16,7 +16,7 @@ //! Substrate-to-Substrate headers sync entrypoint. -use crate::finality_target::SubstrateFinalityTarget; +use crate::{finality_target::SubstrateFinalityTarget, STALL_TIMEOUT}; use bp_header_chain::justification::GrandpaJustification; use bp_runtime::AccountIdOf; @@ -26,16 +26,8 @@ use relay_substrate_client::{ }; use relay_utils::{metrics::MetricsParams, BlockNumberBase}; use sp_core::Bytes; -use std::{fmt::Debug, marker::PhantomData, time::Duration}; +use std::{fmt::Debug, marker::PhantomData}; -/// Default synchronization loop timeout. If transactions generated by relay are immortal, then -/// this timeout is used. -/// -/// There are no any strict requirements on block time in Substrate. But we assume here that all -/// Substrate-based chains will be designed to produce relatively fast (compared to the slowest -/// blockchains) blocks. So 1 hour seems to be a good guess for (even congested) chains to mine -/// transaction, or remove it from the pool. -pub(crate) const STALL_TIMEOUT: Duration = Duration::from_secs(60 * 60); /// Default limit of recent finality proofs. /// /// Finality delay of 4096 blocks is unlikely to happen in practice in @@ -165,8 +157,8 @@ where stall_timeout: relay_substrate_client::transaction_stall_timeout( transactions_mortality, TargetChain::AVERAGE_BLOCK_INTERVAL, - ) - .unwrap_or(STALL_TIMEOUT), + STALL_TIMEOUT, + ), only_mandatory_headers, }, metrics_params, diff --git a/bridges/relays/lib-substrate-relay/src/finality_target.rs b/bridges/relays/lib-substrate-relay/src/finality_target.rs index 1353eec87278a..f50bd103f4300 100644 --- a/bridges/relays/lib-substrate-relay/src/finality_target.rs +++ b/bridges/relays/lib-substrate-relay/src/finality_target.rs @@ -98,8 +98,7 @@ where move |best_block_id, transaction_nonce| { pipeline.make_submit_finality_proof_transaction( relay_substrate_client::TransactionEra::new( - best_block_id.0, - best_block_id.1, + best_block_id, transactions_mortality, ), transaction_nonce, diff --git a/bridges/relays/lib-substrate-relay/src/lib.rs b/bridges/relays/lib-substrate-relay/src/lib.rs index dac6b8caa8e5c..cc066bf501ac6 100644 --- a/bridges/relays/lib-substrate-relay/src/lib.rs +++ b/bridges/relays/lib-substrate-relay/src/lib.rs @@ -18,6 +18,8 @@ #![warn(missing_docs)] +use std::time::Duration; + pub mod conversion_rate_update; pub mod error; pub mod finality_pipeline; @@ -28,3 +30,12 @@ pub mod messages_lane; pub mod messages_source; pub mod messages_target; pub mod on_demand_headers; + +/// Default relay loop stall timeout. If transactions generated by relay are immortal, then +/// this timeout is used. +/// +/// There are no any strict requirements on block time in Substrate. But we assume here that all +/// Substrate-based chains will be designed to produce relatively fast (compared to the slowest +/// blockchains) blocks. So 1 hour seems to be a good guess for (even congested) chains to mine +/// transaction, or remove it from the pool. +pub const STALL_TIMEOUT: Duration = Duration::from_secs(60 * 60); diff --git a/bridges/relays/lib-substrate-relay/src/messages_lane.rs b/bridges/relays/lib-substrate-relay/src/messages_lane.rs index 973f52d60a38b..876b2c2f25728 100644 --- a/bridges/relays/lib-substrate-relay/src/messages_lane.rs +++ b/bridges/relays/lib-substrate-relay/src/messages_lane.rs @@ -44,10 +44,14 @@ pub struct MessagesRelayParams { pub source_client: Client, /// Sign parameters for messages source chain. pub source_sign: SS, + /// Mortality of source transactions. + pub source_transactions_mortality: Option, /// Messages target client. pub target_client: Client, /// Sign parameters for messages target chain. pub target_sign: TS, + /// Mortality of target transactions. + pub target_transactions_mortality: Option, /// Optional on-demand source to target headers relay. pub source_to_target_headers_relay: Option>, /// Optional on-demand target to source headers relay. @@ -113,6 +117,7 @@ pub trait SubstrateMessageLane: 'static + Clone + Send + Sync { /// Make messages delivery transaction. fn make_messages_delivery_transaction( &self, + best_block_id: TargetHeaderIdOf, transaction_nonce: IndexOf, generated_at_header: SourceHeaderIdOf, nonces: RangeInclusive, @@ -126,6 +131,7 @@ pub trait SubstrateMessageLane: 'static + Clone + Send + Sync { /// Make messages receiving proof transaction. fn make_messages_receiving_proof_transaction( &self, + best_block_id: SourceHeaderIdOf, transaction_nonce: IndexOf, generated_at_header: TargetHeaderIdOf, proof: ::MessagesReceivingProof, @@ -144,10 +150,14 @@ pub struct SubstrateMessageLaneToSubstrate< pub source_client: Client, /// Parameters required to sign transactions for source chain. pub source_sign: SourceSignParams, + /// Source transactions mortality. + pub source_transactions_mortality: Option, /// Client for the target Substrate chain. pub target_client: Client, /// Parameters required to sign transactions for target chain. pub target_sign: TargetSignParams, + /// Target transactions mortality. + pub target_transactions_mortality: Option, /// Account id of relayer at the source chain. pub relayer_id_at_source: Source::AccountId, } @@ -159,8 +169,10 @@ impl ::SourceChainBalance { self.client .estimate_extrinsic_fee(self.lane.make_messages_receiving_proof_transaction( + HeaderId(Default::default(), Default::default()), Zero::zero(), HeaderId(Default::default(), Default::default()), prepare_dummy_messages_delivery_proof::(), diff --git a/bridges/relays/lib-substrate-relay/src/messages_target.rs b/bridges/relays/lib-substrate-relay/src/messages_target.rs index f7b911f2c023a..6f95ffd12f09c 100644 --- a/bridges/relays/lib-substrate-relay/src/messages_target.rs +++ b/bridges/relays/lib-substrate-relay/src/messages_target.rs @@ -227,8 +227,9 @@ where self.client .submit_signed_extrinsic( self.lane.target_transactions_author(), - move |_, transaction_nonce| { + move |best_block_id, transaction_nonce| { lane.make_messages_delivery_transaction( + best_block_id, transaction_nonce, generated_at_header, nonces_clone, @@ -264,6 +265,7 @@ where // Prepare 'dummy' delivery transaction - we only care about its length and dispatch weight. let delivery_tx = self.lane.make_messages_delivery_transaction( + HeaderId(Default::default(), Default::default()), Zero::zero(), HeaderId(Default::default(), Default::default()), nonces.clone(), @@ -299,6 +301,7 @@ where let larger_delivery_tx_fee = self .client .estimate_extrinsic_fee(self.lane.make_messages_delivery_transaction( + HeaderId(Default::default(), Default::default()), Zero::zero(), HeaderId(Default::default(), Default::default()), nonces.clone(), @@ -473,6 +476,7 @@ mod tests { fn make_messages_receiving_proof_transaction( &self, + _best_block_id: SourceHeaderIdOf, _transaction_nonce: IndexOf, _generated_at_block: TargetHeaderIdOf, _proof: ::MessagesReceivingProof, @@ -486,6 +490,7 @@ mod tests { fn make_messages_delivery_transaction( &self, + _best_block_id: TargetHeaderIdOf, _transaction_nonce: IndexOf, _generated_at_header: SourceHeaderIdOf, _nonces: RangeInclusive, 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 4dad20579a90d..ee141866eb97d 100644 --- a/bridges/relays/lib-substrate-relay/src/on_demand_headers.rs +++ b/bridges/relays/lib-substrate-relay/src/on_demand_headers.rs @@ -38,9 +38,9 @@ use relay_utils::{ use crate::{ finality_pipeline::{ SubstrateFinalitySyncPipeline, SubstrateFinalityToSubstrate, RECENT_FINALITY_PROOFS_LIMIT, - STALL_TIMEOUT, }, finality_target::SubstrateFinalityTarget, + STALL_TIMEOUT, }; /// On-demand Substrate <-> Substrate headers relay. diff --git a/bridges/relays/utils/Cargo.toml b/bridges/relays/utils/Cargo.toml index 652ff54002833..a08c3b3d688df 100644 --- a/bridges/relays/utils/Cargo.toml +++ b/bridges/relays/utils/Cargo.toml @@ -22,6 +22,10 @@ sysinfo = "0.15" time = "0.2" thiserror = "1.0.26" +# Bridge dependencies + +bp-runtime = { path = "../../primitives/runtime" } + # Substrate dependencies substrate-prometheus-endpoint = { git = "https://github.com/paritytech/substrate", branch = "master" } diff --git a/bridges/relays/utils/src/lib.rs b/bridges/relays/utils/src/lib.rs index 936e9ba68156a..a335be791242c 100644 --- a/bridges/relays/utils/src/lib.rs +++ b/bridges/relays/utils/src/lib.rs @@ -16,6 +16,7 @@ //! Utilities used by different relays. +pub use bp_runtime::HeaderId; pub use error::Error; pub use relay_loop::{relay_loop, relay_metrics}; @@ -103,10 +104,6 @@ macro_rules! bail_on_arg_error { }; } -/// Ethereum header Id. -#[derive(Debug, Default, Clone, Copy, Eq, Hash, PartialEq)] -pub struct HeaderId(pub Number, pub Hash); - /// Error type that can signal connection errors. pub trait MaybeConnectionError { /// Returns true if error (maybe) represents connection error.