From 0fabaea341546a8298a991162146fc81bbaac673 Mon Sep 17 00:00:00 2001 From: Svyatoslav Nikolsky Date: Fri, 3 May 2024 11:34:19 +0300 Subject: [PATCH 1/2] relay single parachain header subcommand --- .../src/cli/relay_parachains.rs | 51 ++++++++ .../lib-substrate-relay/src/parachains/mod.rs | 42 +------ .../relays/parachains/src/parachains_loop.rs | 116 ++++++++++++------ 3 files changed, 129 insertions(+), 80 deletions(-) diff --git a/bridges/relays/lib-substrate-relay/src/cli/relay_parachains.rs b/bridges/relays/lib-substrate-relay/src/cli/relay_parachains.rs index 1425233add1e..00f8cf79ef1f 100644 --- a/bridges/relays/lib-substrate-relay/src/cli/relay_parachains.rs +++ b/bridges/relays/lib-substrate-relay/src/cli/relay_parachains.rs @@ -18,6 +18,8 @@ use async_std::sync::Mutex; use async_trait::async_trait; +use bp_polkadot_core::BlockNumber as RelayBlockNumber; +use bp_runtime::HeaderIdProvider; use parachains_relay::parachains_loop::{AvailableHeader, SourceClient, TargetClient}; use relay_substrate_client::Parachain; use relay_utils::metrics::{GlobalMetrics, StandaloneMetric}; @@ -51,6 +53,21 @@ pub struct RelayParachainsParams { prometheus_params: PrometheusParams, } +/// Single parachains head relaying params. +#[derive(StructOpt)] +pub struct RelayParachainHeadParams { + #[structopt(flatten)] + source: SourceConnectionParams, + #[structopt(flatten)] + target: TargetConnectionParams, + #[structopt(flatten)] + target_sign: TargetSigningParams, + /// Prove parachain head at that relay block number. This relay header must be previously + /// proved to the target chain. + #[structopt(long)] + at_relay_block: RelayBlockNumber, +} + /// Trait used for relaying parachains finality between 2 chains. #[async_trait] pub trait ParachainsRelayer: ParachainToRelayHeadersCliBridge @@ -94,4 +111,38 @@ where .await .map_err(|e| anyhow::format_err!("{}", e)) } + + /// Relay single parachain head. No checks are made to ensure that transaction will succeed. + async fn relay_parachain_head(data: RelayParachainHeadParams) -> anyhow::Result<()> { + let source_chain_client = data.source.into_client::().await?; + let at_relay_block = source_chain_client + .header_by_number(data.at_relay_block) + .await + .map_err(|e| anyhow::format_err!("{}", e))? + .id(); + + let source_client = ParachainsSource::::new( + source_chain_client.clone(), + Arc::new(Mutex::new(AvailableHeader::Missing)), + ); + + let target_transaction_params = TransactionParams { + signer: data.target_sign.to_keypair::()?, + mortality: data.target_sign.target_transactions_mortality, + }; + let target_chain_client = data.target.into_client::().await?; + let target_client = ParachainsTarget::::new( + source_chain_client, + target_chain_client, + target_transaction_params, + ); + + parachains_relay::parachains_loop::relay_single_head( + source_client, + target_client, + at_relay_block, + ) + .await + .map_err(|_| anyhow::format_err!("The command has failed")) + } } diff --git a/bridges/relays/lib-substrate-relay/src/parachains/mod.rs b/bridges/relays/lib-substrate-relay/src/parachains/mod.rs index 8b128bb770dd..6e36d8c9cf59 100644 --- a/bridges/relays/lib-substrate-relay/src/parachains/mod.rs +++ b/bridges/relays/lib-substrate-relay/src/parachains/mod.rs @@ -19,14 +19,8 @@ use async_trait::async_trait; use bp_polkadot_core::parachains::{ParaHash, ParaHeadsProof, ParaId}; -use pallet_bridge_parachains::{ - Call as BridgeParachainsCall, Config as BridgeParachainsConfig, RelayBlockHash, - RelayBlockHasher, RelayBlockNumber, -}; use parachains_relay::ParachainsPipeline; -use relay_substrate_client::{ - CallOf, Chain, ChainWithTransactions, HeaderIdOf, Parachain, RelayChain, -}; +use relay_substrate_client::{CallOf, ChainWithTransactions, HeaderIdOf, Parachain, RelayChain}; use std::{fmt::Debug, marker::PhantomData}; pub mod source; @@ -74,37 +68,3 @@ pub trait SubmitParachainHeadsCallBuilder: is_free_execution_expected: bool, ) -> CallOf; } - -/// Building `submit_parachain_heads` call when you have direct access to the target -/// chain runtime. -pub struct DirectSubmitParachainHeadsCallBuilder { - _phantom: PhantomData<(P, R, I)>, -} - -impl SubmitParachainHeadsCallBuilder

