diff --git a/bridges/bin/millau/runtime/src/lib.rs b/bridges/bin/millau/runtime/src/lib.rs index 288ff9a47d..25cf48b6f7 100644 --- a/bridges/bin/millau/runtime/src/lib.rs +++ b/bridges/bin/millau/runtime/src/lib.rs @@ -731,10 +731,6 @@ impl_runtime_apis! { let header = BridgeRialtoGrandpa::best_finalized(); (header.number, header.hash()) } - - fn is_known_header(hash: bp_rialto::Hash) -> bool { - BridgeRialtoGrandpa::is_known_header(hash) - } } impl bp_westend::WestendFinalityApi for Runtime { @@ -742,10 +738,6 @@ impl_runtime_apis! { let header = BridgeWestendGrandpa::best_finalized(); (header.number, header.hash()) } - - fn is_known_header(hash: bp_westend::Hash) -> bool { - BridgeWestendGrandpa::is_known_header(hash) - } } impl bp_rialto::ToRialtoOutboundLaneApi for Runtime { diff --git a/bridges/bin/rialto/runtime/src/lib.rs b/bridges/bin/rialto/runtime/src/lib.rs index 0987184c73..7b9de28aa9 100644 --- a/bridges/bin/rialto/runtime/src/lib.rs +++ b/bridges/bin/rialto/runtime/src/lib.rs @@ -662,10 +662,6 @@ impl_runtime_apis! { let header = BridgeMillauGrandpa::best_finalized(); (header.number, header.hash()) } - - fn is_known_header(hash: bp_millau::Hash) -> bool { - BridgeMillauGrandpa::is_known_header(hash) - } } impl sp_transaction_pool::runtime_api::TaggedTransactionQueue for Runtime { diff --git a/bridges/primitives/chain-kusama/src/lib.rs b/bridges/primitives/chain-kusama/src/lib.rs index 9a6eb66d22..f52d03f9f2 100644 --- a/bridges/primitives/chain-kusama/src/lib.rs +++ b/bridges/primitives/chain-kusama/src/lib.rs @@ -90,8 +90,6 @@ pub const POLKADOT_TO_KUSAMA_CONVERSION_RATE_PARAMETER_NAME: &str = /// Name of the `KusamaFinalityApi::best_finalized` runtime method. pub const BEST_FINALIZED_KUSAMA_HEADER_METHOD: &str = "KusamaFinalityApi_best_finalized"; -/// Name of the `KusamaFinalityApi::is_known_header` runtime method. -pub const IS_KNOWN_KUSAMA_HEADER_METHOD: &str = "KusamaFinalityApi_is_known_header"; /// Name of the `ToKusamaOutboundLaneApi::estimate_message_delivery_and_dispatch_fee` runtime /// method. @@ -124,8 +122,6 @@ sp_api::decl_runtime_apis! { pub trait KusamaFinalityApi { /// Returns number and hash of the best finalized header known to the bridge module. fn best_finalized() -> (BlockNumber, Hash); - /// Returns true if the header is known to the runtime. - fn is_known_header(hash: Hash) -> bool; } /// Outbound message lane API for messages that are sent to Kusama chain. diff --git a/bridges/primitives/chain-millau/src/lib.rs b/bridges/primitives/chain-millau/src/lib.rs index 0092f7092b..ba68467021 100644 --- a/bridges/primitives/chain-millau/src/lib.rs +++ b/bridges/primitives/chain-millau/src/lib.rs @@ -298,8 +298,6 @@ sp_api::decl_runtime_apis! { pub trait MillauFinalityApi { /// Returns number and hash of the best finalized header known to the bridge module. fn best_finalized() -> (BlockNumber, Hash); - /// Returns true if the header is known to the runtime. - fn is_known_header(hash: Hash) -> bool; } /// Outbound message lane API for messages that are sent to Millau chain. diff --git a/bridges/primitives/chain-polkadot/src/lib.rs b/bridges/primitives/chain-polkadot/src/lib.rs index 26bad1ea86..36d15ea6e4 100644 --- a/bridges/primitives/chain-polkadot/src/lib.rs +++ b/bridges/primitives/chain-polkadot/src/lib.rs @@ -90,8 +90,6 @@ pub const KUSAMA_TO_POLKADOT_CONVERSION_RATE_PARAMETER_NAME: &str = /// Name of the `PolkadotFinalityApi::best_finalized` runtime method. pub const BEST_FINALIZED_POLKADOT_HEADER_METHOD: &str = "PolkadotFinalityApi_best_finalized"; -/// Name of the `PolkadotFinalityApi::is_known_header` runtime method. -pub const IS_KNOWN_POLKADOT_HEADER_METHOD: &str = "PolkadotFinalityApi_is_known_header"; /// Name of the `ToPolkadotOutboundLaneApi::estimate_message_delivery_and_dispatch_fee` runtime /// method. @@ -124,8 +122,6 @@ sp_api::decl_runtime_apis! { pub trait PolkadotFinalityApi { /// Returns number and hash of the best finalized header known to the bridge module. fn best_finalized() -> (BlockNumber, Hash); - /// Returns true if the header is known to the runtime. - fn is_known_header(hash: Hash) -> bool; } /// Outbound message lane API for messages that are sent to Polkadot chain. diff --git a/bridges/primitives/chain-rialto/src/lib.rs b/bridges/primitives/chain-rialto/src/lib.rs index 6c4e48301e..3a0f7045c0 100644 --- a/bridges/primitives/chain-rialto/src/lib.rs +++ b/bridges/primitives/chain-rialto/src/lib.rs @@ -271,8 +271,6 @@ sp_api::decl_runtime_apis! { pub trait RialtoFinalityApi { /// Returns number and hash of the best finalized header known to the bridge module. fn best_finalized() -> (BlockNumber, Hash); - /// Returns true if the header is known to the runtime. - fn is_known_header(hash: Hash) -> bool; } /// Outbound message lane API for messages that are sent to Rialto chain. diff --git a/bridges/primitives/chain-rococo/src/lib.rs b/bridges/primitives/chain-rococo/src/lib.rs index f4ee452119..e5b3647f32 100644 --- a/bridges/primitives/chain-rococo/src/lib.rs +++ b/bridges/primitives/chain-rococo/src/lib.rs @@ -79,8 +79,6 @@ pub const WITH_WOCOCO_MESSAGES_PALLET_NAME: &str = "BridgeWococoMessages"; /// Name of the `RococoFinalityApi::best_finalized` runtime method. pub const BEST_FINALIZED_ROCOCO_HEADER_METHOD: &str = "RococoFinalityApi_best_finalized"; -/// Name of the `RococoFinalityApi::is_known_header` runtime method. -pub const IS_KNOWN_ROCOCO_HEADER_METHOD: &str = "RococoFinalityApi_is_known_header"; /// Name of the `ToRococoOutboundLaneApi::estimate_message_delivery_and_dispatch_fee` runtime /// method. @@ -125,8 +123,6 @@ sp_api::decl_runtime_apis! { pub trait RococoFinalityApi { /// Returns number and hash of the best finalized header known to the bridge module. fn best_finalized() -> (BlockNumber, Hash); - /// Returns true if the header is known to the runtime. - fn is_known_header(hash: Hash) -> bool; } /// Outbound message lane API for messages that are sent to Rococo chain. diff --git a/bridges/primitives/chain-westend/src/lib.rs b/bridges/primitives/chain-westend/src/lib.rs index 8beb897f59..ffc0bf0fca 100644 --- a/bridges/primitives/chain-westend/src/lib.rs +++ b/bridges/primitives/chain-westend/src/lib.rs @@ -90,8 +90,6 @@ pub fn derive_account_from_rococo_id(id: bp_runtime::SourceAccount) - /// Name of the `WestendFinalityApi::best_finalized` runtime method. pub const BEST_FINALIZED_WESTEND_HEADER_METHOD: &str = "WestendFinalityApi_best_finalized"; -/// Name of the `WestendFinalityApi::is_known_header` runtime method. -pub const IS_KNOWN_WESTEND_HEADER_METHOD: &str = "WestendFinalityApi_is_known_header"; /// Name of the `ToWestendOutboundLaneApi::estimate_message_delivery_and_dispatch_fee` runtime /// method. @@ -131,8 +129,6 @@ sp_api::decl_runtime_apis! { pub trait WestendFinalityApi { /// Returns number and hash of the best finalized header known to the bridge module. fn best_finalized() -> (BlockNumber, Hash); - /// Returns true if the header is known to the runtime. - fn is_known_header(hash: Hash) -> bool; } /// Outbound message lane API for messages that are sent to Westend chain. diff --git a/bridges/primitives/chain-wococo/src/lib.rs b/bridges/primitives/chain-wococo/src/lib.rs index 14489351b8..b16dff388c 100644 --- a/bridges/primitives/chain-wococo/src/lib.rs +++ b/bridges/primitives/chain-wococo/src/lib.rs @@ -44,8 +44,6 @@ pub const WITH_ROCOCO_MESSAGES_PALLET_NAME: &str = "BridgeRococoMessages"; /// Name of the `WococoFinalityApi::best_finalized` runtime method. pub const BEST_FINALIZED_WOCOCO_HEADER_METHOD: &str = "WococoFinalityApi_best_finalized"; -/// Name of the `WococoFinalityApi::is_known_header` runtime method. -pub const IS_KNOWN_WOCOCO_HEADER_METHOD: &str = "WococoFinalityApi_is_known_header"; /// Name of the `ToWococoOutboundLaneApi::estimate_message_delivery_and_dispatch_fee` runtime /// method. @@ -78,8 +76,6 @@ sp_api::decl_runtime_apis! { pub trait WococoFinalityApi { /// Returns number and hash of the best finalized header known to the bridge module. fn best_finalized() -> (BlockNumber, Hash); - /// Returns true if the header is known to the runtime. - fn is_known_header(hash: Hash) -> bool; } /// Outbound message lane API for messages that are sent to Wococo chain. diff --git a/bridges/primitives/runtime/src/chain.rs b/bridges/primitives/runtime/src/chain.rs index e24694bf8b..e963b633b7 100644 --- a/bridges/primitives/runtime/src/chain.rs +++ b/bridges/primitives/runtime/src/chain.rs @@ -15,7 +15,7 @@ // along with Parity Bridges Common. If not, see . use frame_support::Parameter; -use num_traits::{AsPrimitive, Bounded, CheckedSub, SaturatingAdd, Zero}; +use num_traits::{AsPrimitive, Bounded, CheckedSub, Saturating, SaturatingAdd, Zero}; use sp_runtime::{ traits::{ AtLeast32Bit, AtLeast32BitUnsigned, Hash as HashT, Header as HeaderT, MaybeDisplay, @@ -46,6 +46,7 @@ pub trait Chain: Send + Sync + 'static { + MaybeMallocSizeOf + AsPrimitive + Default + + Saturating // original `sp_runtime::traits::Header::BlockNumber` doesn't have this trait, but // `sp_runtime::generic::Era` requires block number -> `u64` conversion. + Into; diff --git a/bridges/relays/bin-substrate/src/chains/kusama_headers_to_polkadot.rs b/bridges/relays/bin-substrate/src/chains/kusama_headers_to_polkadot.rs index ce631ef41e..afa22aec9e 100644 --- a/bridges/relays/bin-substrate/src/chains/kusama_headers_to_polkadot.rs +++ b/bridges/relays/bin-substrate/src/chains/kusama_headers_to_polkadot.rs @@ -16,17 +16,8 @@ //! Kusama-to-Polkadot headers sync entrypoint. -use codec::Encode; -use sp_core::{Bytes, Pair}; - -use bp_header_chain::justification::GrandpaJustification; -use relay_kusama_client::{Kusama, SyncHeader as KusamaSyncHeader}; -use relay_polkadot_client::{Polkadot, SigningParams as PolkadotSigningParams}; -use relay_substrate_client::{Client, TransactionSignScheme, UnsignedTransaction}; -use relay_utils::metrics::MetricsParams; -use substrate_relay_helper::finality_pipeline::{ - SubstrateFinalitySyncPipeline, SubstrateFinalityToSubstrate, -}; +use sp_core::Pair; +use substrate_relay_helper::finality_pipeline::{SubstrateFinalitySyncPipeline, TransactionParams}; /// Maximal saturating difference between `balance(now)` and `balance(now-24h)` to treat /// relay as gone wild. @@ -35,77 +26,37 @@ use substrate_relay_helper::finality_pipeline::{ /// DOT, but let's round up to 30 DOT here. pub(crate) const MAXIMAL_BALANCE_DECREASE_PER_DAY: bp_polkadot::Balance = 30_000_000_000; -/// Kusama-to-Polkadot finality sync pipeline. -pub(crate) type FinalityPipelineKusamaFinalityToPolkadot = - SubstrateFinalityToSubstrate; - +/// Description of Kusama -> Polkadot finalized headers bridge. #[derive(Clone, Debug)] -pub(crate) struct KusamaFinalityToPolkadot { - finality_pipeline: FinalityPipelineKusamaFinalityToPolkadot, -} - -impl KusamaFinalityToPolkadot { - pub fn new(target_client: Client, target_sign: PolkadotSigningParams) -> Self { - Self { - finality_pipeline: FinalityPipelineKusamaFinalityToPolkadot::new( - target_client, - target_sign, - ), - } - } -} +pub struct KusamaFinalityToPolkadot; +substrate_relay_helper::generate_mocked_submit_finality_proof_call_builder!( + KusamaFinalityToPolkadot, + KusamaFinalityToPolkadotCallBuilder, + relay_polkadot_client::runtime::Call::BridgeKusamaGrandpa, + relay_polkadot_client::runtime::BridgeKusamaGrandpaCall::submit_finality_proof +); impl SubstrateFinalitySyncPipeline for KusamaFinalityToPolkadot { - type FinalitySyncPipeline = FinalityPipelineKusamaFinalityToPolkadot; + type SourceChain = relay_kusama_client::Kusama; + type TargetChain = relay_polkadot_client::Polkadot; - const BEST_FINALIZED_SOURCE_HEADER_ID_AT_TARGET: &'static str = - bp_kusama::BEST_FINALIZED_KUSAMA_HEADER_METHOD; + type SubmitFinalityProofCallBuilder = KusamaFinalityToPolkadotCallBuilder; + type TransactionSignScheme = relay_polkadot_client::Polkadot; - type TargetChain = Polkadot; - - fn customize_metrics(params: MetricsParams) -> anyhow::Result { - crate::chains::add_polkadot_kusama_price_metrics::(params) - } - - fn start_relay_guards(&self) { + fn start_relay_guards( + target_client: &relay_substrate_client::Client, + transaction_params: &TransactionParams, + ) { relay_substrate_client::guard::abort_on_spec_version_change( - self.finality_pipeline.target_client.clone(), + target_client.clone(), bp_polkadot::VERSION.spec_version, ); relay_substrate_client::guard::abort_when_account_balance_decreased( - self.finality_pipeline.target_client.clone(), - self.transactions_author(), + target_client.clone(), + transaction_params.transactions_signer.public().into(), MAXIMAL_BALANCE_DECREASE_PER_DAY, ); } - - fn transactions_author(&self) -> bp_polkadot::AccountId { - (*self.finality_pipeline.target_sign.public().as_array_ref()).into() - } - - fn make_submit_finality_proof_transaction( - &self, - era: bp_runtime::TransactionEraOf, - transaction_nonce: bp_runtime::IndexOf, - header: KusamaSyncHeader, - proof: GrandpaJustification, - ) -> Bytes { - let call = relay_polkadot_client::runtime::Call::BridgeKusamaGrandpa( - relay_polkadot_client::runtime::BridgeKusamaGrandpaCall::submit_finality_proof( - Box::new(header.into_inner()), - proof, - ), - ); - let genesis_hash = *self.finality_pipeline.target_client.genesis_hash(); - let transaction = Polkadot::sign_transaction( - genesis_hash, - &self.finality_pipeline.target_sign, - era, - UnsignedTransaction::new(call, transaction_nonce), - ); - - Bytes(transaction.encode()) - } } #[cfg(test)] diff --git a/bridges/relays/bin-substrate/src/chains/millau_headers_to_rialto.rs b/bridges/relays/bin-substrate/src/chains/millau_headers_to_rialto.rs index 14a0430f6a..584f0a9bb1 100644 --- a/bridges/relays/bin-substrate/src/chains/millau_headers_to_rialto.rs +++ b/bridges/relays/bin-substrate/src/chains/millau_headers_to_rialto.rs @@ -16,65 +16,22 @@ //! Millau-to-Rialto headers sync entrypoint. -use codec::Encode; -use sp_core::{Bytes, Pair}; - -use bp_header_chain::justification::GrandpaJustification; -use relay_millau_client::{Millau, SyncHeader as MillauSyncHeader}; -use relay_rialto_client::{Rialto, SigningParams as RialtoSigningParams}; -use relay_substrate_client::{Client, IndexOf, TransactionSignScheme, UnsignedTransaction}; use substrate_relay_helper::finality_pipeline::{ - SubstrateFinalitySyncPipeline, SubstrateFinalityToSubstrate, + DirectSubmitFinalityProofCallBuilder, SubstrateFinalitySyncPipeline, }; -/// Millau-to-Rialto finality sync pipeline. -pub(crate) type FinalityPipelineMillauToRialto = - SubstrateFinalityToSubstrate; - +/// Description of Millau -> Rialto finalized headers bridge. #[derive(Clone, Debug)] -pub(crate) struct MillauFinalityToRialto { - finality_pipeline: FinalityPipelineMillauToRialto, -} - -impl MillauFinalityToRialto { - pub fn new(target_client: Client, target_sign: RialtoSigningParams) -> Self { - Self { finality_pipeline: FinalityPipelineMillauToRialto::new(target_client, target_sign) } - } -} +pub struct MillauFinalityToRialto; impl SubstrateFinalitySyncPipeline for MillauFinalityToRialto { - type FinalitySyncPipeline = FinalityPipelineMillauToRialto; + type SourceChain = relay_millau_client::Millau; + type TargetChain = relay_rialto_client::Rialto; - const BEST_FINALIZED_SOURCE_HEADER_ID_AT_TARGET: &'static str = - bp_millau::BEST_FINALIZED_MILLAU_HEADER_METHOD; - - type TargetChain = Rialto; - - fn transactions_author(&self) -> bp_rialto::AccountId { - (*self.finality_pipeline.target_sign.public().as_array_ref()).into() - } - - fn make_submit_finality_proof_transaction( - &self, - era: bp_runtime::TransactionEraOf, - transaction_nonce: IndexOf, - header: MillauSyncHeader, - proof: GrandpaJustification, - ) -> Bytes { - let call = rialto_runtime::BridgeGrandpaMillauCall::submit_finality_proof { - finality_target: Box::new(header.into_inner()), - justification: proof, - } - .into(); - - let genesis_hash = *self.finality_pipeline.target_client.genesis_hash(); - let transaction = Rialto::sign_transaction( - genesis_hash, - &self.finality_pipeline.target_sign, - era, - UnsignedTransaction::new(call, transaction_nonce), - ); - - Bytes(transaction.encode()) - } + type SubmitFinalityProofCallBuilder = DirectSubmitFinalityProofCallBuilder< + Self, + rialto_runtime::Runtime, + rialto_runtime::MillauGrandpaInstance, + >; + type TransactionSignScheme = relay_rialto_client::Rialto; } diff --git a/bridges/relays/bin-substrate/src/chains/mod.rs b/bridges/relays/bin-substrate/src/chains/mod.rs index e9cb2d9b73..1bc0115b5b 100644 --- a/bridges/relays/bin-substrate/src/chains/mod.rs +++ b/bridges/relays/bin-substrate/src/chains/mod.rs @@ -39,18 +39,6 @@ mod rococo; mod westend; mod wococo; -use relay_utils::metrics::{MetricsParams, StandaloneMetric}; - -pub(crate) fn add_polkadot_kusama_price_metrics( - params: MetricsParams, -) -> anyhow::Result { - substrate_relay_helper::helpers::token_price_metric(polkadot::TOKEN_ID)? - .register_and_spawn(¶ms.registry)?; - substrate_relay_helper::helpers::token_price_metric(kusama::TOKEN_ID)? - .register_and_spawn(¶ms.registry)?; - Ok(params) -} - #[cfg(test)] mod tests { use crate::cli::{encode_call, send_message}; diff --git a/bridges/relays/bin-substrate/src/chains/polkadot_headers_to_kusama.rs b/bridges/relays/bin-substrate/src/chains/polkadot_headers_to_kusama.rs index b1948b234c..695e0ec3ee 100644 --- a/bridges/relays/bin-substrate/src/chains/polkadot_headers_to_kusama.rs +++ b/bridges/relays/bin-substrate/src/chains/polkadot_headers_to_kusama.rs @@ -16,17 +16,8 @@ //! Polkadot-to-Kusama headers sync entrypoint. -use codec::Encode; -use sp_core::{Bytes, Pair}; - -use bp_header_chain::justification::GrandpaJustification; -use relay_kusama_client::{Kusama, SigningParams as KusamaSigningParams}; -use relay_polkadot_client::{Polkadot, SyncHeader as PolkadotSyncHeader}; -use relay_substrate_client::{Client, TransactionSignScheme, UnsignedTransaction}; -use relay_utils::metrics::MetricsParams; -use substrate_relay_helper::finality_pipeline::{ - SubstrateFinalitySyncPipeline, SubstrateFinalityToSubstrate, -}; +use sp_core::Pair; +use substrate_relay_helper::finality_pipeline::{SubstrateFinalitySyncPipeline, TransactionParams}; /// Maximal saturating difference between `balance(now)` and `balance(now-24h)` to treat /// relay as gone wild. @@ -35,77 +26,37 @@ use substrate_relay_helper::finality_pipeline::{ /// KSM, but let's round up to 0.1 KSM here. pub(crate) const MAXIMAL_BALANCE_DECREASE_PER_DAY: bp_polkadot::Balance = 100_000_000_000; -/// Polkadot-to-Kusama finality sync pipeline. -pub(crate) type FinalityPipelinePolkadotFinalityToKusama = - SubstrateFinalityToSubstrate; - +/// Description of Polkadot -> Kusama finalized headers bridge. #[derive(Clone, Debug)] -pub(crate) struct PolkadotFinalityToKusama { - finality_pipeline: FinalityPipelinePolkadotFinalityToKusama, -} - -impl PolkadotFinalityToKusama { - pub fn new(target_client: Client, target_sign: KusamaSigningParams) -> Self { - Self { - finality_pipeline: FinalityPipelinePolkadotFinalityToKusama::new( - target_client, - target_sign, - ), - } - } -} +pub struct PolkadotFinalityToKusama; +substrate_relay_helper::generate_mocked_submit_finality_proof_call_builder!( + PolkadotFinalityToKusama, + PolkadotFinalityToKusamaCallBuilder, + relay_kusama_client::runtime::Call::BridgePolkadotGrandpa, + relay_kusama_client::runtime::BridgePolkadotGrandpaCall::submit_finality_proof +); impl SubstrateFinalitySyncPipeline for PolkadotFinalityToKusama { - type FinalitySyncPipeline = FinalityPipelinePolkadotFinalityToKusama; + type SourceChain = relay_polkadot_client::Polkadot; + type TargetChain = relay_kusama_client::Kusama; - const BEST_FINALIZED_SOURCE_HEADER_ID_AT_TARGET: &'static str = - bp_polkadot::BEST_FINALIZED_POLKADOT_HEADER_METHOD; + type SubmitFinalityProofCallBuilder = PolkadotFinalityToKusamaCallBuilder; + type TransactionSignScheme = relay_kusama_client::Kusama; - type TargetChain = Kusama; - - fn customize_metrics(params: MetricsParams) -> anyhow::Result { - crate::chains::add_polkadot_kusama_price_metrics::(params) - } - - fn start_relay_guards(&self) { + fn start_relay_guards( + target_client: &relay_substrate_client::Client, + transaction_params: &TransactionParams, + ) { relay_substrate_client::guard::abort_on_spec_version_change( - self.finality_pipeline.target_client.clone(), + target_client.clone(), bp_kusama::VERSION.spec_version, ); relay_substrate_client::guard::abort_when_account_balance_decreased( - self.finality_pipeline.target_client.clone(), - self.transactions_author(), + target_client.clone(), + transaction_params.transactions_signer.public().into(), MAXIMAL_BALANCE_DECREASE_PER_DAY, ); } - - fn transactions_author(&self) -> bp_kusama::AccountId { - (*self.finality_pipeline.target_sign.public().as_array_ref()).into() - } - - fn make_submit_finality_proof_transaction( - &self, - era: bp_runtime::TransactionEraOf, - transaction_nonce: bp_runtime::IndexOf, - header: PolkadotSyncHeader, - proof: GrandpaJustification, - ) -> Bytes { - let call = relay_kusama_client::runtime::Call::BridgePolkadotGrandpa( - relay_kusama_client::runtime::BridgePolkadotGrandpaCall::submit_finality_proof( - Box::new(header.into_inner()), - proof, - ), - ); - let genesis_hash = *self.finality_pipeline.target_client.genesis_hash(); - let transaction = Kusama::sign_transaction( - genesis_hash, - &self.finality_pipeline.target_sign, - era, - UnsignedTransaction::new(call, transaction_nonce), - ); - - Bytes(transaction.encode()) - } } #[cfg(test)] diff --git a/bridges/relays/bin-substrate/src/chains/rialto_headers_to_millau.rs b/bridges/relays/bin-substrate/src/chains/rialto_headers_to_millau.rs index 7e76f403c5..a433f3562a 100644 --- a/bridges/relays/bin-substrate/src/chains/rialto_headers_to_millau.rs +++ b/bridges/relays/bin-substrate/src/chains/rialto_headers_to_millau.rs @@ -16,73 +16,22 @@ //! Rialto-to-Millau headers sync entrypoint. -use codec::Encode; -use sp_core::{Bytes, Pair}; - -use bp_header_chain::justification::GrandpaJustification; -use relay_millau_client::{Millau, SigningParams as MillauSigningParams}; -use relay_rialto_client::{Rialto, SyncHeader as RialtoSyncHeader}; -use relay_substrate_client::{Client, IndexOf, TransactionSignScheme, UnsignedTransaction}; use substrate_relay_helper::finality_pipeline::{ - SubstrateFinalitySyncPipeline, SubstrateFinalityToSubstrate, + DirectSubmitFinalityProofCallBuilder, SubstrateFinalitySyncPipeline, }; -/// Rialto-to-Millau finality sync pipeline. -pub(crate) type FinalityPipelineRialtoFinalityToMillau = - SubstrateFinalityToSubstrate; - +/// Description of Millau -> Rialto finalized headers bridge. #[derive(Clone, Debug)] -pub struct RialtoFinalityToMillau { - finality_pipeline: FinalityPipelineRialtoFinalityToMillau, -} - -impl RialtoFinalityToMillau { - pub fn new(target_client: Client, target_sign: MillauSigningParams) -> Self { - Self { - finality_pipeline: FinalityPipelineRialtoFinalityToMillau::new( - target_client, - target_sign, - ), - } - } -} +pub struct RialtoFinalityToMillau; impl SubstrateFinalitySyncPipeline for RialtoFinalityToMillau { - type FinalitySyncPipeline = FinalityPipelineRialtoFinalityToMillau; + type SourceChain = relay_rialto_client::Rialto; + type TargetChain = relay_millau_client::Millau; - const BEST_FINALIZED_SOURCE_HEADER_ID_AT_TARGET: &'static str = - bp_rialto::BEST_FINALIZED_RIALTO_HEADER_METHOD; - - type TargetChain = Millau; - - fn transactions_author(&self) -> bp_millau::AccountId { - (*self.finality_pipeline.target_sign.public().as_array_ref()).into() - } - - fn make_submit_finality_proof_transaction( - &self, - era: bp_runtime::TransactionEraOf, - transaction_nonce: IndexOf, - header: RialtoSyncHeader, - proof: GrandpaJustification, - ) -> Bytes { - let call = millau_runtime::BridgeGrandpaCall::< - millau_runtime::Runtime, - millau_runtime::RialtoGrandpaInstance, - >::submit_finality_proof { - finality_target: Box::new(header.into_inner()), - justification: proof, - } - .into(); - - let genesis_hash = *self.finality_pipeline.target_client.genesis_hash(); - let transaction = Millau::sign_transaction( - genesis_hash, - &self.finality_pipeline.target_sign, - era, - UnsignedTransaction::new(call, transaction_nonce), - ); - - Bytes(transaction.encode()) - } + type SubmitFinalityProofCallBuilder = DirectSubmitFinalityProofCallBuilder< + Self, + millau_runtime::Runtime, + millau_runtime::RialtoGrandpaInstance, + >; + type TransactionSignScheme = relay_millau_client::Millau; } diff --git a/bridges/relays/bin-substrate/src/chains/rococo_headers_to_wococo.rs b/bridges/relays/bin-substrate/src/chains/rococo_headers_to_wococo.rs index ec98cec1ec..0b6608b99b 100644 --- a/bridges/relays/bin-substrate/src/chains/rococo_headers_to_wococo.rs +++ b/bridges/relays/bin-substrate/src/chains/rococo_headers_to_wococo.rs @@ -16,89 +16,40 @@ //! Rococo-to-Wococo headers sync entrypoint. -use codec::Encode; -use sp_core::{Bytes, Pair}; - -use bp_header_chain::justification::GrandpaJustification; -use relay_rococo_client::{Rococo, SyncHeader as RococoSyncHeader}; -use relay_substrate_client::{Client, IndexOf, TransactionSignScheme, UnsignedTransaction}; -use relay_utils::metrics::MetricsParams; -use relay_wococo_client::{SigningParams as WococoSigningParams, Wococo}; -use substrate_relay_helper::finality_pipeline::{ - SubstrateFinalitySyncPipeline, SubstrateFinalityToSubstrate, -}; - use crate::chains::wococo_headers_to_rococo::MAXIMAL_BALANCE_DECREASE_PER_DAY; -/// Rococo-to-Wococo finality sync pipeline. -pub(crate) type FinalityPipelineRococoFinalityToWococo = - SubstrateFinalityToSubstrate; +use sp_core::Pair; +use substrate_relay_helper::finality_pipeline::{SubstrateFinalitySyncPipeline, TransactionParams}; +/// Description of Rococo -> Wococo finalized headers bridge. #[derive(Clone, Debug)] -pub(crate) struct RococoFinalityToWococo { - finality_pipeline: FinalityPipelineRococoFinalityToWococo, -} - -impl RococoFinalityToWococo { - pub fn new(target_client: Client, target_sign: WococoSigningParams) -> Self { - Self { - finality_pipeline: FinalityPipelineRococoFinalityToWococo::new( - target_client, - target_sign, - ), - } - } -} +pub struct RococoFinalityToWococo; +substrate_relay_helper::generate_mocked_submit_finality_proof_call_builder!( + RococoFinalityToWococo, + RococoFinalityToWococoCallBuilder, + relay_wococo_client::runtime::Call::BridgeGrandpaRococo, + relay_wococo_client::runtime::BridgeGrandpaRococoCall::submit_finality_proof +); impl SubstrateFinalitySyncPipeline for RococoFinalityToWococo { - type FinalitySyncPipeline = FinalityPipelineRococoFinalityToWococo; + type SourceChain = relay_rococo_client::Rococo; + type TargetChain = relay_wococo_client::Wococo; - const BEST_FINALIZED_SOURCE_HEADER_ID_AT_TARGET: &'static str = - bp_rococo::BEST_FINALIZED_ROCOCO_HEADER_METHOD; + type SubmitFinalityProofCallBuilder = RococoFinalityToWococoCallBuilder; + type TransactionSignScheme = relay_wococo_client::Wococo; - type TargetChain = Wococo; - - fn customize_metrics(params: MetricsParams) -> anyhow::Result { - crate::chains::add_polkadot_kusama_price_metrics::(params) - } - - fn start_relay_guards(&self) { + fn start_relay_guards( + target_client: &relay_substrate_client::Client, + transaction_params: &TransactionParams, + ) { relay_substrate_client::guard::abort_on_spec_version_change( - self.finality_pipeline.target_client.clone(), + target_client.clone(), bp_wococo::VERSION.spec_version, ); relay_substrate_client::guard::abort_when_account_balance_decreased( - self.finality_pipeline.target_client.clone(), - self.transactions_author(), + target_client.clone(), + transaction_params.transactions_signer.public().into(), MAXIMAL_BALANCE_DECREASE_PER_DAY, ); } - - fn transactions_author(&self) -> bp_wococo::AccountId { - (*self.finality_pipeline.target_sign.public().as_array_ref()).into() - } - - fn make_submit_finality_proof_transaction( - &self, - era: bp_runtime::TransactionEraOf, - transaction_nonce: IndexOf, - header: RococoSyncHeader, - proof: GrandpaJustification, - ) -> Bytes { - let call = relay_wococo_client::runtime::Call::BridgeGrandpaRococo( - relay_wococo_client::runtime::BridgeGrandpaRococoCall::submit_finality_proof( - Box::new(header.into_inner()), - proof, - ), - ); - let genesis_hash = *self.finality_pipeline.target_client.genesis_hash(); - let transaction = Wococo::sign_transaction( - genesis_hash, - &self.finality_pipeline.target_sign, - era, - UnsignedTransaction::new(call, transaction_nonce), - ); - - Bytes(transaction.encode()) - } } diff --git a/bridges/relays/bin-substrate/src/chains/westend_headers_to_millau.rs b/bridges/relays/bin-substrate/src/chains/westend_headers_to_millau.rs index 211aa9da9b..2ec20a027f 100644 --- a/bridges/relays/bin-substrate/src/chains/westend_headers_to_millau.rs +++ b/bridges/relays/bin-substrate/src/chains/westend_headers_to_millau.rs @@ -16,78 +16,22 @@ //! Westend-to-Millau headers sync entrypoint. -use codec::Encode; -use sp_core::{Bytes, Pair}; - -use bp_header_chain::justification::GrandpaJustification; -use relay_millau_client::{Millau, SigningParams as MillauSigningParams}; -use relay_substrate_client::{Client, IndexOf, TransactionSignScheme, UnsignedTransaction}; -use relay_utils::metrics::MetricsParams; -use relay_westend_client::{SyncHeader as WestendSyncHeader, Westend}; use substrate_relay_helper::finality_pipeline::{ - SubstrateFinalitySyncPipeline, SubstrateFinalityToSubstrate, + DirectSubmitFinalityProofCallBuilder, SubstrateFinalitySyncPipeline, }; -/// Westend-to-Millau finality sync pipeline. -pub(crate) type FinalityPipelineWestendFinalityToMillau = - SubstrateFinalityToSubstrate; - +/// Description of Westend -> Millau finalized headers bridge. #[derive(Clone, Debug)] -pub(crate) struct WestendFinalityToMillau { - finality_pipeline: FinalityPipelineWestendFinalityToMillau, -} - -impl WestendFinalityToMillau { - pub fn new(target_client: Client, target_sign: MillauSigningParams) -> Self { - Self { - finality_pipeline: FinalityPipelineWestendFinalityToMillau::new( - target_client, - target_sign, - ), - } - } -} +pub struct WestendFinalityToMillau; impl SubstrateFinalitySyncPipeline for WestendFinalityToMillau { - type FinalitySyncPipeline = FinalityPipelineWestendFinalityToMillau; + type SourceChain = relay_westend_client::Westend; + type TargetChain = relay_millau_client::Millau; - const BEST_FINALIZED_SOURCE_HEADER_ID_AT_TARGET: &'static str = - bp_westend::BEST_FINALIZED_WESTEND_HEADER_METHOD; - - type TargetChain = Millau; - - fn customize_metrics(params: MetricsParams) -> anyhow::Result { - crate::chains::add_polkadot_kusama_price_metrics::(params) - } - - fn transactions_author(&self) -> bp_millau::AccountId { - (*self.finality_pipeline.target_sign.public().as_array_ref()).into() - } - - fn make_submit_finality_proof_transaction( - &self, - era: bp_runtime::TransactionEraOf, - transaction_nonce: IndexOf, - header: WestendSyncHeader, - proof: GrandpaJustification, - ) -> Bytes { - let call = millau_runtime::BridgeGrandpaCall::< - millau_runtime::Runtime, - millau_runtime::WestendGrandpaInstance, - >::submit_finality_proof { - finality_target: Box::new(header.into_inner()), - justification: proof, - } - .into(); - - let genesis_hash = *self.finality_pipeline.target_client.genesis_hash(); - let transaction = Millau::sign_transaction( - genesis_hash, - &self.finality_pipeline.target_sign, - era, - UnsignedTransaction::new(call, transaction_nonce), - ); - - Bytes(transaction.encode()) - } + type SubmitFinalityProofCallBuilder = DirectSubmitFinalityProofCallBuilder< + Self, + millau_runtime::Runtime, + millau_runtime::WestendGrandpaInstance, + >; + type TransactionSignScheme = relay_millau_client::Millau; } diff --git a/bridges/relays/bin-substrate/src/chains/wococo_headers_to_rococo.rs b/bridges/relays/bin-substrate/src/chains/wococo_headers_to_rococo.rs index fe17976d06..276a5b84da 100644 --- a/bridges/relays/bin-substrate/src/chains/wococo_headers_to_rococo.rs +++ b/bridges/relays/bin-substrate/src/chains/wococo_headers_to_rococo.rs @@ -16,17 +16,8 @@ //! Wococo-to-Rococo headers sync entrypoint. -use codec::Encode; -use sp_core::{Bytes, Pair}; - -use bp_header_chain::justification::GrandpaJustification; -use relay_rococo_client::{Rococo, SigningParams as RococoSigningParams}; -use relay_substrate_client::{Client, IndexOf, TransactionSignScheme, UnsignedTransaction}; -use relay_utils::metrics::MetricsParams; -use relay_wococo_client::{SyncHeader as WococoSyncHeader, Wococo}; -use substrate_relay_helper::finality_pipeline::{ - SubstrateFinalitySyncPipeline, SubstrateFinalityToSubstrate, -}; +use sp_core::Pair; +use substrate_relay_helper::finality_pipeline::{SubstrateFinalitySyncPipeline, TransactionParams}; /// Maximal saturating difference between `balance(now)` and `balance(now-24h)` to treat /// relay as gone wild. @@ -35,77 +26,37 @@ use substrate_relay_helper::finality_pipeline::{ /// Note that this is in plancks, so this corresponds to `1500 UNITS`. pub(crate) const MAXIMAL_BALANCE_DECREASE_PER_DAY: bp_rococo::Balance = 1_500_000_000_000_000; -/// Wococo-to-Rococo finality sync pipeline. -pub(crate) type FinalityPipelineWococoFinalityToRococo = - SubstrateFinalityToSubstrate; - +/// Description of Wococo -> Rococo finalized headers bridge. #[derive(Clone, Debug)] -pub(crate) struct WococoFinalityToRococo { - finality_pipeline: FinalityPipelineWococoFinalityToRococo, -} - -impl WococoFinalityToRococo { - pub fn new(target_client: Client, target_sign: RococoSigningParams) -> Self { - Self { - finality_pipeline: FinalityPipelineWococoFinalityToRococo::new( - target_client, - target_sign, - ), - } - } -} +pub struct WococoFinalityToRococo; +substrate_relay_helper::generate_mocked_submit_finality_proof_call_builder!( + WococoFinalityToRococo, + WococoFinalityToRococoCallBuilder, + relay_rococo_client::runtime::Call::BridgeGrandpaWococo, + relay_rococo_client::runtime::BridgeGrandpaWococoCall::submit_finality_proof +); impl SubstrateFinalitySyncPipeline for WococoFinalityToRococo { - type FinalitySyncPipeline = FinalityPipelineWococoFinalityToRococo; + type SourceChain = relay_wococo_client::Wococo; + type TargetChain = relay_rococo_client::Rococo; - const BEST_FINALIZED_SOURCE_HEADER_ID_AT_TARGET: &'static str = - bp_wococo::BEST_FINALIZED_WOCOCO_HEADER_METHOD; + type SubmitFinalityProofCallBuilder = WococoFinalityToRococoCallBuilder; + type TransactionSignScheme = relay_rococo_client::Rococo; - type TargetChain = Rococo; - - fn customize_metrics(params: MetricsParams) -> anyhow::Result { - crate::chains::add_polkadot_kusama_price_metrics::(params) - } - - fn start_relay_guards(&self) { + fn start_relay_guards( + target_client: &relay_substrate_client::Client, + transaction_params: &TransactionParams, + ) { relay_substrate_client::guard::abort_on_spec_version_change( - self.finality_pipeline.target_client.clone(), + target_client.clone(), bp_rococo::VERSION.spec_version, ); relay_substrate_client::guard::abort_when_account_balance_decreased( - self.finality_pipeline.target_client.clone(), - self.transactions_author(), + target_client.clone(), + transaction_params.transactions_signer.public().into(), MAXIMAL_BALANCE_DECREASE_PER_DAY, ); } - - fn transactions_author(&self) -> bp_rococo::AccountId { - (*self.finality_pipeline.target_sign.public().as_array_ref()).into() - } - - fn make_submit_finality_proof_transaction( - &self, - era: bp_runtime::TransactionEraOf, - transaction_nonce: IndexOf, - header: WococoSyncHeader, - proof: GrandpaJustification, - ) -> Bytes { - let call = relay_rococo_client::runtime::Call::BridgeGrandpaWococo( - relay_rococo_client::runtime::BridgeGrandpaWococoCall::submit_finality_proof( - Box::new(header.into_inner()), - proof, - ), - ); - let genesis_hash = *self.finality_pipeline.target_client.genesis_hash(); - let transaction = Rococo::sign_transaction( - genesis_hash, - &self.finality_pipeline.target_sign, - era, - UnsignedTransaction::new(call, transaction_nonce), - ); - - Bytes(transaction.encode()) - } } #[cfg(test)] diff --git a/bridges/relays/bin-substrate/src/cli/relay_headers.rs b/bridges/relays/bin-substrate/src/cli/relay_headers.rs index 82c55965a9..a8179478f8 100644 --- a/bridges/relays/bin-substrate/src/cli/relay_headers.rs +++ b/bridges/relays/bin-substrate/src/cli/relay_headers.rs @@ -121,18 +121,22 @@ impl RelayHeaders { let target_client = self.target.to_client::().await?; let target_transactions_mortality = self.target_sign.target_transactions_mortality; let target_sign = self.target_sign.to_keypair::()?; - let metrics_params = Finality::customize_metrics(self.prometheus_params.into())?; + + let metrics_params: relay_utils::metrics::MetricsParams = self.prometheus_params.into(); GlobalMetrics::new()?.register_and_spawn(&metrics_params.registry)?; - let finality = Finality::new(target_client.clone(), target_sign); - finality.start_relay_guards(); + let target_transactions_params = + substrate_relay_helper::finality_pipeline::TransactionParams { + transactions_signer: target_sign, + transactions_mortality: target_transactions_mortality, + }; + Finality::start_relay_guards(&target_client, &target_transactions_params); - substrate_relay_helper::finality_pipeline::run( - finality, + substrate_relay_helper::finality_pipeline::run::( source_client, target_client, self.only_mandatory_headers, - target_transactions_mortality, + target_transactions_params, metrics_params, ) .await 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 7755df39ed..86b2fbfb4d 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 @@ -489,25 +489,35 @@ impl RelayHeadersAndMessages { } // start on-demand header relays - let left_to_right_finality = - LeftToRightFinality::new(right_client.clone(), right_sign.clone()); - let right_to_left_finality = - RightToLeftFinality::new(left_client.clone(), left_sign.clone()); - left_to_right_finality.start_relay_guards(); - right_to_left_finality.start_relay_guards(); - let left_to_right_on_demand_headers = OnDemandHeadersRelay::new( + let left_to_right_transaction_params = + substrate_relay_helper::finality_pipeline::TransactionParams { + transactions_mortality: right_transactions_mortality, + transactions_signer: right_sign.clone(), + }; + let right_to_left_transaction_params = + substrate_relay_helper::finality_pipeline::TransactionParams { + transactions_mortality: left_transactions_mortality, + transactions_signer: left_sign.clone(), + }; + LeftToRightFinality::start_relay_guards( + &right_client, + &left_to_right_transaction_params, + ); + RightToLeftFinality::start_relay_guards( + &left_client, + &right_to_left_transaction_params, + ); + let left_to_right_on_demand_headers = OnDemandHeadersRelay::new::( left_client.clone(), right_client.clone(), - right_transactions_mortality, - left_to_right_finality, + left_to_right_transaction_params, MAX_MISSING_LEFT_HEADERS_AT_RIGHT, params.shared.only_mandatory_headers, ); - let right_to_left_on_demand_headers = OnDemandHeadersRelay::new( + let right_to_left_on_demand_headers = OnDemandHeadersRelay::new::( right_client.clone(), left_client.clone(), - left_transactions_mortality, - right_to_left_finality, + right_to_left_transaction_params, MAX_MISSING_RIGHT_HEADERS_AT_LEFT, params.shared.only_mandatory_headers, ); diff --git a/bridges/relays/client-kusama/src/lib.rs b/bridges/relays/client-kusama/src/lib.rs index a93726620f..b1ea0f5fef 100644 --- a/bridges/relays/client-kusama/src/lib.rs +++ b/bridges/relays/client-kusama/src/lib.rs @@ -48,6 +48,8 @@ impl ChainBase for Kusama { impl Chain for Kusama { const NAME: &'static str = "Kusama"; + const BEST_FINALIZED_HEADER_ID_METHOD: &'static str = + bp_kusama::BEST_FINALIZED_KUSAMA_HEADER_METHOD; const AVERAGE_BLOCK_INTERVAL: Duration = Duration::from_secs(6); const STORAGE_PROOF_OVERHEAD: u32 = bp_kusama::EXTRA_STORAGE_PROOF_SIZE; const MAXIMAL_ENCODED_ACCOUNT_ID_SIZE: u32 = bp_kusama::MAXIMAL_ENCODED_ACCOUNT_ID_SIZE; diff --git a/bridges/relays/client-millau/src/lib.rs b/bridges/relays/client-millau/src/lib.rs index 3f1aba1f3b..e7ee54afb0 100644 --- a/bridges/relays/client-millau/src/lib.rs +++ b/bridges/relays/client-millau/src/lib.rs @@ -46,6 +46,8 @@ impl ChainBase for Millau { impl Chain for Millau { const NAME: &'static str = "Millau"; + const BEST_FINALIZED_HEADER_ID_METHOD: &'static str = + bp_millau::BEST_FINALIZED_MILLAU_HEADER_METHOD; const AVERAGE_BLOCK_INTERVAL: Duration = Duration::from_secs(5); const STORAGE_PROOF_OVERHEAD: u32 = bp_millau::EXTRA_STORAGE_PROOF_SIZE; const MAXIMAL_ENCODED_ACCOUNT_ID_SIZE: u32 = bp_millau::MAXIMAL_ENCODED_ACCOUNT_ID_SIZE; diff --git a/bridges/relays/client-polkadot/src/lib.rs b/bridges/relays/client-polkadot/src/lib.rs index e6ceabf583..e5c7f62fa1 100644 --- a/bridges/relays/client-polkadot/src/lib.rs +++ b/bridges/relays/client-polkadot/src/lib.rs @@ -48,6 +48,8 @@ impl ChainBase for Polkadot { impl Chain for Polkadot { const NAME: &'static str = "Polkadot"; + const BEST_FINALIZED_HEADER_ID_METHOD: &'static str = + bp_polkadot::BEST_FINALIZED_POLKADOT_HEADER_METHOD; const AVERAGE_BLOCK_INTERVAL: Duration = Duration::from_secs(6); const STORAGE_PROOF_OVERHEAD: u32 = bp_polkadot::EXTRA_STORAGE_PROOF_SIZE; const MAXIMAL_ENCODED_ACCOUNT_ID_SIZE: u32 = bp_polkadot::MAXIMAL_ENCODED_ACCOUNT_ID_SIZE; diff --git a/bridges/relays/client-rialto-parachain/src/lib.rs b/bridges/relays/client-rialto-parachain/src/lib.rs index ca299a0eeb..b34154393a 100644 --- a/bridges/relays/client-rialto-parachain/src/lib.rs +++ b/bridges/relays/client-rialto-parachain/src/lib.rs @@ -41,6 +41,8 @@ impl ChainBase for RialtoParachain { impl Chain for RialtoParachain { const NAME: &'static str = "RialtoParachain"; + // should be fixed/changed in https://github.com/paritytech/parity-bridges-common/pull/1199 + const BEST_FINALIZED_HEADER_ID_METHOD: &'static str = ""; const AVERAGE_BLOCK_INTERVAL: Duration = Duration::from_secs(5); const STORAGE_PROOF_OVERHEAD: u32 = bp_rialto::EXTRA_STORAGE_PROOF_SIZE; const MAXIMAL_ENCODED_ACCOUNT_ID_SIZE: u32 = bp_rialto::MAXIMAL_ENCODED_ACCOUNT_ID_SIZE; diff --git a/bridges/relays/client-rialto/src/lib.rs b/bridges/relays/client-rialto/src/lib.rs index 42ed8bce3b..60c6e9388b 100644 --- a/bridges/relays/client-rialto/src/lib.rs +++ b/bridges/relays/client-rialto/src/lib.rs @@ -46,6 +46,8 @@ impl ChainBase for Rialto { impl Chain for Rialto { const NAME: &'static str = "Rialto"; + const BEST_FINALIZED_HEADER_ID_METHOD: &'static str = + bp_rialto::BEST_FINALIZED_RIALTO_HEADER_METHOD; const AVERAGE_BLOCK_INTERVAL: Duration = Duration::from_secs(5); const STORAGE_PROOF_OVERHEAD: u32 = bp_rialto::EXTRA_STORAGE_PROOF_SIZE; const MAXIMAL_ENCODED_ACCOUNT_ID_SIZE: u32 = bp_rialto::MAXIMAL_ENCODED_ACCOUNT_ID_SIZE; diff --git a/bridges/relays/client-rococo/src/lib.rs b/bridges/relays/client-rococo/src/lib.rs index ad61e3cfd6..7ee51730e9 100644 --- a/bridges/relays/client-rococo/src/lib.rs +++ b/bridges/relays/client-rococo/src/lib.rs @@ -51,6 +51,8 @@ impl ChainBase for Rococo { impl Chain for Rococo { const NAME: &'static str = "Rococo"; + const BEST_FINALIZED_HEADER_ID_METHOD: &'static str = + bp_rococo::BEST_FINALIZED_ROCOCO_HEADER_METHOD; const AVERAGE_BLOCK_INTERVAL: Duration = Duration::from_secs(6); const STORAGE_PROOF_OVERHEAD: u32 = bp_rococo::EXTRA_STORAGE_PROOF_SIZE; const MAXIMAL_ENCODED_ACCOUNT_ID_SIZE: u32 = bp_rococo::MAXIMAL_ENCODED_ACCOUNT_ID_SIZE; diff --git a/bridges/relays/client-substrate/src/chain.rs b/bridges/relays/client-substrate/src/chain.rs index 75789ce37f..97063c15c8 100644 --- a/bridges/relays/client-substrate/src/chain.rs +++ b/bridges/relays/client-substrate/src/chain.rs @@ -32,6 +32,13 @@ use std::{fmt::Debug, time::Duration}; pub trait Chain: ChainBase + Clone { /// Chain name. const NAME: &'static str; + /// Name of the runtime API method that is returning best known finalized header number + /// and hash (as tuple). + /// + /// Keep in mind that this method is normally provided by the other chain, which is + /// bridged with this chain. + const BEST_FINALIZED_HEADER_ID_METHOD: &'static str; + /// Average block interval. /// /// How often blocks are produced on that chain. It's suggested to set this value @@ -45,7 +52,7 @@ pub trait Chain: ChainBase + Clone { /// Block type. type SignedBlock: Member + Serialize + DeserializeOwned + BlockWithJustification; /// The aggregated `Call` type. - type Call: Clone + Dispatchable + Debug; + type Call: Clone + Dispatchable + Debug + Send; /// Type that is used by the chain, to convert from weight to fee. type WeightToFee: WeightToFeePolynomial; @@ -102,6 +109,9 @@ impl UnsignedTransaction { } } +/// Account key pair used by transactions signing scheme. +pub type AccountKeyPairOf = ::AccountKeyPair; + /// Substrate-based chain transactions signing scheme. pub trait TransactionSignScheme { /// Chain that this scheme is to be used. diff --git a/bridges/relays/client-substrate/src/guard.rs b/bridges/relays/client-substrate/src/guard.rs index a064e36234..93b76bdf9f 100644 --- a/bridges/relays/client-substrate/src/guard.rs +++ b/bridges/relays/client-substrate/src/guard.rs @@ -206,6 +206,7 @@ mod tests { impl Chain for TestChain { const NAME: &'static str = "Test"; + const BEST_FINALIZED_HEADER_ID_METHOD: &'static str = "BestTestHeader"; const AVERAGE_BLOCK_INTERVAL: Duration = Duration::from_millis(1); const STORAGE_PROOF_OVERHEAD: u32 = 0; const MAXIMAL_ENCODED_ACCOUNT_ID_SIZE: u32 = 0; diff --git a/bridges/relays/client-substrate/src/lib.rs b/bridges/relays/client-substrate/src/lib.rs index 51ddf852b9..f03b79228b 100644 --- a/bridges/relays/client-substrate/src/lib.rs +++ b/bridges/relays/client-substrate/src/lib.rs @@ -24,7 +24,6 @@ mod error; mod rpc; mod sync_header; -pub mod finality_source; pub mod guard; pub mod metrics; @@ -32,8 +31,8 @@ use std::time::Duration; pub use crate::{ chain::{ - BlockWithJustification, CallOf, Chain, ChainWithBalances, TransactionSignScheme, - TransactionStatusOf, UnsignedTransaction, WeightToFeeOf, + AccountKeyPairOf, BlockWithJustification, CallOf, Chain, ChainWithBalances, + TransactionSignScheme, TransactionStatusOf, UnsignedTransaction, WeightToFeeOf, }, client::{Client, OpaqueGrandpaAuthoritiesSet, Subscription}, error::{Error, Result}, diff --git a/bridges/relays/client-westend/src/lib.rs b/bridges/relays/client-westend/src/lib.rs index c719d6ea55..6d43aa837b 100644 --- a/bridges/relays/client-westend/src/lib.rs +++ b/bridges/relays/client-westend/src/lib.rs @@ -44,6 +44,8 @@ impl ChainBase for Westend { impl Chain for Westend { const NAME: &'static str = "Westend"; + const BEST_FINALIZED_HEADER_ID_METHOD: &'static str = + bp_westend::BEST_FINALIZED_WESTEND_HEADER_METHOD; const AVERAGE_BLOCK_INTERVAL: Duration = Duration::from_secs(6); const STORAGE_PROOF_OVERHEAD: u32 = bp_westend::EXTRA_STORAGE_PROOF_SIZE; const MAXIMAL_ENCODED_ACCOUNT_ID_SIZE: u32 = bp_westend::MAXIMAL_ENCODED_ACCOUNT_ID_SIZE; diff --git a/bridges/relays/client-wococo/src/lib.rs b/bridges/relays/client-wococo/src/lib.rs index d61915ec12..a15ff46999 100644 --- a/bridges/relays/client-wococo/src/lib.rs +++ b/bridges/relays/client-wococo/src/lib.rs @@ -51,6 +51,8 @@ impl ChainBase for Wococo { impl Chain for Wococo { const NAME: &'static str = "Wococo"; + const BEST_FINALIZED_HEADER_ID_METHOD: &'static str = + bp_wococo::BEST_FINALIZED_WOCOCO_HEADER_METHOD; const AVERAGE_BLOCK_INTERVAL: Duration = Duration::from_secs(6); const STORAGE_PROOF_OVERHEAD: u32 = bp_wococo::EXTRA_STORAGE_PROOF_SIZE; const MAXIMAL_ENCODED_ACCOUNT_ID_SIZE: u32 = bp_wococo::MAXIMAL_ENCODED_ACCOUNT_ID_SIZE; diff --git a/bridges/relays/lib-substrate-relay/Cargo.toml b/bridges/relays/lib-substrate-relay/Cargo.toml index 5bee10856d..89d03803b3 100644 --- a/bridges/relays/lib-substrate-relay/Cargo.toml +++ b/bridges/relays/lib-substrate-relay/Cargo.toml @@ -27,6 +27,7 @@ relay-utils = { path = "../utils" } messages-relay = { path = "../messages" } relay-substrate-client = { path = "../client-substrate" } +pallet-bridge-grandpa = { path = "../../modules/grandpa" } pallet-bridge-messages = { path = "../../modules/messages" } bp-runtime = { path = "../../primitives/runtime" } diff --git a/bridges/relays/lib-substrate-relay/src/finality_pipeline.rs b/bridges/relays/lib-substrate-relay/src/finality_pipeline.rs index cdfbb3354d..1266ed59ed 100644 --- a/bridges/relays/lib-substrate-relay/src/finality_pipeline.rs +++ b/bridges/relays/lib-substrate-relay/src/finality_pipeline.rs @@ -14,18 +14,20 @@ // You should have received a copy of the GNU General Public License // along with Parity Bridges Common. If not, see . -//! Substrate-to-Substrate headers sync entrypoint. +//! Types and functions intended to ease adding of new Substrate -> Substrate +//! finality proofs synchronization pipelines. -use crate::{finality_target::SubstrateFinalityTarget, STALL_TIMEOUT}; +use crate::{finality_source::SubstrateFinalitySource, finality_target::SubstrateFinalityTarget}; use bp_header_chain::justification::GrandpaJustification; -use bp_runtime::AccountIdOf; -use finality_relay::{FinalitySyncParams, FinalitySyncPipeline}; +use finality_relay::FinalitySyncPipeline; +use pallet_bridge_grandpa::{Call as BridgeGrandpaCall, Config as BridgeGrandpaConfig}; use relay_substrate_client::{ - finality_source::FinalitySource, BlockNumberOf, Chain, Client, HashOf, SyncHeader, + transaction_stall_timeout, AccountIdOf, AccountKeyPairOf, BlockNumberOf, CallOf, Chain, Client, + HashOf, HeaderOf, SyncHeader, TransactionSignScheme, }; -use relay_utils::{metrics::MetricsParams, BlockNumberBase}; -use sp_core::Bytes; +use relay_utils::metrics::MetricsParams; +use sp_core::Pair; use std::{fmt::Debug, marker::PhantomData}; /// Default limit of recent finality proofs. @@ -34,130 +36,152 @@ use std::{fmt::Debug, marker::PhantomData}; /// Substrate+GRANDPA based chains (good to know). pub(crate) const RECENT_FINALITY_PROOFS_LIMIT: usize = 4096; -/// Headers sync pipeline for Substrate <-> Substrate relays. +/// Submit-finality-proofs transaction creation parameters. +#[derive(Clone, Debug)] +pub struct TransactionParams { + /// Transactions author. + pub transactions_signer: TS, + /// Transactions mortality. + pub transactions_mortality: Option, +} + +/// Substrate -> Substrate finality proofs synchronization pipeline. pub trait SubstrateFinalitySyncPipeline: 'static + Clone + Debug + Send + Sync { - /// Pipeline for syncing finalized Source chain headers to Target chain. - type FinalitySyncPipeline: FinalitySyncPipeline; - - /// Name of the runtime method that returns id of best finalized source header at target chain. - const BEST_FINALIZED_SOURCE_HEADER_ID_AT_TARGET: &'static str; - - /// Chain with GRANDPA bridge pallet. + /// Headers of this chain are submitted to the `TargetChain`. + type SourceChain: Chain; + /// Headers of the `SourceChain` are submitted to this chain. type TargetChain: Chain; - /// Customize metrics exposed by headers sync loop. - fn customize_metrics(params: MetricsParams) -> anyhow::Result { - Ok(params) - } + /// How submit finality proof call is built? + type SubmitFinalityProofCallBuilder: SubmitFinalityProofCallBuilder; + /// Scheme used to sign target chain transactions. + type TransactionSignScheme: TransactionSignScheme; - /// Start finality relay guards. - /// - /// Different finality bridges may have different set of guards - e.g. on ephemeral chains we - /// don't need a version guards, on test chains we don't care that much about relayer account - /// balance, ... So the implementation is left to the specific bridges. - fn start_relay_guards(&self) {} - - /// Returns id of account that we're using to sign transactions at target chain. - fn transactions_author(&self) -> AccountIdOf; - - /// Make submit header transaction. - fn make_submit_finality_proof_transaction( - &self, - era: bp_runtime::TransactionEraOf, - transaction_nonce: bp_runtime::IndexOf, - header: ::Header, - proof: ::FinalityProof, - ) -> Bytes; -} - -/// Substrate-to-Substrate finality proof pipeline. -#[derive(Clone)] -pub struct SubstrateFinalityToSubstrate { - /// Client for the target chain. - pub target_client: Client, - /// Data required to sign target chain transactions. - pub target_sign: TargetSign, - /// Unused generic arguments dump. - _marker: PhantomData, -} - -impl Debug - for SubstrateFinalityToSubstrate -{ - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - f.debug_struct("SubstrateFinalityToSubstrate") - .field("target_client", &self.target_client) - .finish() + /// Add relay guards if required. + fn start_relay_guards( + _target_client: &Client, + _transaction_params: &TransactionParams>, + ) { } } -impl - SubstrateFinalityToSubstrate -{ - /// Create new Substrate-to-Substrate headers pipeline. - pub fn new(target_client: Client, target_sign: TargetSign) -> Self { - SubstrateFinalityToSubstrate { target_client, target_sign, _marker: Default::default() } - } +/// Adapter that allows all `SubstrateFinalitySyncPipeline` to act as `FinalitySyncPipeline`. +#[derive(Clone, Debug)] +pub struct FinalitySyncPipelineAdapter { + _phantom: PhantomData

, } -impl FinalitySyncPipeline - for SubstrateFinalityToSubstrate +impl FinalitySyncPipeline for FinalitySyncPipelineAdapter

