...@@ -40,7 +40,7 @@ use crate::{ ...@@ -40,7 +40,7 @@ use crate::{
cli::{bridge::MessagesCliBridge, HexLaneId, PrometheusParams}, cli::{bridge::MessagesCliBridge, HexLaneId, PrometheusParams},
messages_lane::{MessagesRelayLimits, MessagesRelayParams}, messages_lane::{MessagesRelayLimits, MessagesRelayParams},
on_demand::OnDemandRelay, on_demand::OnDemandRelay,
TaggedAccount, TransactionParams, HeadersToRelay, TaggedAccount, TransactionParams,
}; };
use bp_messages::LaneId; use bp_messages::LaneId;
use bp_runtime::BalanceOf; use bp_runtime::BalanceOf;
...@@ -61,11 +61,25 @@ pub struct HeadersAndMessagesSharedParams { ...@@ -61,11 +61,25 @@ pub struct HeadersAndMessagesSharedParams {
/// are relayed. /// are relayed.
#[structopt(long)] #[structopt(long)]
pub only_mandatory_headers: bool, pub only_mandatory_headers: bool,
/// If passed, only free headers (mandatory and every Nth header, if configured in runtime)
/// are relayed. Overrides `only_mandatory_headers`.
#[structopt(long)]
pub only_free_headers: bool,
#[structopt(flatten)] #[structopt(flatten)]
/// Prometheus metrics params. /// Prometheus metrics params.
pub prometheus_params: PrometheusParams, pub prometheus_params: PrometheusParams,
} }
impl HeadersAndMessagesSharedParams {
fn headers_to_relay(&self) -> HeadersToRelay {
match (self.only_mandatory_headers, self.only_free_headers) {
(_, true) => HeadersToRelay::Free,
(true, false) => HeadersToRelay::Mandatory,
_ => HeadersToRelay::All,
}
}
}
/// Bridge parameters, shared by all bridge types. /// Bridge parameters, shared by all bridge types.
pub struct Full2WayBridgeCommonParams< pub struct Full2WayBridgeCommonParams<
Left: ChainWithTransactions + ChainWithRuntimeVersion, Left: ChainWithTransactions + ChainWithRuntimeVersion,
...@@ -418,6 +432,7 @@ mod tests { ...@@ -418,6 +432,7 @@ mod tests {
shared: HeadersAndMessagesSharedParams { shared: HeadersAndMessagesSharedParams {
lane: vec![HexLaneId([0x00, 0x00, 0x00, 0x00])], lane: vec![HexLaneId([0x00, 0x00, 0x00, 0x00])],
only_mandatory_headers: false, only_mandatory_headers: false,
only_free_headers: false,
prometheus_params: PrometheusParams { prometheus_params: PrometheusParams {
no_prometheus: false, no_prometheus: false,
prometheus_host: "0.0.0.0".into(), prometheus_host: "0.0.0.0".into(),
......
...@@ -180,7 +180,7 @@ where ...@@ -180,7 +180,7 @@ where
self.left_relay.clone(), self.left_relay.clone(),
self.common.right.client.clone(), self.common.right.client.clone(),
self.common.right.tx_params.clone(), self.common.right.tx_params.clone(),
self.common.shared.only_mandatory_headers, self.common.shared.headers_to_relay(),
Some(self.common.metrics_params.clone()), Some(self.common.metrics_params.clone()),
); );
let right_relay_to_left_on_demand_headers = let right_relay_to_left_on_demand_headers =
...@@ -188,7 +188,7 @@ where ...@@ -188,7 +188,7 @@ where
self.right_relay.clone(), self.right_relay.clone(),
self.common.left.client.clone(), self.common.left.client.clone(),
self.common.left.tx_params.clone(), self.common.left.tx_params.clone(),
self.common.shared.only_mandatory_headers, self.common.shared.headers_to_relay(),
Some(self.common.metrics_params.clone()), Some(self.common.metrics_params.clone()),
); );
......
...@@ -171,7 +171,7 @@ where ...@@ -171,7 +171,7 @@ where
self.common.left.client.clone(), self.common.left.client.clone(),
self.common.right.client.clone(), self.common.right.client.clone(),
self.common.right.tx_params.clone(), self.common.right.tx_params.clone(),
self.common.shared.only_mandatory_headers, self.common.shared.headers_to_relay(),
None, None,
); );
let right_relay_to_left_on_demand_headers = let right_relay_to_left_on_demand_headers =
...@@ -179,7 +179,7 @@ where ...@@ -179,7 +179,7 @@ where
self.right_relay.clone(), self.right_relay.clone(),
self.common.left.client.clone(), self.common.left.client.clone(),
self.common.left.tx_params.clone(), self.common.left.tx_params.clone(),
self.common.shared.only_mandatory_headers, self.common.shared.headers_to_relay(),
Some(self.common.metrics_params.clone()), Some(self.common.metrics_params.clone()),
); );
let right_to_left_on_demand_parachains = OnDemandParachainsRelay::< let right_to_left_on_demand_parachains = OnDemandParachainsRelay::<
......
...@@ -152,7 +152,7 @@ where ...@@ -152,7 +152,7 @@ where
self.common.left.client.clone(), self.common.left.client.clone(),
self.common.right.client.clone(), self.common.right.client.clone(),
self.common.right.tx_params.clone(), self.common.right.tx_params.clone(),
self.common.shared.only_mandatory_headers, self.common.shared.headers_to_relay(),
None, None,
); );
let right_to_left_on_demand_headers = let right_to_left_on_demand_headers =
...@@ -160,7 +160,7 @@ where ...@@ -160,7 +160,7 @@ where
self.common.right.client.clone(), self.common.right.client.clone(),
self.common.left.client.clone(), self.common.left.client.clone(),
self.common.left.tx_params.clone(), self.common.left.tx_params.clone(),
self.common.shared.only_mandatory_headers, self.common.shared.headers_to_relay(),
None, None,
); );
......
...@@ -43,6 +43,10 @@ pub struct RelayParachainsParams { ...@@ -43,6 +43,10 @@ pub struct RelayParachainsParams {
target: TargetConnectionParams, target: TargetConnectionParams,
#[structopt(flatten)] #[structopt(flatten)]
target_sign: TargetSigningParams, target_sign: TargetSigningParams,
/// If passed, only free headers (those, available at "free" relay chain headers)
/// are relayed.
#[structopt(long)]
only_free_headers: bool,
#[structopt(flatten)] #[structopt(flatten)]
prometheus_params: PrometheusParams, prometheus_params: PrometheusParams,
} }
...@@ -59,9 +63,9 @@ where ...@@ -59,9 +63,9 @@ where
{ {
/// Start relaying parachains finality. /// Start relaying parachains finality.
async fn relay_parachains(data: RelayParachainsParams) -> anyhow::Result<()> { async fn relay_parachains(data: RelayParachainsParams) -> anyhow::Result<()> {
let source_client = data.source.into_client::<Self::SourceRelay>().await?; let source_chain_client = data.source.into_client::<Self::SourceRelay>().await?;
let source_client = ParachainsSource::<Self::ParachainFinality>::new( let source_client = ParachainsSource::<Self::ParachainFinality>::new(
source_client, source_chain_client.clone(),
Arc::new(Mutex::new(AvailableHeader::Missing)), Arc::new(Mutex::new(AvailableHeader::Missing)),
); );
...@@ -69,9 +73,10 @@ where ...@@ -69,9 +73,10 @@ where
signer: data.target_sign.to_keypair::<Self::Target>()?, signer: data.target_sign.to_keypair::<Self::Target>()?,
mortality: data.target_sign.target_transactions_mortality, mortality: data.target_sign.target_transactions_mortality,
}; };
let target_client = data.target.into_client::<Self::Target>().await?; let target_chain_client = data.target.into_client::<Self::Target>().await?;
let target_client = ParachainsTarget::<Self::ParachainFinality>::new( let target_client = ParachainsTarget::<Self::ParachainFinality>::new(
target_client.clone(), source_chain_client,
target_chain_client,
target_transaction_params, target_transaction_params,
); );
...@@ -83,6 +88,7 @@ where ...@@ -83,6 +88,7 @@ where
source_client, source_client,
target_client, target_client,
metrics_params, metrics_params,
data.only_free_headers,
futures::future::pending(), futures::future::pending(),
) )
.await .await
......
...@@ -25,13 +25,15 @@ use crate::{ ...@@ -25,13 +25,15 @@ use crate::{
use async_trait::async_trait; use async_trait::async_trait;
use bp_header_chain::justification::{GrandpaJustification, JustificationVerificationContext}; use bp_header_chain::justification::{GrandpaJustification, JustificationVerificationContext};
use finality_relay::{FinalityPipeline, FinalitySyncPipeline}; use finality_relay::{
FinalityPipeline, FinalitySyncPipeline, HeadersToRelay, SourceClient, TargetClient,
};
use pallet_bridge_grandpa::{Call as BridgeGrandpaCall, Config as BridgeGrandpaConfig}; use pallet_bridge_grandpa::{Call as BridgeGrandpaCall, Config as BridgeGrandpaConfig};
use relay_substrate_client::{ use relay_substrate_client::{
transaction_stall_timeout, AccountIdOf, AccountKeyPairOf, BlockNumberOf, CallOf, Chain, transaction_stall_timeout, AccountIdOf, AccountKeyPairOf, BlockNumberOf, CallOf, Chain,
ChainWithTransactions, Client, HashOf, HeaderOf, SyncHeader, ChainWithTransactions, Client, HashOf, HeaderOf, SyncHeader,
}; };
use relay_utils::metrics::MetricsParams; use relay_utils::{metrics::MetricsParams, TrackedTransactionStatus, TransactionTracker};
use sp_core::Pair; use sp_core::Pair;
use std::{fmt::Debug, marker::PhantomData}; use std::{fmt::Debug, marker::PhantomData};
...@@ -115,6 +117,7 @@ pub trait SubmitFinalityProofCallBuilder<P: SubstrateFinalitySyncPipeline> { ...@@ -115,6 +117,7 @@ pub trait SubmitFinalityProofCallBuilder<P: SubstrateFinalitySyncPipeline> {
fn build_submit_finality_proof_call( fn build_submit_finality_proof_call(
header: SyncHeader<HeaderOf<P::SourceChain>>, header: SyncHeader<HeaderOf<P::SourceChain>>,
proof: SubstrateFinalityProof<P>, proof: SubstrateFinalityProof<P>,
is_free_execution_expected: bool,
context: <<P as SubstrateFinalityPipeline>::FinalityEngine as Engine<P::SourceChain>>::FinalityVerificationContext, context: <<P as SubstrateFinalityPipeline>::FinalityEngine as Engine<P::SourceChain>>::FinalityVerificationContext,
) -> CallOf<P::TargetChain>; ) -> CallOf<P::TargetChain>;
} }
...@@ -142,6 +145,7 @@ where ...@@ -142,6 +145,7 @@ where
fn build_submit_finality_proof_call( fn build_submit_finality_proof_call(
header: SyncHeader<HeaderOf<P::SourceChain>>, header: SyncHeader<HeaderOf<P::SourceChain>>,
proof: GrandpaJustification<HeaderOf<P::SourceChain>>, proof: GrandpaJustification<HeaderOf<P::SourceChain>>,
_is_free_execution_expected: bool,
_context: JustificationVerificationContext, _context: JustificationVerificationContext,
) -> CallOf<P::TargetChain> { ) -> CallOf<P::TargetChain> {
BridgeGrandpaCall::<R, I>::submit_finality_proof { BridgeGrandpaCall::<R, I>::submit_finality_proof {
...@@ -176,6 +180,7 @@ macro_rules! generate_submit_finality_proof_call_builder { ...@@ -176,6 +180,7 @@ macro_rules! generate_submit_finality_proof_call_builder {
<$pipeline as $crate::finality_base::SubstrateFinalityPipeline>::SourceChain <$pipeline as $crate::finality_base::SubstrateFinalityPipeline>::SourceChain
> >
>, >,
_is_free_execution_expected: bool,
_context: bp_header_chain::justification::JustificationVerificationContext, _context: bp_header_chain::justification::JustificationVerificationContext,
) -> relay_substrate_client::CallOf< ) -> relay_substrate_client::CallOf<
<$pipeline as $crate::finality_base::SubstrateFinalityPipeline>::TargetChain <$pipeline as $crate::finality_base::SubstrateFinalityPipeline>::TargetChain
...@@ -215,6 +220,7 @@ macro_rules! generate_submit_finality_proof_ex_call_builder { ...@@ -215,6 +220,7 @@ macro_rules! generate_submit_finality_proof_ex_call_builder {
<$pipeline as $crate::finality_base::SubstrateFinalityPipeline>::SourceChain <$pipeline as $crate::finality_base::SubstrateFinalityPipeline>::SourceChain
> >
>, >,
is_free_execution_expected: bool,
context: bp_header_chain::justification::JustificationVerificationContext, context: bp_header_chain::justification::JustificationVerificationContext,
) -> relay_substrate_client::CallOf< ) -> relay_substrate_client::CallOf<
<$pipeline as $crate::finality_base::SubstrateFinalityPipeline>::TargetChain <$pipeline as $crate::finality_base::SubstrateFinalityPipeline>::TargetChain
...@@ -223,7 +229,8 @@ macro_rules! generate_submit_finality_proof_ex_call_builder { ...@@ -223,7 +229,8 @@ macro_rules! generate_submit_finality_proof_ex_call_builder {
$bridge_grandpa($submit_finality_proof { $bridge_grandpa($submit_finality_proof {
finality_target: Box::new(header.into_inner()), finality_target: Box::new(header.into_inner()),
justification: proof, justification: proof,
current_set_id: context.authority_set_id current_set_id: context.authority_set_id,
is_free_execution_expected,
}) })
} }
} }
...@@ -235,15 +242,16 @@ macro_rules! generate_submit_finality_proof_ex_call_builder { ...@@ -235,15 +242,16 @@ macro_rules! generate_submit_finality_proof_ex_call_builder {
pub async fn run<P: SubstrateFinalitySyncPipeline>( pub async fn run<P: SubstrateFinalitySyncPipeline>(
source_client: Client<P::SourceChain>, source_client: Client<P::SourceChain>,
target_client: Client<P::TargetChain>, target_client: Client<P::TargetChain>,
only_mandatory_headers: bool, headers_to_relay: HeadersToRelay,
transaction_params: TransactionParams<AccountKeyPairOf<P::TargetChain>>, transaction_params: TransactionParams<AccountKeyPairOf<P::TargetChain>>,
metrics_params: MetricsParams, metrics_params: MetricsParams,
) -> anyhow::Result<()> { ) -> anyhow::Result<()> {
log::info!( log::info!(
target: "bridge", target: "bridge",
"Starting {} -> {} finality proof relay", "Starting {} -> {} finality proof relay: relaying {:?} headers",
P::SourceChain::NAME, P::SourceChain::NAME,
P::TargetChain::NAME, P::TargetChain::NAME,
headers_to_relay,
); );
finality_relay::run( finality_relay::run(
...@@ -260,7 +268,7 @@ pub async fn run<P: SubstrateFinalitySyncPipeline>( ...@@ -260,7 +268,7 @@ pub async fn run<P: SubstrateFinalitySyncPipeline>(
P::TargetChain::AVERAGE_BLOCK_INTERVAL, P::TargetChain::AVERAGE_BLOCK_INTERVAL,
relay_utils::STALL_TIMEOUT, relay_utils::STALL_TIMEOUT,
), ),
only_mandatory_headers, headers_to_relay,
}, },
metrics_params, metrics_params,
futures::future::pending(), futures::future::pending(),
...@@ -268,3 +276,34 @@ pub async fn run<P: SubstrateFinalitySyncPipeline>( ...@@ -268,3 +276,34 @@ pub async fn run<P: SubstrateFinalitySyncPipeline>(
.await .await
.map_err(|e| anyhow::format_err!("{}", e)) .map_err(|e| anyhow::format_err!("{}", e))
} }
/// Relay single header. No checks are made to ensure that transaction will succeed.
pub async fn relay_single_header<P: SubstrateFinalitySyncPipeline>(
source_client: Client<P::SourceChain>,
target_client: Client<P::TargetChain>,
transaction_params: TransactionParams<AccountKeyPairOf<P::TargetChain>>,
header_number: BlockNumberOf<P::SourceChain>,
) -> anyhow::Result<()> {
let finality_source = SubstrateFinalitySource::<P>::new(source_client, None);
let (header, proof) = finality_source.header_and_finality_proof(header_number).await?;
let Some(proof) = proof else {
return Err(anyhow::format_err!(
"Unable to submit {} header #{} to {}: no finality proof",
P::SourceChain::NAME,
header_number,
P::TargetChain::NAME,
));
};
let finality_target = SubstrateFinalityTarget::<P>::new(target_client, transaction_params);
let tx_tracker = finality_target.submit_finality_proof(header, proof, false).await?;
match tx_tracker.wait().await {
TrackedTransactionStatus::Finalized(_) => Ok(()),
TrackedTransactionStatus::Lost => Err(anyhow::format_err!(
"Transaction with {} header #{} is considered lost at {}",
P::SourceChain::NAME,
header_number,
P::TargetChain::NAME,
)),
}
}
...@@ -25,9 +25,10 @@ use crate::{ ...@@ -25,9 +25,10 @@ use crate::{
}; };
use async_trait::async_trait; use async_trait::async_trait;
use bp_runtime::BlockNumberOf;
use finality_relay::TargetClient; use finality_relay::TargetClient;
use relay_substrate_client::{ use relay_substrate_client::{
AccountKeyPairOf, Client, Error, HeaderIdOf, HeaderOf, SyncHeader, TransactionEra, AccountKeyPairOf, Chain, Client, Error, HeaderIdOf, HeaderOf, SyncHeader, TransactionEra,
TransactionTracker, UnsignedTransaction, TransactionTracker, UnsignedTransaction,
}; };
use relay_utils::relay_loop::Client as RelayClient; use relay_utils::relay_loop::Client as RelayClient;
...@@ -103,10 +104,23 @@ impl<P: SubstrateFinalitySyncPipeline> TargetClient<FinalitySyncPipelineAdapter< ...@@ -103,10 +104,23 @@ impl<P: SubstrateFinalitySyncPipeline> TargetClient<FinalitySyncPipelineAdapter<
.ok_or(Error::BridgePalletIsNotInitialized)?) .ok_or(Error::BridgePalletIsNotInitialized)?)
} }
async fn free_source_headers_interval(
&self,
) -> Result<Option<BlockNumberOf<P::SourceChain>>, Self::Error> {
self.client
.typed_state_call(
P::SourceChain::FREE_HEADERS_INTERVAL_METHOD.into(),
(),
Some(self.client.best_header().await?.hash()),
)
.await
}
async fn submit_finality_proof( async fn submit_finality_proof(
&self, &self,
header: SyncHeader<HeaderOf<P::SourceChain>>, header: SyncHeader<HeaderOf<P::SourceChain>>,
mut proof: SubstrateFinalityProof<P>, mut proof: SubstrateFinalityProof<P>,
is_free_execution_expected: bool,
) -> Result<Self::TransactionTracker, Error> { ) -> Result<Self::TransactionTracker, Error> {
// verify and runtime module at target chain may require optimized finality proof // verify and runtime module at target chain may require optimized finality proof
let context = let context =
...@@ -115,7 +129,10 @@ impl<P: SubstrateFinalitySyncPipeline> TargetClient<FinalitySyncPipelineAdapter< ...@@ -115,7 +129,10 @@ impl<P: SubstrateFinalitySyncPipeline> TargetClient<FinalitySyncPipelineAdapter<
// now we may submit optimized finality proof // now we may submit optimized finality proof
let mortality = self.transaction_params.mortality; let mortality = self.transaction_params.mortality;
let call = P::SubmitFinalityProofCallBuilder::build_submit_finality_proof_call( let call = P::SubmitFinalityProofCallBuilder::build_submit_finality_proof_call(
header, proof, context, header,
proof,
is_free_execution_expected,
context,
); );
self.client self.client
.submit_and_watch_signed_extrinsic( .submit_and_watch_signed_extrinsic(
......
...@@ -22,6 +22,9 @@ use relay_substrate_client::{Chain, ChainWithUtilityPallet, UtilityPallet}; ...@@ -22,6 +22,9 @@ use relay_substrate_client::{Chain, ChainWithUtilityPallet, UtilityPallet};
use std::marker::PhantomData; use std::marker::PhantomData;
// to avoid `finality_relay` dependency in other crates
pub use finality_relay::HeadersToRelay;
pub mod cli; pub mod cli;
pub mod equivocation; pub mod equivocation;
pub mod error; pub mod error;
......
...@@ -28,7 +28,7 @@ use futures::{select, FutureExt}; ...@@ -28,7 +28,7 @@ use futures::{select, FutureExt};
use num_traits::{One, Saturating, Zero}; use num_traits::{One, Saturating, Zero};
use sp_runtime::traits::Header; use sp_runtime::traits::Header;
use finality_relay::{FinalitySyncParams, TargetClient as FinalityTargetClient}; use finality_relay::{FinalitySyncParams, HeadersToRelay, TargetClient as FinalityTargetClient};
use relay_substrate_client::{ use relay_substrate_client::{
AccountIdOf, AccountKeyPairOf, BlockNumberOf, CallOf, Chain, Client, Error as SubstrateError, AccountIdOf, AccountKeyPairOf, BlockNumberOf, CallOf, Chain, Client, Error as SubstrateError,
HeaderIdOf, HeaderIdOf,
...@@ -75,7 +75,7 @@ impl<P: SubstrateFinalitySyncPipeline> OnDemandHeadersRelay<P> { ...@@ -75,7 +75,7 @@ impl<P: SubstrateFinalitySyncPipeline> OnDemandHeadersRelay<P> {
source_client: Client<P::SourceChain>, source_client: Client<P::SourceChain>,
target_client: Client<P::TargetChain>, target_client: Client<P::TargetChain>,
target_transaction_params: TransactionParams<AccountKeyPairOf<P::TargetChain>>, target_transaction_params: TransactionParams<AccountKeyPairOf<P::TargetChain>>,
only_mandatory_headers: bool, headers_to_relay: HeadersToRelay,
metrics_params: Option<MetricsParams>, metrics_params: Option<MetricsParams>,
) -> Self ) -> Self
where where
...@@ -94,7 +94,7 @@ impl<P: SubstrateFinalitySyncPipeline> OnDemandHeadersRelay<P> { ...@@ -94,7 +94,7 @@ impl<P: SubstrateFinalitySyncPipeline> OnDemandHeadersRelay<P> {
source_client, source_client,
target_client, target_client,
target_transaction_params, target_transaction_params,
only_mandatory_headers, headers_to_relay,
required_header_number, required_header_number,
metrics_params, metrics_params,
) )
...@@ -191,7 +191,7 @@ impl<P: SubstrateFinalitySyncPipeline> OnDemandRelay<P::SourceChain, P::TargetCh ...@@ -191,7 +191,7 @@ impl<P: SubstrateFinalitySyncPipeline> OnDemandRelay<P::SourceChain, P::TargetCh
// and then craft the submit-proof call // and then craft the submit-proof call
let call = P::SubmitFinalityProofCallBuilder::build_submit_finality_proof_call( let call = P::SubmitFinalityProofCallBuilder::build_submit_finality_proof_call(
header, proof, context, header, proof, false, context,
); );
return Ok((header_id, vec![call])); return Ok((header_id, vec![call]));
...@@ -204,7 +204,7 @@ async fn background_task<P: SubstrateFinalitySyncPipeline>( ...@@ -204,7 +204,7 @@ async fn background_task<P: SubstrateFinalitySyncPipeline>(
source_client: Client<P::SourceChain>, source_client: Client<P::SourceChain>,
target_client: Client<P::TargetChain>, target_client: Client<P::TargetChain>,
target_transaction_params: TransactionParams<AccountKeyPairOf<P::TargetChain>>, target_transaction_params: TransactionParams<AccountKeyPairOf<P::TargetChain>>,
only_mandatory_headers: bool, headers_to_relay: HeadersToRelay,
required_header_number: RequiredHeaderNumberRef<P::SourceChain>, required_header_number: RequiredHeaderNumberRef<P::SourceChain>,
metrics_params: Option<MetricsParams>, metrics_params: Option<MetricsParams>,
) where ) where
...@@ -346,11 +346,11 @@ async fn background_task<P: SubstrateFinalitySyncPipeline>( ...@@ -346,11 +346,11 @@ async fn background_task<P: SubstrateFinalitySyncPipeline>(
log::info!( log::info!(
target: "bridge", target: "bridge",
"[{}] Starting on-demand headers relay task\n\t\ "[{}] Starting on-demand headers relay task\n\t\
Only mandatory headers: {}\n\t\ Headers to relay: {:?}\n\t\
Tx mortality: {:?} (~{}m)\n\t\ Tx mortality: {:?} (~{}m)\n\t\
Stall timeout: {:?}", Stall timeout: {:?}",
relay_task_name, relay_task_name,
only_mandatory_headers, headers_to_relay,
target_transactions_mortality, target_transactions_mortality,
stall_timeout.as_secs_f64() / 60.0f64, stall_timeout.as_secs_f64() / 60.0f64,
stall_timeout, stall_timeout,
...@@ -367,7 +367,7 @@ async fn background_task<P: SubstrateFinalitySyncPipeline>( ...@@ -367,7 +367,7 @@ async fn background_task<P: SubstrateFinalitySyncPipeline>(
), ),
recent_finality_proofs_limit: RECENT_FINALITY_PROOFS_LIMIT, recent_finality_proofs_limit: RECENT_FINALITY_PROOFS_LIMIT,
stall_timeout, stall_timeout,
only_mandatory_headers, headers_to_relay,
}, },
metrics_params.clone().unwrap_or_else(MetricsParams::disabled), metrics_params.clone().unwrap_or_else(MetricsParams::disabled),
futures::future::pending(), futures::future::pending(),
......
...@@ -222,6 +222,7 @@ where ...@@ -222,6 +222,7 @@ where
proved_relay_block, proved_relay_block,
vec![(para_id, para_hash)], vec![(para_id, para_hash)],
para_proof, para_proof,
false,
)); ));
Ok((proved_parachain_block, calls)) Ok((proved_parachain_block, calls))
...@@ -256,8 +257,11 @@ async fn background_task<P: SubstrateParachainsPipeline>( ...@@ -256,8 +257,11 @@ async fn background_task<P: SubstrateParachainsPipeline>(
let mut parachains_source = let mut parachains_source =
ParachainsSource::<P>::new(source_relay_client.clone(), required_para_header_ref.clone()); ParachainsSource::<P>::new(source_relay_client.clone(), required_para_header_ref.clone());
let mut parachains_target = let mut parachains_target = ParachainsTarget::<P>::new(
ParachainsTarget::<P>::new(target_client.clone(), target_transaction_params.clone()); source_relay_client.clone(),
target_client.clone(),
target_transaction_params.clone(),
);
loop { loop {
select! { select! {
...@@ -392,6 +396,8 @@ async fn background_task<P: SubstrateParachainsPipeline>( ...@@ -392,6 +396,8 @@ async fn background_task<P: SubstrateParachainsPipeline>(
parachains_source.clone(), parachains_source.clone(),
parachains_target.clone(), parachains_target.clone(),
MetricsParams::disabled(), MetricsParams::disabled(),
// we do not support free parachain headers relay in on-demand relays
false,
futures::future::pending(), futures::future::pending(),
) )
.fuse(), .fuse(),
...@@ -481,7 +487,7 @@ where ...@@ -481,7 +487,7 @@ where
let para_header_at_target = best_finalized_peer_header_at_self::< let para_header_at_target = best_finalized_peer_header_at_self::<
P::TargetChain, P::TargetChain,
P::SourceParachain, P::SourceParachain,
>(target.client(), best_target_block_hash) >(target.target_client(), best_target_block_hash)
.await; .await;
// if there are no parachain heads at the target (`NoParachainHeadAtTarget`), we'll need to // if there are no parachain heads at the target (`NoParachainHeadAtTarget`), we'll need to
// submit at least one. Otherwise the pallet will be treated as uninitialized and messages // submit at least one. Otherwise the pallet will be treated as uninitialized and messages
...@@ -504,7 +510,7 @@ where ...@@ -504,7 +510,7 @@ where
let relay_header_at_target = best_finalized_peer_header_at_self::< let relay_header_at_target = best_finalized_peer_header_at_self::<
P::TargetChain, P::TargetChain,
P::SourceRelayChain, P::SourceRelayChain,
>(target.client(), best_target_block_hash) >(target.target_client(), best_target_block_hash)
.await .await
.map_err(map_target_err)?; .map_err(map_target_err)?;
......
...@@ -71,6 +71,7 @@ pub trait SubmitParachainHeadsCallBuilder<P: SubstrateParachainsPipeline>: ...@@ -71,6 +71,7 @@ pub trait SubmitParachainHeadsCallBuilder<P: SubstrateParachainsPipeline>:
at_relay_block: HeaderIdOf<P::SourceRelayChain>, at_relay_block: HeaderIdOf<P::SourceRelayChain>,
parachains: Vec<(ParaId, ParaHash)>, parachains: Vec<(ParaId, ParaHash)>,
parachain_heads_proof: ParaHeadsProof, parachain_heads_proof: ParaHeadsProof,
is_free_execution_expected: bool,
) -> CallOf<P::TargetChain>; ) -> CallOf<P::TargetChain>;
} }
...@@ -97,6 +98,7 @@ where ...@@ -97,6 +98,7 @@ where
at_relay_block: HeaderIdOf<P::SourceRelayChain>, at_relay_block: HeaderIdOf<P::SourceRelayChain>,
parachains: Vec<(ParaId, ParaHash)>, parachains: Vec<(ParaId, ParaHash)>,
parachain_heads_proof: ParaHeadsProof, parachain_heads_proof: ParaHeadsProof,
_is_free_execution_expected: bool,
) -> CallOf<P::TargetChain> { ) -> CallOf<P::TargetChain> {
BridgeParachainsCall::<R, I>::submit_parachain_heads { BridgeParachainsCall::<R, I>::submit_parachain_heads {
at_relay_block: (at_relay_block.0, at_relay_block.1), at_relay_block: (at_relay_block.0, at_relay_block.1),
......
...@@ -24,42 +24,53 @@ use crate::{ ...@@ -24,42 +24,53 @@ use crate::{
}; };
use async_trait::async_trait; use async_trait::async_trait;
use bp_polkadot_core::parachains::{ParaHash, ParaHeadsProof, ParaId}; use bp_parachains::{
use bp_runtime::HeaderIdProvider; ImportedParaHeadsKeyProvider, ParaInfo, ParaStoredHeaderData, ParasInfoKeyProvider,
use codec::Decode; };
use bp_polkadot_core::{
parachains::{ParaHash, ParaHeadsProof, ParaId},
BlockNumber as RelayBlockNumber,
};
use bp_runtime::{
Chain as ChainBase, HeaderId, HeaderIdProvider, StorageDoubleMapKeyProvider,
StorageMapKeyProvider,
};
use parachains_relay::parachains_loop::TargetClient; use parachains_relay::parachains_loop::TargetClient;
use relay_substrate_client::{ use relay_substrate_client::{
AccountIdOf, AccountKeyPairOf, Chain, Client, Error as SubstrateError, HeaderIdOf, AccountIdOf, AccountKeyPairOf, BlockNumberOf, Chain, Client, Error as SubstrateError,
ParachainBase, TransactionEra, TransactionTracker, UnsignedTransaction, HeaderIdOf, ParachainBase, RelayChain, TransactionEra, TransactionTracker, UnsignedTransaction,
}; };
use relay_utils::relay_loop::Client as RelayClient; use relay_utils::relay_loop::Client as RelayClient;
use sp_core::{Bytes, Pair}; use sp_core::Pair;
/// Substrate client as parachain heads source. /// Substrate client as parachain heads source.
pub struct ParachainsTarget<P: SubstrateParachainsPipeline> { pub struct ParachainsTarget<P: SubstrateParachainsPipeline> {
client: Client<P::TargetChain>, source_client: Client<P::SourceRelayChain>,
target_client: Client<P::TargetChain>,
transaction_params: TransactionParams<AccountKeyPairOf<P::TargetChain>>, transaction_params: TransactionParams<AccountKeyPairOf<P::TargetChain>>,
} }
impl<P: SubstrateParachainsPipeline> ParachainsTarget<P> { impl<P: SubstrateParachainsPipeline> ParachainsTarget<P> {
/// Creates new parachains target client. /// Creates new parachains target client.
pub fn new( pub fn new(
client: Client<P::TargetChain>, source_client: Client<P::SourceRelayChain>,
target_client: Client<P::TargetChain>,
transaction_params: TransactionParams<AccountKeyPairOf<P::TargetChain>>, transaction_params: TransactionParams<AccountKeyPairOf<P::TargetChain>>,
) -> Self { ) -> Self {
ParachainsTarget { client, transaction_params } ParachainsTarget { source_client, target_client, transaction_params }
} }
/// Returns reference to the underlying RPC client. /// Returns reference to the underlying RPC client.
pub fn client(&self) -> &Client<P::TargetChain> { pub fn target_client(&self) -> &Client<P::TargetChain> {
&self.client &self.target_client
} }
} }
impl<P: SubstrateParachainsPipeline> Clone for ParachainsTarget<P> { impl<P: SubstrateParachainsPipeline> Clone for ParachainsTarget<P> {
fn clone(&self) -> Self { fn clone(&self) -> Self {
ParachainsTarget { ParachainsTarget {
client: self.client.clone(), source_client: self.source_client.clone(),
target_client: self.target_client.clone(),
transaction_params: self.transaction_params.clone(), transaction_params: self.transaction_params.clone(),
} }
} }
...@@ -70,7 +81,9 @@ impl<P: SubstrateParachainsPipeline> RelayClient for ParachainsTarget<P> { ...@@ -70,7 +81,9 @@ impl<P: SubstrateParachainsPipeline> RelayClient for ParachainsTarget<P> {
type Error = SubstrateError; type Error = SubstrateError;
async fn reconnect(&mut self) -> Result<(), SubstrateError> { async fn reconnect(&mut self) -> Result<(), SubstrateError> {
self.client.reconnect().await self.target_client.reconnect().await?;
self.source_client.reconnect().await?;
Ok(())
} }
} }
...@@ -79,11 +92,13 @@ impl<P> TargetClient<ParachainsPipelineAdapter<P>> for ParachainsTarget<P> ...@@ -79,11 +92,13 @@ impl<P> TargetClient<ParachainsPipelineAdapter<P>> for ParachainsTarget<P>
where where
P: SubstrateParachainsPipeline, P: SubstrateParachainsPipeline,
AccountIdOf<P::TargetChain>: From<<AccountKeyPairOf<P::TargetChain> as Pair>::Public>, AccountIdOf<P::TargetChain>: From<<AccountKeyPairOf<P::TargetChain> as Pair>::Public>,
P::SourceParachain: ChainBase<Hash = ParaHash>,
P::SourceRelayChain: ChainBase<BlockNumber = RelayBlockNumber>,
{ {
type TransactionTracker = TransactionTracker<P::TargetChain, Client<P::TargetChain>>; type TransactionTracker = TransactionTracker<P::TargetChain, Client<P::TargetChain>>;
async fn best_block(&self) -> Result<HeaderIdOf<P::TargetChain>, Self::Error> { async fn best_block(&self) -> Result<HeaderIdOf<P::TargetChain>, Self::Error> {
let best_header = self.client.best_header().await?; let best_header = self.target_client.best_header().await?;
let best_id = best_header.id(); let best_id = best_header.id();
Ok(best_id) Ok(best_id)
...@@ -93,7 +108,7 @@ where ...@@ -93,7 +108,7 @@ where
&self, &self,
at_block: &HeaderIdOf<P::TargetChain>, at_block: &HeaderIdOf<P::TargetChain>,
) -> Result<HeaderIdOf<P::SourceRelayChain>, Self::Error> { ) -> Result<HeaderIdOf<P::SourceRelayChain>, Self::Error> {
self.client self.target_client
.typed_state_call::<_, Option<HeaderIdOf<P::SourceRelayChain>>>( .typed_state_call::<_, Option<HeaderIdOf<P::SourceRelayChain>>>(
P::SourceRelayChain::BEST_FINALIZED_HEADER_ID_METHOD.into(), P::SourceRelayChain::BEST_FINALIZED_HEADER_ID_METHOD.into(),
(), (),
...@@ -104,23 +119,57 @@ where ...@@ -104,23 +119,57 @@ where
.unwrap_or(Err(SubstrateError::BridgePalletIsNotInitialized)) .unwrap_or(Err(SubstrateError::BridgePalletIsNotInitialized))
} }
async fn free_source_relay_headers_interval(
&self,
) -> Result<Option<BlockNumberOf<P::SourceRelayChain>>, Self::Error> {
self.target_client
.typed_state_call(P::SourceRelayChain::FREE_HEADERS_INTERVAL_METHOD.into(), (), None)
.await
}
async fn parachain_head( async fn parachain_head(
&self, &self,
at_block: HeaderIdOf<P::TargetChain>, at_block: HeaderIdOf<P::TargetChain>,
) -> Result<Option<HeaderIdOf<P::SourceParachain>>, Self::Error> { ) -> Result<
let encoded_best_finalized_source_para_block = self Option<(HeaderIdOf<P::SourceRelayChain>, HeaderIdOf<P::SourceParachain>)>,
.client Self::Error,
.state_call( > {
P::SourceParachain::BEST_FINALIZED_HEADER_ID_METHOD.into(), // read best parachain head from the target bridge-parachains pallet
Bytes(Vec::new()), let storage_key = ParasInfoKeyProvider::final_key(
Some(at_block.1), P::SourceRelayChain::WITH_CHAIN_BRIDGE_PARACHAINS_PALLET_NAME,
) &P::SourceParachain::PARACHAIN_ID.into(),
.await?; );
let storage_value: Option<ParaInfo> =
self.target_client.storage_value(storage_key, Some(at_block.hash())).await?;
let para_info = match storage_value {
Some(para_info) => para_info,
None => return Ok(None),
};
Ok(Option::<HeaderIdOf<P::SourceParachain>>::decode( // now we need to get full header ids. For source relay chain it is simple, because we
&mut &encoded_best_finalized_source_para_block.0[..], // are connected
) let relay_header_id = self
.map_err(SubstrateError::ResponseParseFailed)?) .source_client
.header_by_number(para_info.best_head_hash.at_relay_block_number)
.await?
.id();
// for parachain, we need to read from the target chain runtime storage
let storage_key = ImportedParaHeadsKeyProvider::final_key(
P::SourceRelayChain::WITH_CHAIN_BRIDGE_PARACHAINS_PALLET_NAME,
&P::SourceParachain::PARACHAIN_ID.into(),
&para_info.best_head_hash.head_hash,
);
let storage_value: Option<ParaStoredHeaderData> =
self.target_client.storage_value(storage_key, Some(at_block.hash())).await?;
let para_head_number = match storage_value {
Some(para_head_data) =>
para_head_data.decode_parachain_head_data::<P::SourceParachain>()?.number,
None => return Ok(None),
};
let para_head_id = HeaderId(para_head_number, para_info.best_head_hash.head_hash);
Ok(Some((relay_header_id, para_head_id)))
} }
async fn submit_parachain_head_proof( async fn submit_parachain_head_proof(
...@@ -128,14 +177,16 @@ where ...@@ -128,14 +177,16 @@ where
at_relay_block: HeaderIdOf<P::SourceRelayChain>, at_relay_block: HeaderIdOf<P::SourceRelayChain>,
updated_head_hash: ParaHash, updated_head_hash: ParaHash,
proof: ParaHeadsProof, proof: ParaHeadsProof,
is_free_execution_expected: bool,
) -> Result<Self::TransactionTracker, Self::Error> { ) -> Result<Self::TransactionTracker, Self::Error> {
let transaction_params = self.transaction_params.clone(); let transaction_params = self.transaction_params.clone();
let call = P::SubmitParachainHeadsCallBuilder::build_submit_parachain_heads_call( let call = P::SubmitParachainHeadsCallBuilder::build_submit_parachain_heads_call(
at_relay_block, at_relay_block,
vec![(ParaId(P::SourceParachain::PARACHAIN_ID), updated_head_hash)], vec![(ParaId(P::SourceParachain::PARACHAIN_ID), updated_head_hash)],
proof, proof,
is_free_execution_expected,
); );
self.client self.target_client
.submit_and_watch_signed_extrinsic( .submit_and_watch_signed_extrinsic(
&transaction_params.signer, &transaction_params.signer,
move |best_block_id, transaction_nonce| { move |best_block_id, transaction_nonce| {
......
...@@ -25,7 +25,7 @@ use futures::{ ...@@ -25,7 +25,7 @@ use futures::{
future::{FutureExt, Shared}, future::{FutureExt, Shared},
poll, select_biased, poll, select_biased,
}; };
use relay_substrate_client::{Chain, HeaderIdOf, ParachainBase}; use relay_substrate_client::{BlockNumberOf, Chain, HeaderIdOf, ParachainBase};
use relay_utils::{ use relay_utils::{
metrics::MetricsParams, relay_loop::Client as RelayClient, FailedClient, metrics::MetricsParams, relay_loop::Client as RelayClient, FailedClient,
TrackedTransactionStatus, TransactionTracker, TrackedTransactionStatus, TransactionTracker,
...@@ -96,17 +96,27 @@ pub trait TargetClient<P: ParachainsPipeline>: RelayClient { ...@@ -96,17 +96,27 @@ pub trait TargetClient<P: ParachainsPipeline>: RelayClient {
/// Get best block id. /// Get best block id.
async fn best_block(&self) -> Result<HeaderIdOf<P::TargetChain>, Self::Error>; async fn best_block(&self) -> Result<HeaderIdOf<P::TargetChain>, Self::Error>;
/// Get best finalized source relay chain block id. /// Get best finalized source relay chain block id. If `free_source_relay_headers_interval`
/// is `Some(_)`, the returned
async fn best_finalized_source_relay_chain_block( async fn best_finalized_source_relay_chain_block(
&self, &self,
at_block: &HeaderIdOf<P::TargetChain>, at_block: &HeaderIdOf<P::TargetChain>,
) -> Result<HeaderIdOf<P::SourceRelayChain>, Self::Error>; ) -> Result<HeaderIdOf<P::SourceRelayChain>, Self::Error>;
/// Get free source **relay** headers submission interval, if it is configured in the
/// target runtime. We assume that the target chain will accept parachain header, proved
/// at such relay header for free.
async fn free_source_relay_headers_interval(
&self,
) -> Result<Option<BlockNumberOf<P::SourceRelayChain>>, Self::Error>;
/// Get parachain head id at given block. /// Get parachain head id at given block.
async fn parachain_head( async fn parachain_head(
&self, &self,
at_block: HeaderIdOf<P::TargetChain>, at_block: HeaderIdOf<P::TargetChain>,
) -> Result<Option<HeaderIdOf<P::SourceParachain>>, Self::Error>; ) -> Result<
Option<(HeaderIdOf<P::SourceRelayChain>, HeaderIdOf<P::SourceParachain>)>,
Self::Error,
>;
/// Submit parachain heads proof. /// Submit parachain heads proof.
async fn submit_parachain_head_proof( async fn submit_parachain_head_proof(
...@@ -114,6 +124,7 @@ pub trait TargetClient<P: ParachainsPipeline>: RelayClient { ...@@ -114,6 +124,7 @@ pub trait TargetClient<P: ParachainsPipeline>: RelayClient {
at_source_block: HeaderIdOf<P::SourceRelayChain>, at_source_block: HeaderIdOf<P::SourceRelayChain>,
para_head_hash: ParaHash, para_head_hash: ParaHash,
proof: ParaHeadsProof, proof: ParaHeadsProof,
is_free_execution_expected: bool,
) -> Result<Self::TransactionTracker, Self::Error>; ) -> Result<Self::TransactionTracker, Self::Error>;
} }
...@@ -133,6 +144,7 @@ pub async fn run<P: ParachainsPipeline>( ...@@ -133,6 +144,7 @@ pub async fn run<P: ParachainsPipeline>(
source_client: impl SourceClient<P>, source_client: impl SourceClient<P>,
target_client: impl TargetClient<P>, target_client: impl TargetClient<P>,
metrics_params: MetricsParams, metrics_params: MetricsParams,
only_free_headers: bool,
exit_signal: impl Future<Output = ()> + 'static + Send, exit_signal: impl Future<Output = ()> + 'static + Send,
) -> Result<(), relay_utils::Error> ) -> Result<(), relay_utils::Error>
where where
...@@ -145,7 +157,13 @@ where ...@@ -145,7 +157,13 @@ where
.expose() .expose()
.await? .await?
.run(metrics_prefix::<P>(), move |source_client, target_client, metrics| { .run(metrics_prefix::<P>(), move |source_client, target_client, metrics| {
run_until_connection_lost(source_client, target_client, metrics, exit_signal.clone()) run_until_connection_lost(
source_client,
target_client,
metrics,
only_free_headers,
exit_signal.clone(),
)
}) })
.await .await
} }
...@@ -155,6 +173,7 @@ async fn run_until_connection_lost<P: ParachainsPipeline>( ...@@ -155,6 +173,7 @@ async fn run_until_connection_lost<P: ParachainsPipeline>(
source_client: impl SourceClient<P>, source_client: impl SourceClient<P>,
target_client: impl TargetClient<P>, target_client: impl TargetClient<P>,
metrics: Option<ParachainsLoopMetrics>, metrics: Option<ParachainsLoopMetrics>,
only_free_headers: bool,
exit_signal: impl Future<Output = ()> + Send, exit_signal: impl Future<Output = ()> + Send,
) -> Result<(), FailedClient> ) -> Result<(), FailedClient>
where where
...@@ -166,6 +185,47 @@ where ...@@ -166,6 +185,47 @@ where
P::TargetChain::AVERAGE_BLOCK_INTERVAL, P::TargetChain::AVERAGE_BLOCK_INTERVAL,
); );
// free parachain header = header, available (proved) at free relay chain block. Let's
// read interval of free source relay chain blocks from target client
let free_source_relay_headers_interval = if only_free_headers {
let free_source_relay_headers_interval =
target_client.free_source_relay_headers_interval().await.map_err(|e| {
log::warn!(
target: "bridge",
"Failed to read free {} headers interval at {}: {:?}",
P::SourceRelayChain::NAME,
P::TargetChain::NAME,
e,
);
FailedClient::Target
})?;
match free_source_relay_headers_interval {
Some(free_source_relay_headers_interval) if free_source_relay_headers_interval != 0 => {
log::trace!(
target: "bridge",
"Free {} headers interval at {}: {:?}",
P::SourceRelayChain::NAME,
P::TargetChain::NAME,
free_source_relay_headers_interval,
);
free_source_relay_headers_interval
},
_ => {
log::warn!(
target: "bridge",
"Invalid free {} headers interval at {}: {:?}",
P::SourceRelayChain::NAME,
P::TargetChain::NAME,
free_source_relay_headers_interval,
);
return Err(FailedClient::Target)
},
}
} else {
// ignore - we don't need it
0
};
let mut submitted_heads_tracker: Option<SubmittedHeadsTracker<P>> = None; let mut submitted_heads_tracker: Option<SubmittedHeadsTracker<P>> = None;
futures::pin_mut!(exit_signal); futures::pin_mut!(exit_signal);
...@@ -211,7 +271,7 @@ where ...@@ -211,7 +271,7 @@ where
log::warn!(target: "bridge", "Failed to read best {} block: {:?}", P::SourceRelayChain::NAME, e); log::warn!(target: "bridge", "Failed to read best {} block: {:?}", P::SourceRelayChain::NAME, e);
FailedClient::Target FailedClient::Target
})?; })?;
let head_at_target = let (relay_of_head_at_target, head_at_target) =
read_head_at_target(&target_client, metrics.as_ref(), &best_target_block).await?; read_head_at_target(&target_client, metrics.as_ref(), &best_target_block).await?;
// check if our transaction has been mined // check if our transaction has been mined
...@@ -238,9 +298,9 @@ where ...@@ -238,9 +298,9 @@ where
} }
} }
// we have no active transaction and may need to update heads, but do we have something for // in all-headers strategy we'll be submitting para head, available at
// update? // `best_finalized_relay_block_at_target`
let best_finalized_relay_block = target_client let best_finalized_relay_block_at_target = target_client
.best_finalized_source_relay_chain_block(&best_target_block) .best_finalized_source_relay_chain_block(&best_target_block)
.await .await
.map_err(|e| { .map_err(|e| {
...@@ -253,21 +313,56 @@ where ...@@ -253,21 +313,56 @@ where
); );
FailedClient::Target FailedClient::Target
})?; })?;
// ..but if we only need to submit free headers, we need to submit para
// head, available at best free source relay chain header, known to the
// target chain
let prove_at_relay_block = if only_free_headers {
match relay_of_head_at_target {
Some(relay_of_head_at_target) => {
// find last free relay chain header in the range that we are interested in
let scan_range_begin = relay_of_head_at_target.number();
let scan_range_end = best_finalized_relay_block_at_target.number();
if scan_range_end.saturating_sub(scan_range_begin) <
free_source_relay_headers_interval
{
// there are no new **free** relay chain headers in the range
log::trace!(
target: "bridge",
"Waiting for new free {} headers at {}: scanned {:?}..={:?}",
P::SourceRelayChain::NAME,
P::TargetChain::NAME,
scan_range_begin,
scan_range_end,
);
continue;
}
// we may submit new parachain head for free
best_finalized_relay_block_at_target
},
None => {
// no parachain head at target => let's submit first one
best_finalized_relay_block_at_target
},
}
} else {
best_finalized_relay_block_at_target
};
// now let's check if we need to update parachain head at all
let head_at_source = let head_at_source =
read_head_at_source(&source_client, metrics.as_ref(), &best_finalized_relay_block) read_head_at_source(&source_client, metrics.as_ref(), &prove_at_relay_block).await?;
.await?;
let is_update_required = is_update_required::<P>( let is_update_required = is_update_required::<P>(
head_at_source, head_at_source,
head_at_target, head_at_target,
best_finalized_relay_block, prove_at_relay_block,
best_target_block, best_target_block,
); );
if is_update_required { if is_update_required {
let (head_proof, head_hash) = source_client let (head_proof, head_hash) =
.prove_parachain_head(best_finalized_relay_block) source_client.prove_parachain_head(prove_at_relay_block).await.map_err(|e| {
.await
.map_err(|e| {
log::warn!( log::warn!(
target: "bridge", target: "bridge",
"Failed to prove {} parachain ParaId({}) heads: {:?}", "Failed to prove {} parachain ParaId({}) heads: {:?}",
...@@ -283,12 +378,17 @@ where ...@@ -283,12 +378,17 @@ where
P::SourceRelayChain::NAME, P::SourceRelayChain::NAME,
P::SourceParachain::PARACHAIN_ID, P::SourceParachain::PARACHAIN_ID,
P::TargetChain::NAME, P::TargetChain::NAME,
best_finalized_relay_block, prove_at_relay_block,
head_hash, head_hash,
); );
let transaction_tracker = target_client let transaction_tracker = target_client
.submit_parachain_head_proof(best_finalized_relay_block, head_hash, head_proof) .submit_parachain_head_proof(
prove_at_relay_block,
head_hash,
head_proof,
only_free_headers,
)
.await .await
.map_err(|e| { .map_err(|e| {
log::warn!( log::warn!(
...@@ -311,7 +411,7 @@ where ...@@ -311,7 +411,7 @@ where
fn is_update_required<P: ParachainsPipeline>( fn is_update_required<P: ParachainsPipeline>(
head_at_source: AvailableHeader<HeaderIdOf<P::SourceParachain>>, head_at_source: AvailableHeader<HeaderIdOf<P::SourceParachain>>,
head_at_target: Option<HeaderIdOf<P::SourceParachain>>, head_at_target: Option<HeaderIdOf<P::SourceParachain>>,
best_finalized_relay_block_at_source: HeaderIdOf<P::SourceRelayChain>, prove_at_relay_block: HeaderIdOf<P::SourceRelayChain>,
best_target_block: HeaderIdOf<P::TargetChain>, best_target_block: HeaderIdOf<P::TargetChain>,
) -> bool ) -> bool
where where
...@@ -326,7 +426,7 @@ where ...@@ -326,7 +426,7 @@ where
P::SourceParachain::PARACHAIN_ID, P::SourceParachain::PARACHAIN_ID,
P::TargetChain::NAME, P::TargetChain::NAME,
P::SourceRelayChain::NAME, P::SourceRelayChain::NAME,
best_finalized_relay_block_at_source, prove_at_relay_block,
head_at_source, head_at_source,
P::TargetChain::NAME, P::TargetChain::NAME,
best_target_block, best_target_block,
...@@ -413,24 +513,28 @@ async fn read_head_at_source<P: ParachainsPipeline>( ...@@ -413,24 +513,28 @@ async fn read_head_at_source<P: ParachainsPipeline>(
} }
} }
/// Reads parachain head from the target client. /// Reads parachain head from the target client. Also returns source relay chain header
/// that has been used to prove that head.
async fn read_head_at_target<P: ParachainsPipeline>( async fn read_head_at_target<P: ParachainsPipeline>(
target_client: &impl TargetClient<P>, target_client: &impl TargetClient<P>,
metrics: Option<&ParachainsLoopMetrics>, metrics: Option<&ParachainsLoopMetrics>,
at_block: &HeaderIdOf<P::TargetChain>, at_block: &HeaderIdOf<P::TargetChain>,
) -> Result<Option<HeaderIdOf<P::SourceParachain>>, FailedClient> { ) -> Result<
(Option<HeaderIdOf<P::SourceRelayChain>>, Option<HeaderIdOf<P::SourceParachain>>),
FailedClient,
> {
let para_head_id = target_client.parachain_head(*at_block).await; let para_head_id = target_client.parachain_head(*at_block).await;
match para_head_id { match para_head_id {
Ok(Some(para_head_id)) => { Ok(Some((relay_header_id, para_head_id))) => {
if let Some(metrics) = metrics { if let Some(metrics) = metrics {
metrics.update_best_parachain_block_at_target( metrics.update_best_parachain_block_at_target(
ParaId(P::SourceParachain::PARACHAIN_ID), ParaId(P::SourceParachain::PARACHAIN_ID),
para_head_id.number(), para_head_id.number(),
); );
} }
Ok(Some(para_head_id)) Ok((Some(relay_header_id), Some(para_head_id)))
}, },
Ok(None) => Ok(None), Ok(None) => Ok((None, None)),
Err(e) => { Err(e) => {
log::warn!( log::warn!(
target: "bridge", target: "bridge",
...@@ -543,6 +647,7 @@ mod tests { ...@@ -543,6 +647,7 @@ mod tests {
use relay_substrate_client::test_chain::{TestChain, TestParachain}; use relay_substrate_client::test_chain::{TestChain, TestParachain};
use relay_utils::{HeaderId, MaybeConnectionError}; use relay_utils::{HeaderId, MaybeConnectionError};
use sp_core::H256; use sp_core::H256;
use std::collections::HashMap;
const PARA_10_HASH: ParaHash = H256([10u8; 32]); const PARA_10_HASH: ParaHash = H256([10u8; 32]);
const PARA_20_HASH: ParaHash = H256([20u8; 32]); const PARA_20_HASH: ParaHash = H256([20u8; 32]);
...@@ -590,14 +695,21 @@ mod tests { ...@@ -590,14 +695,21 @@ mod tests {
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
struct TestClientData { struct TestClientData {
source_sync_status: Result<bool, TestError>, source_sync_status: Result<bool, TestError>,
source_head: Result<AvailableHeader<HeaderIdOf<TestParachain>>, TestError>, source_head: HashMap<
BlockNumberOf<TestChain>,
Result<AvailableHeader<HeaderIdOf<TestParachain>>, TestError>,
>,
source_proof: Result<(), TestError>, source_proof: Result<(), TestError>,
target_free_source_relay_headers_interval:
Result<Option<BlockNumberOf<TestChain>>, TestError>,
target_best_block: Result<HeaderIdOf<TestChain>, TestError>, target_best_block: Result<HeaderIdOf<TestChain>, TestError>,
target_best_finalized_source_block: Result<HeaderIdOf<TestChain>, TestError>, target_best_finalized_source_block: Result<HeaderIdOf<TestChain>, TestError>,
target_head: Result<Option<HeaderIdOf<TestParachain>>, TestError>, #[allow(clippy::type_complexity)]
target_head: Result<Option<(HeaderIdOf<TestChain>, HeaderIdOf<TestParachain>)>, TestError>,
target_submit_result: Result<(), TestError>, target_submit_result: Result<(), TestError>,
submitted_proof_at_source_relay_block: Option<HeaderIdOf<TestChain>>,
exit_signal_sender: Option<Box<futures::channel::mpsc::UnboundedSender<()>>>, exit_signal_sender: Option<Box<futures::channel::mpsc::UnboundedSender<()>>>,
} }
...@@ -605,14 +717,18 @@ mod tests { ...@@ -605,14 +717,18 @@ mod tests {
pub fn minimal() -> Self { pub fn minimal() -> Self {
TestClientData { TestClientData {
source_sync_status: Ok(true), source_sync_status: Ok(true),
source_head: Ok(AvailableHeader::Available(HeaderId(0, PARA_20_HASH))), source_head: vec![(0, Ok(AvailableHeader::Available(HeaderId(0, PARA_20_HASH))))]
.into_iter()
.collect(),
source_proof: Ok(()), source_proof: Ok(()),
target_free_source_relay_headers_interval: Ok(None),
target_best_block: Ok(HeaderId(0, Default::default())), target_best_block: Ok(HeaderId(0, Default::default())),
target_best_finalized_source_block: Ok(HeaderId(0, Default::default())), target_best_finalized_source_block: Ok(HeaderId(0, Default::default())),
target_head: Ok(None), target_head: Ok(None),
target_submit_result: Ok(()), target_submit_result: Ok(()),
submitted_proof_at_source_relay_block: None,
exit_signal_sender: None, exit_signal_sender: None,
} }
} }
...@@ -649,16 +765,24 @@ mod tests { ...@@ -649,16 +765,24 @@ mod tests {
async fn parachain_head( async fn parachain_head(
&self, &self,
_at_block: HeaderIdOf<TestChain>, at_block: HeaderIdOf<TestChain>,
) -> Result<AvailableHeader<HeaderIdOf<TestParachain>>, TestError> { ) -> Result<AvailableHeader<HeaderIdOf<TestParachain>>, TestError> {
self.data.lock().await.source_head.clone() self.data
.lock()
.await
.source_head
.get(&at_block.0)
.expect(&format!("SourceClient::parachain_head({})", at_block.0))
.clone()
} }
async fn prove_parachain_head( async fn prove_parachain_head(
&self, &self,
_at_block: HeaderIdOf<TestChain>, at_block: HeaderIdOf<TestChain>,
) -> Result<(ParaHeadsProof, ParaHash), TestError> { ) -> Result<(ParaHeadsProof, ParaHash), TestError> {
let head = *self.data.lock().await.source_head.clone()?.as_available().unwrap(); let head_result =
SourceClient::<TestParachainsPipeline>::parachain_head(self, at_block).await?;
let head = head_result.as_available().unwrap();
let storage_proof = vec![head.hash().encode()]; let storage_proof = vec![head.hash().encode()];
let proof = (ParaHeadsProof { storage_proof }, head.hash()); let proof = (ParaHeadsProof { storage_proof }, head.hash());
self.data.lock().await.source_proof.clone().map(|_| proof) self.data.lock().await.source_proof.clone().map(|_| proof)
...@@ -680,21 +804,29 @@ mod tests { ...@@ -680,21 +804,29 @@ mod tests {
self.data.lock().await.target_best_finalized_source_block.clone() self.data.lock().await.target_best_finalized_source_block.clone()
} }
async fn free_source_relay_headers_interval(
&self,
) -> Result<Option<BlockNumberOf<TestParachain>>, TestError> {
self.data.lock().await.target_free_source_relay_headers_interval.clone()
}
async fn parachain_head( async fn parachain_head(
&self, &self,
_at_block: HeaderIdOf<TestChain>, _at_block: HeaderIdOf<TestChain>,
) -> Result<Option<HeaderIdOf<TestParachain>>, TestError> { ) -> Result<Option<(HeaderIdOf<TestChain>, HeaderIdOf<TestParachain>)>, TestError> {
self.data.lock().await.target_head.clone() self.data.lock().await.target_head.clone()
} }
async fn submit_parachain_head_proof( async fn submit_parachain_head_proof(
&self, &self,
_at_source_block: HeaderIdOf<TestChain>, at_source_block: HeaderIdOf<TestChain>,
_updated_parachain_head: ParaHash, _updated_parachain_head: ParaHash,
_proof: ParaHeadsProof, _proof: ParaHeadsProof,
_is_free_execution_expected: bool,
) -> Result<TestTransactionTracker, Self::Error> { ) -> Result<TestTransactionTracker, Self::Error> {
let mut data = self.data.lock().await; let mut data = self.data.lock().await;
data.target_submit_result.clone()?; data.target_submit_result.clone()?;
data.submitted_proof_at_source_relay_block = Some(at_source_block);
if let Some(mut exit_signal_sender) = data.exit_signal_sender.take() { if let Some(mut exit_signal_sender) = data.exit_signal_sender.take() {
exit_signal_sender.send(()).await.unwrap(); exit_signal_sender.send(()).await.unwrap();
...@@ -715,6 +847,7 @@ mod tests { ...@@ -715,6 +847,7 @@ mod tests {
TestClient::from(test_source_client), TestClient::from(test_source_client),
TestClient::from(TestClientData::minimal()), TestClient::from(TestClientData::minimal()),
None, None,
false,
futures::future::pending(), futures::future::pending(),
)), )),
Err(FailedClient::Source), Err(FailedClient::Source),
...@@ -731,6 +864,7 @@ mod tests { ...@@ -731,6 +864,7 @@ mod tests {
TestClient::from(TestClientData::minimal()), TestClient::from(TestClientData::minimal()),
TestClient::from(test_target_client), TestClient::from(test_target_client),
None, None,
false,
futures::future::pending(), futures::future::pending(),
)), )),
Err(FailedClient::Target), Err(FailedClient::Target),
...@@ -747,6 +881,7 @@ mod tests { ...@@ -747,6 +881,7 @@ mod tests {
TestClient::from(TestClientData::minimal()), TestClient::from(TestClientData::minimal()),
TestClient::from(test_target_client), TestClient::from(test_target_client),
None, None,
false,
futures::future::pending(), futures::future::pending(),
)), )),
Err(FailedClient::Target), Err(FailedClient::Target),
...@@ -763,6 +898,7 @@ mod tests { ...@@ -763,6 +898,7 @@ mod tests {
TestClient::from(TestClientData::minimal()), TestClient::from(TestClientData::minimal()),
TestClient::from(test_target_client), TestClient::from(test_target_client),
None, None,
false,
futures::future::pending(), futures::future::pending(),
)), )),
Err(FailedClient::Target), Err(FailedClient::Target),
...@@ -772,13 +908,14 @@ mod tests { ...@@ -772,13 +908,14 @@ mod tests {
#[test] #[test]
fn when_source_client_fails_to_read_heads() { fn when_source_client_fails_to_read_heads() {
let mut test_source_client = TestClientData::minimal(); let mut test_source_client = TestClientData::minimal();
test_source_client.source_head = Err(TestError::Error); test_source_client.source_head.insert(0, Err(TestError::Error));
assert_eq!( assert_eq!(
async_std::task::block_on(run_until_connection_lost( async_std::task::block_on(run_until_connection_lost(
TestClient::from(test_source_client), TestClient::from(test_source_client),
TestClient::from(TestClientData::minimal()), TestClient::from(TestClientData::minimal()),
None, None,
false,
futures::future::pending(), futures::future::pending(),
)), )),
Err(FailedClient::Source), Err(FailedClient::Source),
...@@ -795,6 +932,7 @@ mod tests { ...@@ -795,6 +932,7 @@ mod tests {
TestClient::from(test_source_client), TestClient::from(test_source_client),
TestClient::from(TestClientData::minimal()), TestClient::from(TestClientData::minimal()),
None, None,
false,
futures::future::pending(), futures::future::pending(),
)), )),
Err(FailedClient::Source), Err(FailedClient::Source),
...@@ -811,6 +949,7 @@ mod tests { ...@@ -811,6 +949,7 @@ mod tests {
TestClient::from(TestClientData::minimal()), TestClient::from(TestClientData::minimal()),
TestClient::from(test_target_client), TestClient::from(test_target_client),
None, None,
false,
futures::future::pending(), futures::future::pending(),
)), )),
Err(FailedClient::Target), Err(FailedClient::Target),
...@@ -825,12 +964,108 @@ mod tests { ...@@ -825,12 +964,108 @@ mod tests {
TestClient::from(TestClientData::minimal()), TestClient::from(TestClientData::minimal()),
TestClient::from(TestClientData::with_exit_signal_sender(exit_signal_sender)), TestClient::from(TestClientData::with_exit_signal_sender(exit_signal_sender)),
None, None,
false,
exit_signal.into_future().map(|(_, _)| ()), exit_signal.into_future().map(|(_, _)| ()),
)), )),
Ok(()), Ok(()),
); );
} }
#[async_std::test]
async fn free_headers_are_relayed() {
// prepare following case:
// 1) best source relay at target: 95
// 2) best source parachain at target: 5 at relay 50
// 3) free headers interval: 10
// 4) at source relay chain block 90 source parachain block is 9
// +
// 5) best finalized source relay chain block is 95
// 6) at source relay chain block 95 source parachain block is 42
// =>
// parachain block 42 would have been relayed, because 95 - 50 > 10
let (exit_signal_sender, exit_signal) = futures::channel::mpsc::unbounded();
let clients_data = TestClientData {
source_sync_status: Ok(true),
source_head: vec![
(90, Ok(AvailableHeader::Available(HeaderId(9, [9u8; 32].into())))),
(95, Ok(AvailableHeader::Available(HeaderId(42, [42u8; 32].into())))),
]
.into_iter()
.collect(),
source_proof: Ok(()),
target_free_source_relay_headers_interval: Ok(Some(10)),
target_best_block: Ok(HeaderId(200, [200u8; 32].into())),
target_best_finalized_source_block: Ok(HeaderId(95, [95u8; 32].into())),
target_head: Ok(Some((HeaderId(50, [50u8; 32].into()), HeaderId(5, [5u8; 32].into())))),
target_submit_result: Ok(()),
submitted_proof_at_source_relay_block: None,
exit_signal_sender: Some(Box::new(exit_signal_sender)),
};
let source_client = TestClient::from(clients_data.clone());
let target_client = TestClient::from(clients_data);
assert_eq!(
run_until_connection_lost(
source_client,
target_client.clone(),
None,
true,
exit_signal.into_future().map(|(_, _)| ()),
)
.await,
Ok(()),
);
assert_eq!(
target_client
.data
.lock()
.await
.submitted_proof_at_source_relay_block
.map(|id| id.0),
Some(95)
);
// now source relay block chain 104 is mined with parachain head #84
// => since 104 - 95 < 10, there are no free headers
// => nothing is submitted
let mut clients_data: TestClientData = target_client.data.lock().await.clone();
clients_data
.source_head
.insert(104, Ok(AvailableHeader::Available(HeaderId(84, [84u8; 32].into()))));
clients_data.target_best_finalized_source_block = Ok(HeaderId(104, [104u8; 32].into()));
clients_data.target_head =
Ok(Some((HeaderId(95, [95u8; 32].into()), HeaderId(42, [42u8; 32].into()))));
clients_data.target_best_block = Ok(HeaderId(255, [255u8; 32].into()));
clients_data.exit_signal_sender = None;
let source_client = TestClient::from(clients_data.clone());
let target_client = TestClient::from(clients_data);
assert_eq!(
run_until_connection_lost(
source_client,
target_client.clone(),
None,
true,
async_std::task::sleep(std::time::Duration::from_millis(100)),
)
.await,
Ok(()),
);
assert_eq!(
target_client
.data
.lock()
.await
.submitted_proof_at_source_relay_block
.map(|id| id.0),
Some(95)
);
}
fn test_tx_tracker() -> SubmittedHeadsTracker<TestParachainsPipeline> { fn test_tx_tracker() -> SubmittedHeadsTracker<TestParachainsPipeline> {
SubmittedHeadsTracker::new( SubmittedHeadsTracker::new(
AvailableHeader::Available(HeaderId(20, PARA_20_HASH)), AvailableHeader::Available(HeaderId(20, PARA_20_HASH)),
......
...@@ -273,8 +273,10 @@ where ...@@ -273,8 +273,10 @@ where
}, },
None => { None => {
instructions.extend(vec![ instructions.extend(vec![
// Deposit asset to beneficiary. // Deposit both asset and fees to beneficiary so the fees will not get
DepositAsset { assets: Definite(asset.into()), beneficiary }, // trapped. Another benefit is when fees left more than ED on AssetHub could be
// used to create the beneficiary account in case it does not exist.
DepositAsset { assets: Wild(AllCounted(2)), beneficiary },
]); ]);
}, },
} }
......
...@@ -40,7 +40,7 @@ cumulus_based = true ...@@ -40,7 +40,7 @@ cumulus_based = true
rpc_port = 8933 rpc_port = 8933
ws_port = 8943 ws_port = 8943
args = [ args = [
"-lparachain=debug,runtime::bridge-hub=trace,runtime::bridge=trace,runtime::bridge-dispatch=trace,bridge=trace,runtime::bridge-messages=trace,xcm=trace" "-lparachain=debug,runtime::bridge=trace,xcm=trace,txpool=trace"
] ]
# run bob as parachain collator # run bob as parachain collator
...@@ -51,7 +51,7 @@ cumulus_based = true ...@@ -51,7 +51,7 @@ cumulus_based = true
rpc_port = 8934 rpc_port = 8934
ws_port = 8944 ws_port = 8944
args = [ args = [
"-lparachain=trace,runtime::bridge-hub=trace,runtime::bridge=trace,runtime::bridge-dispatch=trace,bridge=trace,runtime::bridge-messages=trace,xcm=trace" "-lparachain=debug,runtime::bridge=trace,xcm=trace,txpool=trace"
] ]
[[parachains]] [[parachains]]
...@@ -65,14 +65,14 @@ cumulus_based = true ...@@ -65,14 +65,14 @@ cumulus_based = true
ws_port = 9910 ws_port = 9910
command = "{{POLKADOT_PARACHAIN_BINARY}}" command = "{{POLKADOT_PARACHAIN_BINARY}}"
args = [ args = [
"-lparachain=debug,xcm=trace,runtime::bridge-transfer=trace" "-lparachain=debug,xcm=trace,runtime::bridge=trace,txpool=trace"
] ]
[[parachains.collators]] [[parachains.collators]]
name = "asset-hub-rococo-collator2" name = "asset-hub-rococo-collator2"
command = "{{POLKADOT_PARACHAIN_BINARY}}" command = "{{POLKADOT_PARACHAIN_BINARY}}"
args = [ args = [
"-lparachain=debug,xcm=trace,runtime::bridge-transfer=trace" "-lparachain=debug,xcm=trace,runtime::bridge=trace,txpool=trace"
] ]
#[[hrmp_channels]] #[[hrmp_channels]]
......
...@@ -40,7 +40,7 @@ cumulus_based = true ...@@ -40,7 +40,7 @@ cumulus_based = true
rpc_port = 8935 rpc_port = 8935
ws_port = 8945 ws_port = 8945
args = [ args = [
"-lparachain=debug,runtime::mmr=info,substrate=info,runtime=info,runtime::bridge-hub=trace,runtime::bridge=trace,runtime::bridge-dispatch=trace,bridge=trace,runtime::bridge-messages=trace,xcm=trace" "-lparachain=debug,runtime::bridge=trace,xcm=trace,txpool=trace"
] ]
# run bob as parachain collator # run bob as parachain collator
...@@ -51,7 +51,7 @@ cumulus_based = true ...@@ -51,7 +51,7 @@ cumulus_based = true
rpc_port = 8936 rpc_port = 8936
ws_port = 8946 ws_port = 8946
args = [ args = [
"-lparachain=trace,runtime::mmr=info,substrate=info,runtime=info,runtime::bridge-hub=trace,runtime::bridge=trace,runtime::bridge-dispatch=trace,bridge=trace,runtime::bridge-messages=trace,xcm=trace" "-lparachain=debug,runtime::bridge=trace,xcm=trace,txpool=trace"
] ]
[[parachains]] [[parachains]]
...@@ -65,14 +65,14 @@ cumulus_based = true ...@@ -65,14 +65,14 @@ cumulus_based = true
ws_port = 9010 ws_port = 9010
command = "{{POLKADOT_PARACHAIN_BINARY}}" command = "{{POLKADOT_PARACHAIN_BINARY}}"
args = [ args = [
"-lparachain=debug,xcm=trace,runtime::bridge-transfer=trace" "-lparachain=debug,xcm=trace,runtime::bridge=trace,txpool=trace"
] ]
[[parachains.collators]] [[parachains.collators]]
name = "asset-hub-westend-collator2" name = "asset-hub-westend-collator2"
command = "{{POLKADOT_PARACHAIN_BINARY}}" command = "{{POLKADOT_PARACHAIN_BINARY}}"
args = [ args = [
"-lparachain=debug,xcm=trace,runtime::bridge-transfer=trace" "-lparachain=debug,xcm=trace,runtime::bridge=trace,txpool=trace"
] ]
#[[hrmp_channels]] #[[hrmp_channels]]
......
...@@ -169,12 +169,107 @@ function run_relay() { ...@@ -169,12 +169,107 @@ function run_relay() {
--lane "${LANE_ID}" --lane "${LANE_ID}"
} }
function run_finality_relay() {
local relayer_path=$(ensure_relayer)
RUST_LOG=runtime=trace,rpc=trace,bridge=trace \
$relayer_path relay-headers rococo-to-bridge-hub-westend \
--only-free-headers \
--source-host localhost \
--source-port 9942 \
--target-host localhost \
--target-port 8945 \
--target-version-mode Auto \
--target-signer //Charlie \
--target-transactions-mortality 4&
RUST_LOG=runtime=trace,rpc=trace,bridge=trace \
$relayer_path relay-headers westend-to-bridge-hub-rococo \
--only-free-headers \
--source-host localhost \
--source-port 9945 \
--target-host localhost \
--target-port 8943 \
--target-version-mode Auto \
--target-signer //Charlie \
--target-transactions-mortality 4
}
function run_parachains_relay() {
local relayer_path=$(ensure_relayer)
RUST_LOG=runtime=trace,rpc=trace,bridge=trace \
$relayer_path relay-parachains rococo-to-bridge-hub-westend \
--only-free-headers \
--source-host localhost \
--source-port 9942 \
--target-host localhost \
--target-port 8945 \
--target-version-mode Auto \
--target-signer //Dave \
--target-transactions-mortality 4&
RUST_LOG=runtime=trace,rpc=trace,bridge=trace \
$relayer_path relay-parachains westend-to-bridge-hub-rococo \
--only-free-headers \
--source-host localhost \
--source-port 9945 \
--target-host localhost \
--target-port 8943 \
--target-version-mode Auto \
--target-signer //Dave \
--target-transactions-mortality 4
}
function run_messages_relay() {
local relayer_path=$(ensure_relayer)
RUST_LOG=runtime=trace,rpc=trace,bridge=trace \
$relayer_path relay-messages bridge-hub-rococo-to-bridge-hub-westend \
--source-host localhost \
--source-port 8943 \
--source-version-mode Auto \
--source-signer //Eve \
--source-transactions-mortality 4 \
--target-host localhost \
--target-port 8945 \
--target-version-mode Auto \
--target-signer //Eve \
--target-transactions-mortality 4 \
--lane $LANE_ID&
RUST_LOG=runtime=trace,rpc=trace,bridge=trace \
$relayer_path relay-messages bridge-hub-westend-to-bridge-hub-rococo \
--source-host localhost \
--source-port 8945 \
--source-version-mode Auto \
--source-signer //Ferdie \
--source-transactions-mortality 4 \
--target-host localhost \
--target-port 8943 \
--target-version-mode Auto \
--target-signer //Ferdie \
--target-transactions-mortality 4 \
--lane $LANE_ID
}
case "$1" in case "$1" in
run-relay) run-relay)
init_wnd_ro init_wnd_ro
init_ro_wnd init_ro_wnd
run_relay run_relay
;; ;;
run-finality-relay)
init_wnd_ro
init_ro_wnd
run_finality_relay
;;
run-parachains-relay)
run_parachains_relay
;;
run-messages-relay)
run_messages_relay
;;
init-asset-hub-rococo-local) init-asset-hub-rococo-local)
ensure_polkadot_js_api ensure_polkadot_js_api
# create foreign assets for native Westend token (governance call on Rococo) # create foreign assets for native Westend token (governance call on Rococo)
...@@ -386,6 +481,9 @@ case "$1" in ...@@ -386,6 +481,9 @@ case "$1" in
echo "A command is require. Supported commands for: echo "A command is require. Supported commands for:
Local (zombienet) run: Local (zombienet) run:
- run-relay - run-relay
- run-finality-relay
- run-parachains-relay
- run-messages-relay
- init-asset-hub-rococo-local - init-asset-hub-rococo-local
- init-bridge-hub-rococo-local - init-bridge-hub-rococo-local
- init-asset-hub-westend-local - init-asset-hub-westend-local
......
#!/bin/bash
# Rococo AH
xdg-open https://polkadot.js.org/apps/?rpc=ws://127.0.0.1:9910#/explorer&
# Rococo BH
xdg-open https://polkadot.js.org/apps/?rpc=ws://127.0.0.1:8943#/explorer&
# Westend BH
xdg-open https://polkadot.js.org/apps/?rpc=ws://127.0.0.1:8945#/explorer&
# Westend AH
xdg-open https://polkadot.js.org/apps/?rpc=ws://127.0.0.1:9010#/explorer&
#!/bin/bash #!/bin/bash
if [ $1 == "auto-log" ]; then
shift # ignore "auto-log"
log_name=$1
$ENV_PATH/bridges_rococo_westend.sh "$@" >$TEST_DIR/logs/$log_name.log
else
$ENV_PATH/bridges_rococo_westend.sh "$@" $ENV_PATH/bridges_rococo_westend.sh "$@"
fi
...@@ -59,12 +59,12 @@ if [[ $init -eq 1 ]]; then ...@@ -59,12 +59,12 @@ if [[ $init -eq 1 ]]; then
fi fi
if [[ $start_relayer -eq 1 ]]; then if [[ $start_relayer -eq 1 ]]; then
${BASH_SOURCE%/*}/start_relayer.sh $rococo_dir $westend_dir relayer_pid ${BASH_SOURCE%/*}/start_relayer.sh $rococo_dir $westend_dir finality_relayer_pid parachains_relayer_pid messages_relayer_pid
fi fi
echo $rococo_dir > $TEST_DIR/rococo.env echo $rococo_dir > $TEST_DIR/rococo.env
echo $westend_dir > $TEST_DIR/westend.env echo $westend_dir > $TEST_DIR/westend.env
echo echo
wait -n $rococo_pid $westend_pid $relayer_pid wait -n $rococo_pid $westend_pid $finality_relayer_pid $parachains_relayer_pid $messages_relayer_pid
kill -9 -$$ kill -9 -$$