for DirectSubmitParachainHeadsCallBuilder -where - P: SubstrateParachainsPipeline, - P::SourceRelayChain: Chain, - R: BridgeParachainsConfig + Send + Sync, - I: 'static + Send + Sync, - R::BridgedChain: bp_runtime::Chain< - BlockNumber = RelayBlockNumber, - Hash = RelayBlockHash, - Hasher = RelayBlockHasher, - >, - CallOf: From>, -{ - fn build_submit_parachain_heads_call( - at_relay_block: HeaderIdOf, - parachains: Vec<(ParaId, ParaHash)>, - parachain_heads_proof: ParaHeadsProof, - _is_free_execution_expected: bool, - ) -> CallOf { - BridgeParachainsCall::::submit_parachain_heads { - at_relay_block: (at_relay_block.0, at_relay_block.1), - parachains, - parachain_heads_proof, - } - .into() - } -} diff --git a/bridges/relays/parachains/src/parachains_loop.rs b/bridges/relays/parachains/src/parachains_loop.rs index 55f236eeac1d..fd73ca2d46c0 100644 --- a/bridges/relays/parachains/src/parachains_loop.rs +++ b/bridges/relays/parachains/src/parachains_loop.rs @@ -139,6 +139,33 @@ pub fn metrics_prefix() -> String { ) } +/// Relay single parachain head. +pub async fn relay_single_head( + source_client: impl SourceClient

, + target_client: impl TargetClient

, + at_relay_block: HeaderIdOf, +) -> Result<(), ()> +where + P::SourceRelayChain: Chain, +{ + let tx_tracker = + submit_selected_head::(&source_client, &target_client, at_relay_block, false) + .await + .map_err(drop)?; + match tx_tracker.wait().await { + TrackedTransactionStatus::Finalized(_) => Ok(()), + TrackedTransactionStatus::Lost => { + log::error!( + "Transaction with {} header at relay header {:?} is considered lost at {}", + P::SourceParachain::NAME, + at_relay_block, + P::TargetChain::NAME, + ); + Err(()) + }, + } +} + /// Run parachain heads synchronization. pub async fn run( source_client: impl SourceClient

, @@ -361,52 +388,63 @@ where ); if is_update_required { - let (head_proof, head_hash) = - source_client.prove_parachain_head(prove_at_relay_block).await.map_err(|e| { - log::warn!( - target: "bridge", - "Failed to prove {} parachain ParaId({}) heads: {:?}", - P::SourceRelayChain::NAME, - P::SourceParachain::PARACHAIN_ID, - e, - ); - FailedClient::Source - })?; - log::info!( - target: "bridge", - "Submitting {} parachain ParaId({}) head update transaction to {}. Para hash at source relay {:?}: {:?}", - P::SourceRelayChain::NAME, - P::SourceParachain::PARACHAIN_ID, - P::TargetChain::NAME, + let transaction_tracker = submit_selected_head::( + &source_client, + &target_client, prove_at_relay_block, - head_hash, - ); - - let transaction_tracker = target_client - .submit_parachain_head_proof( - prove_at_relay_block, - head_hash, - head_proof, - only_free_headers, - ) - .await - .map_err(|e| { - log::warn!( - target: "bridge", - "Failed to submit {} parachain ParaId({}) heads proof to {}: {:?}", - P::SourceRelayChain::NAME, - P::SourceParachain::PARACHAIN_ID, - P::TargetChain::NAME, - e, - ); - FailedClient::Target - })?; + only_free_headers, + ) + .await?; submitted_heads_tracker = Some(SubmittedHeadsTracker::

::new(head_at_source, transaction_tracker)); } } } +/// Prove and submit parachain head at given relay chain block. +async fn submit_selected_head>( + source_client: &impl SourceClient