{ + const SOURCE_NAME: &'static str = P::SourceChain::NAME; + const TARGET_NAME: &'static str = P::TargetChain::NAME; + + type Hash = HashOf; + type Number = BlockNumberOf; + type Header = relay_substrate_client::SyncHeader>; + type FinalityProof = GrandpaJustification>; +} + +/// Different ways of building `submit_finality_proof` calls. +pub trait SubmitFinalityProofCallBuilder { + /// Given source chain header and its finality proofs, build call of `submit_finality_proof` + /// function of bridge GRANDPA module at the target chain. + fn build_submit_finality_proof_call( + header: SyncHeader>, + proof: GrandpaJustification>, + ) -> CallOf; +} + +/// Building `submit_finality_proof` call when you have direct access to the target +/// chain runtime. +pub struct DirectSubmitFinalityProofCallBuilder { + _phantom: PhantomData<(P, R, I)>, +} + +impl SubmitFinalityProofCallBuilder

for DirectSubmitFinalityProofCallBuilder where - SourceChain: Clone + Chain + Debug, - BlockNumberOf: BlockNumberBase, - TargetChain: Clone + Chain + Debug, - TargetSign: 'static + Clone + Send + Sync, + P: SubstrateFinalitySyncPipeline, + R: BridgeGrandpaConfig, + I: 'static, + R::BridgedChain: bp_runtime::Chain

