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::{Client, Parachain};
use relay_utils::metrics::{GlobalMetrics, StandaloneMetric};
use std::sync::Arc;
use structopt::StructOpt;
use crate::{
cli::{
bridge::{CliBridgeBase, ParachainToRelayHeadersCliBridge},
chain_schema::*,
DefaultClient, PrometheusParams,
},
finality::SubstrateFinalitySyncPipeline,
parachains::{source::ParachainsSource, target::ParachainsTarget, ParachainsPipelineAdapter},
TransactionParams,
};
#[derive(StructOpt)]
pub struct RelayParachainsParams {
#[structopt(flatten)]
source: SourceConnectionParams,
#[structopt(flatten)]
target: TargetConnectionParams,
#[structopt(flatten)]
target_sign: TargetSigningParams,
#[structopt(long)]
only_free_headers: bool,
#[structopt(flatten)]
prometheus_params: PrometheusParams,
}
#[derive(StructOpt)]
pub struct RelayParachainHeadParams {
#[structopt(flatten)]
source: SourceConnectionParams,
#[structopt(flatten)]
target: TargetConnectionParams,
#[structopt(flatten)]
target_sign: TargetSigningParams,
#[structopt(long)]
at_relay_block: RelayBlockNumber,
}
#[async_trait]
pub trait ParachainsRelayer: ParachainToRelayHeadersCliBridge
where
ParachainsSource<Self::ParachainFinality, DefaultClient<Self::SourceRelay>>:
SourceClient<ParachainsPipelineAdapter<Self::ParachainFinality>>,
ParachainsTarget<
Self::ParachainFinality,
DefaultClient<Self::SourceRelay>,
DefaultClient<Self::Target>,
>: TargetClient<ParachainsPipelineAdapter<Self::ParachainFinality>>,
<Self as CliBridgeBase>::Source: Parachain,
{
async fn relay_parachains(data: RelayParachainsParams) -> anyhow::Result<()> {
let source_chain_client = data.source.into_client::<Self::SourceRelay>().await?;
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,
);
let metrics_params: relay_utils::metrics::MetricsParams =
data.prometheus_params.into_metrics_params()?;
GlobalMetrics::new()?.register_and_spawn(&metrics_params.registry)?;
Self::RelayFinality::start_relay_guards(
target_client.target_client(),
target_client.target_client().can_start_version_guard(),
)
.await?;
parachains_relay::parachains_loop::run(
source_client,
target_client,
metrics_params,
data.only_free_headers,
futures::future::pending(),
)
.await
.map_err(|e| anyhow::format_err!("{}", e))
}
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"))
}
}