, + target_client: &TC, + prove_at_relay_block: HeaderIdOf, + only_free_headers: bool, +) -> Result { + let (head_proof, head_hash) = + source_client.prove_parachain_head(prove_at_relay_block).await.map_err(|e| { + log::warn!( + target: "bridge", + "Failed to prove {} parachain ParaId({}) heads: {:?}", + P::SourceRelayChain::NAME, + P::SourceParachain::PARACHAIN_ID, + e, + ); + FailedClient::Source + })?; + log::info!( + target: "bridge", + "Submitting {} parachain ParaId({}) head update transaction to {}. Para hash at source relay {:?}: {:?}", + P::SourceRelayChain::NAME, + P::SourceParachain::PARACHAIN_ID, + P::TargetChain::NAME, + prove_at_relay_block, + head_hash, + ); + + target_client + .submit_parachain_head_proof(prove_at_relay_block, head_hash, head_proof, only_free_headers) + .await + .map_err(|e| { + log::warn!( + target: "bridge", + "Failed to submit {} parachain ParaId({}) heads proof to {}: {:?}", + P::SourceRelayChain::NAME, + P::SourceParachain::PARACHAIN_ID, + P::TargetChain::NAME, + e, + ); + FailedClient::Target + }) +} + /// Returns `true` if we need to submit parachain-head-update transaction. fn is_update_required( head_at_source: AvailableHeader>, From d54ad81f0730383489c6d37f2fc86861657d3d26 Mon Sep 17 00:00:00 2001 From: Svyatoslav Nikolsky Date: Fri, 3 May 2024 14:12:01 +0300 Subject: [PATCH 2/2] revert DirectSubmitParachainHeadsCallBuilder removal --- .../lib-substrate-relay/src/parachains/mod.rs | 42 ++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/bridges/relays/lib-substrate-relay/src/parachains/mod.rs b/bridges/relays/lib-substrate-relay/src/parachains/mod.rs index 6e36d8c9cf59..8b128bb770dd 100644 --- a/bridges/relays/lib-substrate-relay/src/parachains/mod.rs +++ b/bridges/relays/lib-substrate-relay/src/parachains/mod.rs @@ -19,8 +19,14 @@ use async_trait::async_trait; use bp_polkadot_core::parachains::{ParaHash, ParaHeadsProof, ParaId}; +use pallet_bridge_parachains::{ + Call as BridgeParachainsCall, Config as BridgeParachainsConfig, RelayBlockHash, + RelayBlockHasher, RelayBlockNumber, +}; use parachains_relay::ParachainsPipeline; -use relay_substrate_client::{CallOf, ChainWithTransactions, HeaderIdOf, Parachain, RelayChain}; +use relay_substrate_client::{ + CallOf, Chain, ChainWithTransactions, HeaderIdOf, Parachain, RelayChain, +}; use std::{fmt::Debug, marker::PhantomData}; pub mod source; @@ -68,3 +74,37 @@ pub trait SubmitParachainHeadsCallBuilder: is_free_execution_expected: bool, ) -> CallOf; } + +/// Building `submit_parachain_heads` call when you have direct access to the target +/// chain runtime. +pub struct DirectSubmitParachainHeadsCallBuilder { + _phantom: PhantomData<(P, R, I)>, +} + +impl SubmitParachainHeadsCallBuilder

for DirectSubmitParachainHeadsCallBuilder +where + P: SubstrateParachainsPipeline, + P::SourceRelayChain: Chain, + R: BridgeParachainsConfig + Send + Sync, + I: 'static + Send + Sync, + R::BridgedChain: bp_runtime::Chain< + BlockNumber = RelayBlockNumber, + Hash = RelayBlockHash, + Hasher = RelayBlockHasher, + >, + CallOf: From>, +{ + fn build_submit_parachain_heads_call( + at_relay_block: HeaderIdOf, + parachains: Vec<(ParaId, ParaHash)>, + parachain_heads_proof: ParaHeadsProof, + _is_free_execution_expected: bool, + ) -> CallOf { + BridgeParachainsCall::::submit_parachain_heads { + at_relay_block: (at_relay_block.0, at_relay_block.1), + parachains, + parachain_heads_proof, + } + .into() + } +}