>, + CallOf: From>, { - const SOURCE_NAME: &'static str = SourceChain::NAME; - const TARGET_NAME: &'static str = TargetChain::NAME; - - type Hash = HashOf; - type Number = BlockNumberOf; - type Header = SyncHeader; - type FinalityProof = GrandpaJustification; + fn build_submit_finality_proof_call( + header: SyncHeader>, + proof: GrandpaJustification>, + ) -> CallOf { + BridgeGrandpaCall::::submit_finality_proof { + finality_target: Box::new(header.into_inner()), + justification: proof, + } + .into() + } } -/// Run Substrate-to-Substrate finality sync. -pub async fn run( - pipeline: P, - source_client: Client, - target_client: Client, +/// Macro that generates `SubmitFinalityProofCallBuilder` implementation for the case when +/// you only have an access to the mocked version of target chain runtime. In this case you +/// should provide "name" of the call variant for the bridge GRANDPA calls and the "name" of +/// the variant for the `submit_finality_proof` call within that first option. +#[rustfmt::skip] +#[macro_export] +macro_rules! generate_mocked_submit_finality_proof_call_builder { + ($pipeline:ident, $mocked_builder:ident, $bridge_grandpa:path, $submit_finality_proof:path) => { + pub struct $mocked_builder; + + impl $crate::finality_pipeline::SubmitFinalityProofCallBuilder<$pipeline> + for $mocked_builder + { + fn build_submit_finality_proof_call( + header: relay_substrate_client::SyncHeader< + relay_substrate_client::HeaderOf< + <$pipeline as $crate::finality_pipeline::SubstrateFinalitySyncPipeline>::SourceChain + > + >, + proof: bp_header_chain::justification::GrandpaJustification< + relay_substrate_client::HeaderOf< + <$pipeline as $crate::finality_pipeline::SubstrateFinalitySyncPipeline>::SourceChain + > + >, + ) -> relay_substrate_client::CallOf< + <$pipeline as $crate::finality_pipeline::SubstrateFinalitySyncPipeline>::TargetChain + > { + $bridge_grandpa($submit_finality_proof(Box::new(header.into_inner()), proof)) + } + } + }; +} + +/// Run Substrate-to-Substrate finality sync loop. +pub async fn run( + source_client: Client, + target_client: Client, only_mandatory_headers: bool, - transactions_mortality: Option, + transaction_params: TransactionParams>, metrics_params: MetricsParams, ) -> anyhow::Result<()> where - P: SubstrateFinalitySyncPipeline, - P::FinalitySyncPipeline: FinalitySyncPipeline< - Hash = HashOf, - Number = BlockNumberOf, - Header = SyncHeader, - FinalityProof = GrandpaJustification, - >, - SourceChain: Clone + Chain, - BlockNumberOf: BlockNumberBase, - TargetChain: Clone + Chain, + AccountIdOf: From< as Pair>::Public>, + P::TransactionSignScheme: TransactionSignScheme, { log::info!( target: "bridge", "Starting {} -> {} finality proof relay", - SourceChain::NAME, - TargetChain::NAME, + P::SourceChain::NAME, + P::TargetChain::NAME, ); finality_relay::run( - FinalitySource::new(source_client, None), - SubstrateFinalityTarget::new(target_client, pipeline, transactions_mortality), - FinalitySyncParams { + SubstrateFinalitySource::

