Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bridge: added subcommand to relay single parachain header #4365

Merged
merged 2 commits into from
May 3, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 51 additions & 0 deletions bridges/relays/lib-substrate-relay/src/cli/relay_parachains.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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::<Self::SourceRelay>().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::<Self::ParachainFinality>::new(
source_chain_client.clone(),
Arc::new(Mutex::new(AvailableHeader::Missing)),
);

let target_transaction_params = TransactionParams {
signer: data.target_sign.to_keypair::<Self::Target>()?,
mortality: data.target_sign.target_transactions_mortality,
};
let target_chain_client = data.target.into_client::<Self::Target>().await?;
let target_client = ParachainsTarget::<Self::ParachainFinality>::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"))
}
}
42 changes: 1 addition & 41 deletions bridges/relays/lib-substrate-relay/src/parachains/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -74,37 +68,3 @@ pub trait SubmitParachainHeadsCallBuilder<P: SubstrateParachainsPipeline>:
is_free_execution_expected: bool,
) -> CallOf<P::TargetChain>;
}

/// Building `submit_parachain_heads` call when you have direct access to the target
/// chain runtime.
pub struct DirectSubmitParachainHeadsCallBuilder<P, R, I> {
_phantom: PhantomData<(P, R, I)>,
}

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

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we keep this ? I think it will be needed for paritytech/parity-bridges-common#2952

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense - I've reverted removal. I've also recently removed similar struct for GRANDPA submissions - you may need it as well.

116 changes: 77 additions & 39 deletions bridges/relays/parachains/src/parachains_loop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,33 @@ pub fn metrics_prefix<P: ParachainsPipeline>() -> String {
)
}

/// Relay single parachain head.
pub async fn relay_single_head<P: ParachainsPipeline>(
source_client: impl SourceClient<P>,
target_client: impl TargetClient<P>,
at_relay_block: HeaderIdOf<P::SourceRelayChain>,
) -> Result<(), ()>
where
P::SourceRelayChain: Chain<BlockNumber = RelayBlockNumber>,
{
let tx_tracker =
submit_selected_head::<P, _>(&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<P: ParachainsPipeline>(
source_client: impl SourceClient<P>,
Expand Down Expand Up @@ -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::<P, _>(
&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::<P>::new(head_at_source, transaction_tracker));
}
}
}

/// Prove and submit parachain head at given relay chain block.
async fn submit_selected_head<P: ParachainsPipeline, TC: TargetClient<P>>(
source_client: &impl SourceClient<P>,
target_client: &TC,
prove_at_relay_block: HeaderIdOf<P::SourceRelayChain>,
only_free_headers: bool,
) -> Result<TC::TransactionTracker, FailedClient> {
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<P: ParachainsPipeline>(
head_at_source: AvailableHeader<HeaderIdOf<P::SourceParachain>>,
Expand Down
Loading