::new(source_client, None), + SubstrateFinalityTarget::

::new(target_client, transaction_params.clone()), + finality_relay::FinalitySyncParams { tick: std::cmp::max( - SourceChain::AVERAGE_BLOCK_INTERVAL, - TargetChain::AVERAGE_BLOCK_INTERVAL, + P::SourceChain::AVERAGE_BLOCK_INTERVAL, + P::TargetChain::AVERAGE_BLOCK_INTERVAL, ), recent_finality_proofs_limit: RECENT_FINALITY_PROOFS_LIMIT, - stall_timeout: relay_substrate_client::transaction_stall_timeout( - transactions_mortality, - TargetChain::AVERAGE_BLOCK_INTERVAL, - STALL_TIMEOUT, + stall_timeout: transaction_stall_timeout( + transaction_params.transactions_mortality, + P::TargetChain::AVERAGE_BLOCK_INTERVAL, + crate::STALL_TIMEOUT, ), only_mandatory_headers, }, diff --git a/bridges/relays/client-substrate/src/finality_source.rs b/bridges/relays/lib-substrate-relay/src/finality_source.rs similarity index 66% rename from bridges/relays/client-substrate/src/finality_source.rs rename to bridges/relays/lib-substrate-relay/src/finality_source.rs index 98526de178..804d321293 100644 --- a/bridges/relays/client-substrate/src/finality_source.rs +++ b/bridges/relays/lib-substrate-relay/src/finality_source.rs @@ -16,49 +16,59 @@ //! Default generic implementation of finality source for basic Substrate client. -use crate::{ - chain::{BlockWithJustification, Chain}, - client::Client, - error::Error, - sync_header::SyncHeader, -}; +use crate::finality_pipeline::{FinalitySyncPipelineAdapter, SubstrateFinalitySyncPipeline}; use async_std::sync::{Arc, Mutex}; use async_trait::async_trait; use bp_header_chain::justification::GrandpaJustification; use codec::Decode; -use finality_relay::{FinalitySyncPipeline, SourceClient, SourceHeader}; +use finality_relay::SourceClient; use futures::stream::{unfold, Stream, StreamExt}; +use relay_substrate_client::{ + BlockNumberOf, BlockWithJustification, Chain, Client, Error, HeaderOf, +}; use relay_utils::relay_loop::Client as RelayClient; use sp_runtime::traits::Header as HeaderT; -use std::{marker::PhantomData, pin::Pin}; +use std::pin::Pin; /// Shared updatable reference to the maximal header number that we want to sync from the source. pub type RequiredHeaderNumberRef = Arc::BlockNumber>>; +/// Substrate finality proofs stream. +pub type SubstrateFinalityProofsStream

= Pin< + Box< + dyn Stream< + Item = GrandpaJustification< + HeaderOf<

::SourceChain>, + >, + > + Send, + >, +>; + /// Substrate node as finality source. -pub struct FinalitySource { - client: Client, - maximal_header_number: Option>, - _phantom: PhantomData

, +pub struct SubstrateFinalitySource { + client: Client, + maximal_header_number: Option>, } -impl FinalitySource { +impl SubstrateFinalitySource

{ /// Create new headers source using given client. pub fn new( - client: Client, - maximal_header_number: Option>, + client: Client, + maximal_header_number: Option>, ) -> Self { - FinalitySource { client, maximal_header_number, _phantom: Default::default() } + SubstrateFinalitySource { client, maximal_header_number } } /// Returns reference to the underlying RPC client. - pub fn client(&self) -> &Client { + pub fn client(&self) -> &Client { &self.client } /// Returns best finalized block number. - pub async fn on_chain_best_finalized_block_number(&self) -> Result { + pub async fn on_chain_best_finalized_block_number( + &self, + ) -> Result, Error> { // we **CAN** continue to relay finality proofs if source node is out of sync, because // target node may be missing proofs that are already available at the source let finalized_header_hash = self.client.best_finalized_header_hash().await?; @@ -67,18 +77,17 @@ impl FinalitySource { } } -impl Clone for FinalitySource { +impl Clone for SubstrateFinalitySource

{ fn clone(&self) -> Self { - FinalitySource { + SubstrateFinalitySource { client: self.client.clone(), maximal_header_number: self.maximal_header_number.clone(), - _phantom: Default::default(), } } } #[async_trait] -impl RelayClient for FinalitySource { +impl RelayClient for SubstrateFinalitySource

{ type Error = Error; async fn reconnect(&mut self) -> Result<(), Error> { @@ -87,21 +96,12 @@ impl RelayClient for FinalitySource { } #[async_trait] -impl SourceClient

for FinalitySource -where - C: Chain, - C::BlockNumber: relay_utils::BlockNumberBase, - P: FinalitySyncPipeline< - Hash = C::Hash, - Number = C::BlockNumber, - Header = SyncHeader, - FinalityProof = GrandpaJustification, - >, - P::Header: SourceHeader, +impl SourceClient> + for SubstrateFinalitySource

{ - type FinalityProofsStream = Pin> + Send>>; + type FinalityProofsStream = SubstrateFinalityProofsStream

; - async fn best_finalized_block_number(&self) -> Result { + async fn best_finalized_block_number(&self) -> Result, Error> { let mut finalized_header_number = self.on_chain_best_finalized_block_number().await?; // never return block number larger than requested. This way we'll never sync headers // past `maximal_header_number` @@ -116,15 +116,23 @@ where async fn header_and_finality_proof( &self, - number: P::Number, - ) -> Result<(P::Header, Option), Error> { + number: BlockNumberOf, + ) -> Result< + ( + relay_substrate_client::SyncHeader>, + Option>>, + ), + Error, + > { let header_hash = self.client.block_hash_by_number(number).await?; let signed_block = self.client.get_block(Some(header_hash)).await?; let justification = signed_block .justification() .map(|raw_justification| { - GrandpaJustification::::decode(&mut raw_justification.as_slice()) + GrandpaJustification::>::decode( + &mut raw_justification.as_slice(), + ) }) .transpose() .map_err(Error::ResponseParseFailed)?; @@ -141,7 +149,7 @@ where log::error!( target: "bridge", "Failed to read justification target from the {} justifications stream: {:?}", - P::SOURCE_NAME, + P::SourceChain::NAME, err, ); }; @@ -153,7 +161,9 @@ where .ok()??; let decoded_justification = - GrandpaJustification::::decode(&mut &next_justification[..]); + GrandpaJustification::>::decode( + &mut &next_justification[..], + ); let justification = match decoded_justification { Ok(j) => j, diff --git a/bridges/relays/lib-substrate-relay/src/finality_target.rs b/bridges/relays/lib-substrate-relay/src/finality_target.rs index f50bd103f4..adfe12ab35 100644 --- a/bridges/relays/lib-substrate-relay/src/finality_target.rs +++ b/bridges/relays/lib-substrate-relay/src/finality_target.rs @@ -15,70 +15,78 @@ // along with Parity Bridges Common. If not, see . //! Substrate client as Substrate finality proof target. The chain we connect to should have -//! runtime that implements `FinalityApi` to allow bridging with -//! chain. +//! bridge GRANDPA pallet deployed and provide `FinalityApi` to allow bridging +//! with chain. -use crate::finality_pipeline::SubstrateFinalitySyncPipeline; +use crate::finality_pipeline::{ + FinalitySyncPipelineAdapter, SubmitFinalityProofCallBuilder, SubstrateFinalitySyncPipeline, + TransactionParams, +}; use async_trait::async_trait; -use codec::Decode; -use finality_relay::{FinalitySyncPipeline, TargetClient}; -use relay_substrate_client::{Chain, Client, Error as SubstrateError}; +use bp_header_chain::justification::GrandpaJustification; +use codec::Encode; +use finality_relay::TargetClient; +use relay_substrate_client::{ + AccountIdOf, AccountKeyPairOf, BlockNumberOf, Chain, Client, Error, HashOf, HeaderOf, + SyncHeader, TransactionEra, TransactionSignScheme, UnsignedTransaction, +}; use relay_utils::relay_loop::Client as RelayClient; +use sp_core::{Bytes, Pair}; /// Substrate client as Substrate finality target. -pub struct SubstrateFinalityTarget { - client: Client, - pipeline: P, - transactions_mortality: Option, +pub struct SubstrateFinalityTarget { + client: Client, + transaction_params: TransactionParams>, } -impl SubstrateFinalityTarget { +impl SubstrateFinalityTarget

{ /// Create new Substrate headers target. - pub fn new(client: Client, pipeline: P, transactions_mortality: Option) -> Self { - SubstrateFinalityTarget { client, pipeline, transactions_mortality } + pub fn new( + client: Client, + transaction_params: TransactionParams>, + ) -> Self { + SubstrateFinalityTarget { client, transaction_params } } } -impl Clone for SubstrateFinalityTarget { +impl Clone for SubstrateFinalityTarget

{ fn clone(&self) -> Self { SubstrateFinalityTarget { client: self.client.clone(), - pipeline: self.pipeline.clone(), - transactions_mortality: self.transactions_mortality, + transaction_params: self.transaction_params.clone(), } } } #[async_trait] -impl RelayClient for SubstrateFinalityTarget { - type Error = SubstrateError; +impl RelayClient for SubstrateFinalityTarget

{ + type Error = Error; - async fn reconnect(&mut self) -> Result<(), SubstrateError> { + async fn reconnect(&mut self) -> Result<(), Error> { self.client.reconnect().await } } #[async_trait] -impl TargetClient for SubstrateFinalityTarget +impl TargetClient> + for SubstrateFinalityTarget

where - C: Chain, - P: SubstrateFinalitySyncPipeline, - ::Number: Decode, - ::Hash: Decode, + AccountIdOf: From< as Pair>::Public>, + P::TransactionSignScheme: TransactionSignScheme, { async fn best_finalized_source_block_number( &self, - ) -> Result<::Number, SubstrateError> { + ) -> Result, Error> { // we can't continue to relay finality if target node is out of sync, because // it may have already received (some of) headers that we're going to relay self.client.ensure_synced().await?; Ok(crate::messages_source::read_client_state::< - C, - ::Hash, - ::Number, - >(&self.client, P::BEST_FINALIZED_SOURCE_HEADER_ID_AT_TARGET) + P::TargetChain, + HashOf, + BlockNumberOf, + >(&self.client, P::SourceChain::BEST_FINALIZED_HEADER_ID_METHOD) .await? .best_finalized_peer_at_best_self .0) @@ -86,24 +94,28 @@ where async fn submit_finality_proof( &self, - header: ::Header, - proof: ::FinalityProof, - ) -> Result<(), SubstrateError> { - let transactions_author = self.pipeline.transactions_author(); - let pipeline = self.pipeline.clone(); - let transactions_mortality = self.transactions_mortality; + header: SyncHeader>, + proof: GrandpaJustification>, + ) -> Result<(), Error> { + let genesis_hash = *self.client.genesis_hash(); + let transaction_params = self.transaction_params.clone(); + let call = + P::SubmitFinalityProofCallBuilder::build_submit_finality_proof_call(header, proof); self.client .submit_signed_extrinsic( - transactions_author, + self.transaction_params.transactions_signer.public().into(), move |best_block_id, transaction_nonce| { - pipeline.make_submit_finality_proof_transaction( - relay_substrate_client::TransactionEra::new( - best_block_id, - transactions_mortality, - ), - transaction_nonce, - header, - proof, + Bytes( + P::TransactionSignScheme::sign_transaction( + genesis_hash, + &transaction_params.transactions_signer, + TransactionEra::new( + best_block_id, + transaction_params.transactions_mortality, + ), + UnsignedTransaction::new(call, transaction_nonce), + ) + .encode(), ) }, ) diff --git a/bridges/relays/lib-substrate-relay/src/lib.rs b/bridges/relays/lib-substrate-relay/src/lib.rs index cc066bf501..1c62ddaa9a 100644 --- a/bridges/relays/lib-substrate-relay/src/lib.rs +++ b/bridges/relays/lib-substrate-relay/src/lib.rs @@ -23,6 +23,7 @@ use std::time::Duration; pub mod conversion_rate_update; pub mod error; pub mod finality_pipeline; +pub mod finality_source; pub mod finality_target; pub mod headers_initialize; pub mod helpers; 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 ee141866eb..5a170d5cbf 100644 --- a/bridges/relays/lib-substrate-relay/src/on_demand_headers.rs +++ b/bridges/relays/lib-substrate-relay/src/on_demand_headers.rs @@ -16,29 +16,24 @@ //! On-demand Substrate -> Substrate headers relay. -use std::fmt::Debug; - use async_std::sync::{Arc, Mutex}; use futures::{select, FutureExt}; use num_traits::{CheckedSub, One, Zero}; -use finality_relay::{ - FinalitySyncParams, FinalitySyncPipeline, SourceClient as FinalitySourceClient, SourceHeader, - TargetClient as FinalityTargetClient, -}; +use finality_relay::{FinalitySyncParams, SourceHeader, TargetClient as FinalityTargetClient}; use relay_substrate_client::{ - finality_source::{FinalitySource as SubstrateFinalitySource, RequiredHeaderNumberRef}, - Chain, Client, HeaderIdOf, SyncHeader, + AccountIdOf, AccountKeyPairOf, BlockNumberOf, Chain, Client, HeaderIdOf, HeaderOf, SyncHeader, + TransactionSignScheme, }; use relay_utils::{ - metrics::MetricsParams, relay_loop::Client as RelayClient, BlockNumberBase, FailedClient, - MaybeConnectionError, + metrics::MetricsParams, relay_loop::Client as RelayClient, FailedClient, MaybeConnectionError, }; use crate::{ finality_pipeline::{ - SubstrateFinalitySyncPipeline, SubstrateFinalityToSubstrate, RECENT_FINALITY_PROOFS_LIMIT, + SubstrateFinalitySyncPipeline, TransactionParams, RECENT_FINALITY_PROOFS_LIMIT, }, + finality_source::{RequiredHeaderNumberRef, SubstrateFinalitySource}, finality_target::SubstrateFinalityTarget, STALL_TIMEOUT, }; @@ -58,40 +53,28 @@ pub struct OnDemandHeadersRelay { impl OnDemandHeadersRelay { /// Create new on-demand headers relay. - pub fn new( - source_client: Client, - target_client: Client, - target_transactions_mortality: Option, - pipeline: P, - maximal_headers_difference: SourceChain::BlockNumber, + pub fn new>( + source_client: Client, + target_client: Client, + target_transaction_params: TransactionParams>, + maximal_headers_difference: BlockNumberOf, only_mandatory_headers: bool, ) -> Self where - SourceChain: Chain + Debug, - SourceChain::BlockNumber: BlockNumberBase, - TargetChain: Chain + Debug, - TargetChain::BlockNumber: BlockNumberBase, - TargetSign: Clone + Send + Sync + 'static, - P: SubstrateFinalitySyncPipeline< - FinalitySyncPipeline = SubstrateFinalityToSubstrate< - SourceChain, - TargetChain, - TargetSign, - >, - TargetChain = TargetChain, - >, + AccountIdOf: + From< as sp_core::Pair>::Public>, + P::TransactionSignScheme: TransactionSignScheme, { let required_header_number = Arc::new(Mutex::new(Zero::zero())); let this = OnDemandHeadersRelay { - relay_task_name: on_demand_headers_relay_name::(), + relay_task_name: on_demand_headers_relay_name::(), required_header_number: required_header_number.clone(), }; async_std::task::spawn(async move { - background_task( + background_task::

( source_client, target_client, - target_transactions_mortality, - pipeline, + target_transaction_params, maximal_headers_difference, only_mandatory_headers, required_header_number, @@ -120,35 +103,25 @@ impl OnDemandHeadersRelay { } /// Background task that is responsible for starting headers relay. -async fn background_task( - source_client: Client, - target_client: Client, - target_transactions_mortality: Option, - pipeline: P, - maximal_headers_difference: SourceChain::BlockNumber, +async fn background_task( + source_client: Client, + target_client: Client, + target_transaction_params: TransactionParams>, + maximal_headers_difference: BlockNumberOf, only_mandatory_headers: bool, - required_header_number: RequiredHeaderNumberRef, + required_header_number: RequiredHeaderNumberRef, ) where - SourceChain: Chain + Debug, - SourceChain::BlockNumber: BlockNumberBase, - TargetChain: Chain + Debug, - TargetChain::BlockNumber: BlockNumberBase, - TargetSign: Clone + Send + Sync + 'static, - P: SubstrateFinalitySyncPipeline< - FinalitySyncPipeline = SubstrateFinalityToSubstrate, - TargetChain = TargetChain, - >, + AccountIdOf: + From< as sp_core::Pair>::Public>, + P::TransactionSignScheme: TransactionSignScheme, { - let relay_task_name = on_demand_headers_relay_name::(); - let mut finality_source = SubstrateFinalitySource::< - _, - SubstrateFinalityToSubstrate, - >::new(source_client.clone(), Some(required_header_number.clone())); - let mut finality_target = SubstrateFinalityTarget::new( - target_client.clone(), - pipeline.clone(), - target_transactions_mortality, + let relay_task_name = on_demand_headers_relay_name::(); + let mut finality_source = SubstrateFinalitySource::

::new( + source_client.clone(), + Some(required_header_number.clone()), ); + let mut finality_target = + SubstrateFinalityTarget::new(target_client.clone(), target_transaction_params); let mut latest_non_mandatory_at_source = Zero::zero(); let mut restart_relay = true; @@ -157,7 +130,7 @@ async fn background_task( loop { select! { - _ = async_std::task::sleep(TargetChain::AVERAGE_BLOCK_INTERVAL).fuse() => {}, + _ = async_std::task::sleep(P::TargetChain::AVERAGE_BLOCK_INTERVAL).fuse() => {}, _ = finality_relay_task => { // this should never happen in practice given the current code restart_relay = true; @@ -179,12 +152,8 @@ async fn background_task( } // read best finalized source header number from target - let best_finalized_source_header_at_target = best_finalized_source_header_at_target::< - SourceChain, - _, - _, - >(&finality_target, &relay_task_name) - .await; + let best_finalized_source_header_at_target = + best_finalized_source_header_at_target::

(&finality_target, &relay_task_name).await; if matches!(best_finalized_source_header_at_target, Err(ref e) if e.is_connection_error()) { relay_utils::relay_loop::reconnect_failed_client( FailedClient::Target, @@ -199,7 +168,7 @@ async fn background_task( // submit mandatory header if some headers are missing let best_finalized_source_header_at_target_fmt = format!("{:?}", best_finalized_source_header_at_target); - let mandatory_scan_range = mandatory_headers_scan_range::( + let mandatory_scan_range = mandatory_headers_scan_range::( best_finalized_source_header_at_source.ok(), best_finalized_source_header_at_target.ok(), maximal_headers_difference, @@ -247,8 +216,8 @@ async fn background_task( finality_target.clone(), FinalitySyncParams { tick: std::cmp::max( - SourceChain::AVERAGE_BLOCK_INTERVAL, - TargetChain::AVERAGE_BLOCK_INTERVAL, + P::SourceChain::AVERAGE_BLOCK_INTERVAL, + P::TargetChain::AVERAGE_BLOCK_INTERVAL, ), recent_finality_proofs_limit: RECENT_FINALITY_PROOFS_LIMIT, stall_timeout: STALL_TIMEOUT, @@ -316,17 +285,13 @@ async fn mandatory_headers_scan_range( /// it. /// /// Returns `true` if header was found and (asked to be) relayed and `false` otherwise. -async fn relay_mandatory_header_from_range( - finality_source: &SubstrateFinalitySource, - required_header_number: &RequiredHeaderNumberRef, +async fn relay_mandatory_header_from_range( + finality_source: &SubstrateFinalitySource

, + required_header_number: &RequiredHeaderNumberRef, best_finalized_source_header_at_target: String, - range: (SourceChain::BlockNumber, SourceChain::BlockNumber), + range: (BlockNumberOf, BlockNumberOf), relay_task_name: &str, -) -> Result -where - SubstrateFinalitySource: FinalitySourceClient

, - P: FinalitySyncPipeline, -{ +) -> Result { // search for mandatory header first let mandatory_source_header_number = find_mandatory_header_in_range(finality_source, range).await?; @@ -347,7 +312,7 @@ where log::trace!( target: "bridge", "Too many {} headers missing at target in {} relay ({} vs {}). Going to sync up to the mandatory {}", - SourceChain::NAME, + P::SourceChain::NAME, relay_task_name, best_finalized_source_header_at_target, range.1, @@ -361,14 +326,10 @@ where /// Read best finalized source block number from source client. /// /// Returns `None` if we have failed to read the number. -async fn best_finalized_source_header_at_source( - finality_source: &SubstrateFinalitySource, +async fn best_finalized_source_header_at_source( + finality_source: &SubstrateFinalitySource

, relay_task_name: &str, -) -> Result -where - SubstrateFinalitySource: FinalitySourceClient

, - P: FinalitySyncPipeline, -{ +) -> Result, relay_substrate_client::Error> { finality_source.on_chain_best_finalized_block_number().await.map_err(|error| { log::error!( target: "bridge", @@ -384,14 +345,14 @@ where /// Read best finalized source block number from target client. /// /// Returns `None` if we have failed to read the number. -async fn best_finalized_source_header_at_target( - finality_target: &SubstrateFinalityTarget, +async fn best_finalized_source_header_at_target( + finality_target: &SubstrateFinalityTarget

, relay_task_name: &str, -) -> Result as RelayClient>::Error> +) -> Result, as RelayClient>::Error> where - SubstrateFinalityTarget: FinalityTargetClient, - P: SubstrateFinalitySyncPipeline, - P::FinalitySyncPipeline: FinalitySyncPipeline, + AccountIdOf: + From< as sp_core::Pair>::Public>, + P::TransactionSignScheme: TransactionSignScheme, { finality_target.best_finalized_source_block_number().await.map_err(|error| { log::error!( @@ -408,17 +369,13 @@ where /// Read first mandatory header in given inclusive range. /// /// Returns `Ok(None)` if there were no mandatory headers in the range. -async fn find_mandatory_header_in_range( - finality_source: &SubstrateFinalitySource, - range: (SourceChain::BlockNumber, SourceChain::BlockNumber), -) -> Result, relay_substrate_client::Error> -where - SubstrateFinalitySource: FinalitySourceClient

, - P: FinalitySyncPipeline, -{ +async fn find_mandatory_header_in_range( + finality_source: &SubstrateFinalitySource

, + range: (BlockNumberOf, BlockNumberOf), +) -> Result>, relay_substrate_client::Error> { let mut current = range.0; while current <= range.1 { - let header: SyncHeader = + let header: SyncHeader> = finality_source.client().header_by_number(current).await?.into(); if header.is_mandatory() { return Ok(Some(current))