mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-07-24 04:15:45 +00:00
Bridge: added free headers submission support to the substrate-relay (#4157)
Original PR: https://github.com/paritytech/parity-bridges-common/pull/2884. Since chain-specific code lives in the `parity-bridges-common` repo, some parts of original PR will require another PR --------- Co-authored-by: Adrian Catangiu <adrian@parity.io>
This commit is contained in:
committed by
GitHub
parent
a633e954f3
commit
7e68b2b8da
@@ -24,6 +24,7 @@ use relay_utils::metrics::{GlobalMetrics, StandaloneMetric};
|
||||
use crate::{
|
||||
cli::{bridge::*, chain_schema::*, PrometheusParams},
|
||||
finality::SubstrateFinalitySyncPipeline,
|
||||
HeadersToRelay,
|
||||
};
|
||||
|
||||
/// Chain headers relaying params.
|
||||
@@ -33,6 +34,10 @@ pub struct RelayHeadersParams {
|
||||
/// are relayed.
|
||||
#[structopt(long)]
|
||||
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)]
|
||||
only_free_headers: bool,
|
||||
#[structopt(flatten)]
|
||||
source: SourceConnectionParams,
|
||||
#[structopt(flatten)]
|
||||
@@ -43,11 +48,22 @@ pub struct RelayHeadersParams {
|
||||
prometheus_params: PrometheusParams,
|
||||
}
|
||||
|
||||
impl RelayHeadersParams {
|
||||
fn headers_to_relay(&self) -> HeadersToRelay {
|
||||
match (self.only_mandatory_headers, self.only_free_headers) {
|
||||
(_, true) => HeadersToRelay::Free,
|
||||
(true, false) => HeadersToRelay::Mandatory,
|
||||
_ => HeadersToRelay::All,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Trait used for relaying headers between 2 chains.
|
||||
#[async_trait]
|
||||
pub trait HeadersRelayer: RelayToRelayHeadersCliBridge {
|
||||
/// Relay headers.
|
||||
async fn relay_headers(data: RelayHeadersParams) -> anyhow::Result<()> {
|
||||
let headers_to_relay = data.headers_to_relay();
|
||||
let source_client = data.source.into_client::<Self::Source>().await?;
|
||||
let target_client = data.target.into_client::<Self::Target>().await?;
|
||||
let target_transactions_mortality = data.target_sign.target_transactions_mortality;
|
||||
@@ -67,7 +83,7 @@ pub trait HeadersRelayer: RelayToRelayHeadersCliBridge {
|
||||
crate::finality::run::<Self::Finality>(
|
||||
source_client,
|
||||
target_client,
|
||||
data.only_mandatory_headers,
|
||||
headers_to_relay,
|
||||
target_transactions_params,
|
||||
metrics_params,
|
||||
)
|
||||
|
||||
@@ -40,7 +40,7 @@ use crate::{
|
||||
cli::{bridge::MessagesCliBridge, HexLaneId, PrometheusParams},
|
||||
messages_lane::{MessagesRelayLimits, MessagesRelayParams},
|
||||
on_demand::OnDemandRelay,
|
||||
TaggedAccount, TransactionParams,
|
||||
HeadersToRelay, TaggedAccount, TransactionParams,
|
||||
};
|
||||
use bp_messages::LaneId;
|
||||
use bp_runtime::BalanceOf;
|
||||
@@ -61,11 +61,25 @@ pub struct HeadersAndMessagesSharedParams {
|
||||
/// are relayed.
|
||||
#[structopt(long)]
|
||||
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)]
|
||||
/// Prometheus metrics params.
|
||||
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.
|
||||
pub struct Full2WayBridgeCommonParams<
|
||||
Left: ChainWithTransactions + ChainWithRuntimeVersion,
|
||||
@@ -418,6 +432,7 @@ mod tests {
|
||||
shared: HeadersAndMessagesSharedParams {
|
||||
lane: vec![HexLaneId([0x00, 0x00, 0x00, 0x00])],
|
||||
only_mandatory_headers: false,
|
||||
only_free_headers: false,
|
||||
prometheus_params: PrometheusParams {
|
||||
no_prometheus: false,
|
||||
prometheus_host: "0.0.0.0".into(),
|
||||
|
||||
+2
-2
@@ -180,7 +180,7 @@ where
|
||||
self.left_relay.clone(),
|
||||
self.common.right.client.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()),
|
||||
);
|
||||
let right_relay_to_left_on_demand_headers =
|
||||
@@ -188,7 +188,7 @@ where
|
||||
self.right_relay.clone(),
|
||||
self.common.left.client.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()),
|
||||
);
|
||||
|
||||
|
||||
+2
-2
@@ -171,7 +171,7 @@ where
|
||||
self.common.left.client.clone(),
|
||||
self.common.right.client.clone(),
|
||||
self.common.right.tx_params.clone(),
|
||||
self.common.shared.only_mandatory_headers,
|
||||
self.common.shared.headers_to_relay(),
|
||||
None,
|
||||
);
|
||||
let right_relay_to_left_on_demand_headers =
|
||||
@@ -179,7 +179,7 @@ where
|
||||
self.right_relay.clone(),
|
||||
self.common.left.client.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()),
|
||||
);
|
||||
let right_to_left_on_demand_parachains = OnDemandParachainsRelay::<
|
||||
|
||||
+2
-2
@@ -152,7 +152,7 @@ where
|
||||
self.common.left.client.clone(),
|
||||
self.common.right.client.clone(),
|
||||
self.common.right.tx_params.clone(),
|
||||
self.common.shared.only_mandatory_headers,
|
||||
self.common.shared.headers_to_relay(),
|
||||
None,
|
||||
);
|
||||
let right_to_left_on_demand_headers =
|
||||
@@ -160,7 +160,7 @@ where
|
||||
self.common.right.client.clone(),
|
||||
self.common.left.client.clone(),
|
||||
self.common.left.tx_params.clone(),
|
||||
self.common.shared.only_mandatory_headers,
|
||||
self.common.shared.headers_to_relay(),
|
||||
None,
|
||||
);
|
||||
|
||||
|
||||
@@ -43,6 +43,10 @@ pub struct RelayParachainsParams {
|
||||
target: TargetConnectionParams,
|
||||
#[structopt(flatten)]
|
||||
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)]
|
||||
prometheus_params: PrometheusParams,
|
||||
}
|
||||
@@ -59,9 +63,9 @@ where
|
||||
{
|
||||
/// Start relaying parachains finality.
|
||||
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(
|
||||
source_client,
|
||||
source_chain_client.clone(),
|
||||
Arc::new(Mutex::new(AvailableHeader::Missing)),
|
||||
);
|
||||
|
||||
@@ -69,9 +73,10 @@ where
|
||||
signer: data.target_sign.to_keypair::<Self::Target>()?,
|
||||
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(
|
||||
target_client.clone(),
|
||||
source_chain_client,
|
||||
target_chain_client,
|
||||
target_transaction_params,
|
||||
);
|
||||
|
||||
@@ -83,6 +88,7 @@ where
|
||||
source_client,
|
||||
target_client,
|
||||
metrics_params,
|
||||
data.only_free_headers,
|
||||
futures::future::pending(),
|
||||
)
|
||||
.await
|
||||
|
||||
@@ -25,7 +25,7 @@ use crate::{
|
||||
|
||||
use async_trait::async_trait;
|
||||
use bp_header_chain::justification::{GrandpaJustification, JustificationVerificationContext};
|
||||
use finality_relay::{FinalityPipeline, FinalitySyncPipeline};
|
||||
use finality_relay::{FinalityPipeline, FinalitySyncPipeline, HeadersToRelay};
|
||||
use pallet_bridge_grandpa::{Call as BridgeGrandpaCall, Config as BridgeGrandpaConfig};
|
||||
use relay_substrate_client::{
|
||||
transaction_stall_timeout, AccountIdOf, AccountKeyPairOf, BlockNumberOf, CallOf, Chain,
|
||||
@@ -115,6 +115,7 @@ pub trait SubmitFinalityProofCallBuilder<P: SubstrateFinalitySyncPipeline> {
|
||||
fn build_submit_finality_proof_call(
|
||||
header: SyncHeader<HeaderOf<P::SourceChain>>,
|
||||
proof: SubstrateFinalityProof<P>,
|
||||
is_free_execution_expected: bool,
|
||||
context: <<P as SubstrateFinalityPipeline>::FinalityEngine as Engine<P::SourceChain>>::FinalityVerificationContext,
|
||||
) -> CallOf<P::TargetChain>;
|
||||
}
|
||||
@@ -142,6 +143,7 @@ where
|
||||
fn build_submit_finality_proof_call(
|
||||
header: SyncHeader<HeaderOf<P::SourceChain>>,
|
||||
proof: GrandpaJustification<HeaderOf<P::SourceChain>>,
|
||||
_is_free_execution_expected: bool,
|
||||
_context: JustificationVerificationContext,
|
||||
) -> CallOf<P::TargetChain> {
|
||||
BridgeGrandpaCall::<R, I>::submit_finality_proof {
|
||||
@@ -176,6 +178,7 @@ macro_rules! generate_submit_finality_proof_call_builder {
|
||||
<$pipeline as $crate::finality_base::SubstrateFinalityPipeline>::SourceChain
|
||||
>
|
||||
>,
|
||||
_is_free_execution_expected: bool,
|
||||
_context: bp_header_chain::justification::JustificationVerificationContext,
|
||||
) -> relay_substrate_client::CallOf<
|
||||
<$pipeline as $crate::finality_base::SubstrateFinalityPipeline>::TargetChain
|
||||
@@ -215,6 +218,7 @@ macro_rules! generate_submit_finality_proof_ex_call_builder {
|
||||
<$pipeline as $crate::finality_base::SubstrateFinalityPipeline>::SourceChain
|
||||
>
|
||||
>,
|
||||
is_free_execution_expected: bool,
|
||||
context: bp_header_chain::justification::JustificationVerificationContext,
|
||||
) -> relay_substrate_client::CallOf<
|
||||
<$pipeline as $crate::finality_base::SubstrateFinalityPipeline>::TargetChain
|
||||
@@ -223,7 +227,8 @@ macro_rules! generate_submit_finality_proof_ex_call_builder {
|
||||
$bridge_grandpa($submit_finality_proof {
|
||||
finality_target: Box::new(header.into_inner()),
|
||||
justification: proof,
|
||||
current_set_id: context.authority_set_id
|
||||
current_set_id: context.authority_set_id,
|
||||
is_free_execution_expected,
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -235,15 +240,16 @@ macro_rules! generate_submit_finality_proof_ex_call_builder {
|
||||
pub async fn run<P: SubstrateFinalitySyncPipeline>(
|
||||
source_client: Client<P::SourceChain>,
|
||||
target_client: Client<P::TargetChain>,
|
||||
only_mandatory_headers: bool,
|
||||
headers_to_relay: HeadersToRelay,
|
||||
transaction_params: TransactionParams<AccountKeyPairOf<P::TargetChain>>,
|
||||
metrics_params: MetricsParams,
|
||||
) -> anyhow::Result<()> {
|
||||
log::info!(
|
||||
target: "bridge",
|
||||
"Starting {} -> {} finality proof relay",
|
||||
"Starting {} -> {} finality proof relay: relaying {:?} headers",
|
||||
P::SourceChain::NAME,
|
||||
P::TargetChain::NAME,
|
||||
headers_to_relay,
|
||||
);
|
||||
|
||||
finality_relay::run(
|
||||
@@ -260,7 +266,7 @@ pub async fn run<P: SubstrateFinalitySyncPipeline>(
|
||||
P::TargetChain::AVERAGE_BLOCK_INTERVAL,
|
||||
relay_utils::STALL_TIMEOUT,
|
||||
),
|
||||
only_mandatory_headers,
|
||||
headers_to_relay,
|
||||
},
|
||||
metrics_params,
|
||||
futures::future::pending(),
|
||||
|
||||
@@ -25,9 +25,10 @@ use crate::{
|
||||
};
|
||||
|
||||
use async_trait::async_trait;
|
||||
use bp_runtime::BlockNumberOf;
|
||||
use finality_relay::TargetClient;
|
||||
use relay_substrate_client::{
|
||||
AccountKeyPairOf, Client, Error, HeaderIdOf, HeaderOf, SyncHeader, TransactionEra,
|
||||
AccountKeyPairOf, Chain, Client, Error, HeaderIdOf, HeaderOf, SyncHeader, TransactionEra,
|
||||
TransactionTracker, UnsignedTransaction,
|
||||
};
|
||||
use relay_utils::relay_loop::Client as RelayClient;
|
||||
@@ -103,10 +104,23 @@ impl<P: SubstrateFinalitySyncPipeline> TargetClient<FinalitySyncPipelineAdapter<
|
||||
.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(
|
||||
&self,
|
||||
header: SyncHeader<HeaderOf<P::SourceChain>>,
|
||||
mut proof: SubstrateFinalityProof<P>,
|
||||
is_free_execution_expected: bool,
|
||||
) -> Result<Self::TransactionTracker, Error> {
|
||||
// verify and runtime module at target chain may require optimized finality proof
|
||||
let context =
|
||||
@@ -115,7 +129,10 @@ impl<P: SubstrateFinalitySyncPipeline> TargetClient<FinalitySyncPipelineAdapter<
|
||||
// now we may submit optimized finality proof
|
||||
let mortality = self.transaction_params.mortality;
|
||||
let call = P::SubmitFinalityProofCallBuilder::build_submit_finality_proof_call(
|
||||
header, proof, context,
|
||||
header,
|
||||
proof,
|
||||
is_free_execution_expected,
|
||||
context,
|
||||
);
|
||||
self.client
|
||||
.submit_and_watch_signed_extrinsic(
|
||||
|
||||
@@ -22,6 +22,9 @@ use relay_substrate_client::{Chain, ChainWithUtilityPallet, UtilityPallet};
|
||||
|
||||
use std::marker::PhantomData;
|
||||
|
||||
// to avoid `finality_relay` dependency in other crates
|
||||
pub use finality_relay::HeadersToRelay;
|
||||
|
||||
pub mod cli;
|
||||
pub mod equivocation;
|
||||
pub mod error;
|
||||
|
||||
@@ -28,7 +28,7 @@ use futures::{select, FutureExt};
|
||||
use num_traits::{One, Saturating, Zero};
|
||||
use sp_runtime::traits::Header;
|
||||
|
||||
use finality_relay::{FinalitySyncParams, TargetClient as FinalityTargetClient};
|
||||
use finality_relay::{FinalitySyncParams, HeadersToRelay, TargetClient as FinalityTargetClient};
|
||||
use relay_substrate_client::{
|
||||
AccountIdOf, AccountKeyPairOf, BlockNumberOf, CallOf, Chain, Client, Error as SubstrateError,
|
||||
HeaderIdOf,
|
||||
@@ -75,7 +75,7 @@ impl<P: SubstrateFinalitySyncPipeline> OnDemandHeadersRelay<P> {
|
||||
source_client: Client<P::SourceChain>,
|
||||
target_client: Client<P::TargetChain>,
|
||||
target_transaction_params: TransactionParams<AccountKeyPairOf<P::TargetChain>>,
|
||||
only_mandatory_headers: bool,
|
||||
headers_to_relay: HeadersToRelay,
|
||||
metrics_params: Option<MetricsParams>,
|
||||
) -> Self
|
||||
where
|
||||
@@ -94,7 +94,7 @@ impl<P: SubstrateFinalitySyncPipeline> OnDemandHeadersRelay<P> {
|
||||
source_client,
|
||||
target_client,
|
||||
target_transaction_params,
|
||||
only_mandatory_headers,
|
||||
headers_to_relay,
|
||||
required_header_number,
|
||||
metrics_params,
|
||||
)
|
||||
@@ -191,7 +191,7 @@ impl<P: SubstrateFinalitySyncPipeline> OnDemandRelay<P::SourceChain, P::TargetCh
|
||||
|
||||
// and then craft the submit-proof call
|
||||
let call = P::SubmitFinalityProofCallBuilder::build_submit_finality_proof_call(
|
||||
header, proof, context,
|
||||
header, proof, false, context,
|
||||
);
|
||||
|
||||
return Ok((header_id, vec![call]));
|
||||
@@ -204,7 +204,7 @@ async fn background_task<P: SubstrateFinalitySyncPipeline>(
|
||||
source_client: Client<P::SourceChain>,
|
||||
target_client: Client<P::TargetChain>,
|
||||
target_transaction_params: TransactionParams<AccountKeyPairOf<P::TargetChain>>,
|
||||
only_mandatory_headers: bool,
|
||||
headers_to_relay: HeadersToRelay,
|
||||
required_header_number: RequiredHeaderNumberRef<P::SourceChain>,
|
||||
metrics_params: Option<MetricsParams>,
|
||||
) where
|
||||
@@ -346,11 +346,11 @@ async fn background_task<P: SubstrateFinalitySyncPipeline>(
|
||||
log::info!(
|
||||
target: "bridge",
|
||||
"[{}] Starting on-demand headers relay task\n\t\
|
||||
Only mandatory headers: {}\n\t\
|
||||
Headers to relay: {:?}\n\t\
|
||||
Tx mortality: {:?} (~{}m)\n\t\
|
||||
Stall timeout: {:?}",
|
||||
relay_task_name,
|
||||
only_mandatory_headers,
|
||||
headers_to_relay,
|
||||
target_transactions_mortality,
|
||||
stall_timeout.as_secs_f64() / 60.0f64,
|
||||
stall_timeout,
|
||||
@@ -367,7 +367,7 @@ async fn background_task<P: SubstrateFinalitySyncPipeline>(
|
||||
),
|
||||
recent_finality_proofs_limit: RECENT_FINALITY_PROOFS_LIMIT,
|
||||
stall_timeout,
|
||||
only_mandatory_headers,
|
||||
headers_to_relay,
|
||||
},
|
||||
metrics_params.clone().unwrap_or_else(MetricsParams::disabled),
|
||||
futures::future::pending(),
|
||||
|
||||
@@ -222,6 +222,7 @@ where
|
||||
proved_relay_block,
|
||||
vec![(para_id, para_hash)],
|
||||
para_proof,
|
||||
false,
|
||||
));
|
||||
|
||||
Ok((proved_parachain_block, calls))
|
||||
@@ -256,8 +257,11 @@ async fn background_task<P: SubstrateParachainsPipeline>(
|
||||
|
||||
let mut parachains_source =
|
||||
ParachainsSource::<P>::new(source_relay_client.clone(), required_para_header_ref.clone());
|
||||
let mut parachains_target =
|
||||
ParachainsTarget::<P>::new(target_client.clone(), target_transaction_params.clone());
|
||||
let mut parachains_target = ParachainsTarget::<P>::new(
|
||||
source_relay_client.clone(),
|
||||
target_client.clone(),
|
||||
target_transaction_params.clone(),
|
||||
);
|
||||
|
||||
loop {
|
||||
select! {
|
||||
@@ -392,6 +396,8 @@ async fn background_task<P: SubstrateParachainsPipeline>(
|
||||
parachains_source.clone(),
|
||||
parachains_target.clone(),
|
||||
MetricsParams::disabled(),
|
||||
// we do not support free parachain headers relay in on-demand relays
|
||||
false,
|
||||
futures::future::pending(),
|
||||
)
|
||||
.fuse(),
|
||||
@@ -481,7 +487,7 @@ where
|
||||
let para_header_at_target = best_finalized_peer_header_at_self::<
|
||||
P::TargetChain,
|
||||
P::SourceParachain,
|
||||
>(target.client(), best_target_block_hash)
|
||||
>(target.target_client(), best_target_block_hash)
|
||||
.await;
|
||||
// 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
|
||||
@@ -504,7 +510,7 @@ where
|
||||
let relay_header_at_target = best_finalized_peer_header_at_self::<
|
||||
P::TargetChain,
|
||||
P::SourceRelayChain,
|
||||
>(target.client(), best_target_block_hash)
|
||||
>(target.target_client(), best_target_block_hash)
|
||||
.await
|
||||
.map_err(map_target_err)?;
|
||||
|
||||
|
||||
@@ -71,6 +71,7 @@ pub trait SubmitParachainHeadsCallBuilder<P: SubstrateParachainsPipeline>:
|
||||
at_relay_block: HeaderIdOf<P::SourceRelayChain>,
|
||||
parachains: Vec<(ParaId, ParaHash)>,
|
||||
parachain_heads_proof: ParaHeadsProof,
|
||||
is_free_execution_expected: bool,
|
||||
) -> CallOf<P::TargetChain>;
|
||||
}
|
||||
|
||||
@@ -97,6 +98,7 @@ where
|
||||
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),
|
||||
|
||||
@@ -24,42 +24,53 @@ use crate::{
|
||||
};
|
||||
|
||||
use async_trait::async_trait;
|
||||
use bp_polkadot_core::parachains::{ParaHash, ParaHeadsProof, ParaId};
|
||||
use bp_runtime::HeaderIdProvider;
|
||||
use codec::Decode;
|
||||
use bp_parachains::{
|
||||
ImportedParaHeadsKeyProvider, ParaInfo, ParaStoredHeaderData, ParasInfoKeyProvider,
|
||||
};
|
||||
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 relay_substrate_client::{
|
||||
AccountIdOf, AccountKeyPairOf, Chain, Client, Error as SubstrateError, HeaderIdOf,
|
||||
ParachainBase, TransactionEra, TransactionTracker, UnsignedTransaction,
|
||||
AccountIdOf, AccountKeyPairOf, BlockNumberOf, Chain, Client, Error as SubstrateError,
|
||||
HeaderIdOf, ParachainBase, RelayChain, TransactionEra, TransactionTracker, UnsignedTransaction,
|
||||
};
|
||||
use relay_utils::relay_loop::Client as RelayClient;
|
||||
use sp_core::{Bytes, Pair};
|
||||
use sp_core::Pair;
|
||||
|
||||
/// Substrate client as parachain heads source.
|
||||
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>>,
|
||||
}
|
||||
|
||||
impl<P: SubstrateParachainsPipeline> ParachainsTarget<P> {
|
||||
/// Creates new parachains target client.
|
||||
pub fn new(
|
||||
client: Client<P::TargetChain>,
|
||||
source_client: Client<P::SourceRelayChain>,
|
||||
target_client: Client<P::TargetChain>,
|
||||
transaction_params: TransactionParams<AccountKeyPairOf<P::TargetChain>>,
|
||||
) -> Self {
|
||||
ParachainsTarget { client, transaction_params }
|
||||
ParachainsTarget { source_client, target_client, transaction_params }
|
||||
}
|
||||
|
||||
/// Returns reference to the underlying RPC client.
|
||||
pub fn client(&self) -> &Client<P::TargetChain> {
|
||||
&self.client
|
||||
pub fn target_client(&self) -> &Client<P::TargetChain> {
|
||||
&self.target_client
|
||||
}
|
||||
}
|
||||
|
||||
impl<P: SubstrateParachainsPipeline> Clone for ParachainsTarget<P> {
|
||||
fn clone(&self) -> Self {
|
||||
ParachainsTarget {
|
||||
client: self.client.clone(),
|
||||
source_client: self.source_client.clone(),
|
||||
target_client: self.target_client.clone(),
|
||||
transaction_params: self.transaction_params.clone(),
|
||||
}
|
||||
}
|
||||
@@ -70,7 +81,9 @@ impl<P: SubstrateParachainsPipeline> RelayClient for ParachainsTarget<P> {
|
||||
type Error = 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>
|
||||
where
|
||||
P: SubstrateParachainsPipeline,
|
||||
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>>;
|
||||
|
||||
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();
|
||||
|
||||
Ok(best_id)
|
||||
@@ -93,7 +108,7 @@ where
|
||||
&self,
|
||||
at_block: &HeaderIdOf<P::TargetChain>,
|
||||
) -> Result<HeaderIdOf<P::SourceRelayChain>, Self::Error> {
|
||||
self.client
|
||||
self.target_client
|
||||
.typed_state_call::<_, Option<HeaderIdOf<P::SourceRelayChain>>>(
|
||||
P::SourceRelayChain::BEST_FINALIZED_HEADER_ID_METHOD.into(),
|
||||
(),
|
||||
@@ -104,23 +119,57 @@ where
|
||||
.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(
|
||||
&self,
|
||||
at_block: HeaderIdOf<P::TargetChain>,
|
||||
) -> Result<Option<HeaderIdOf<P::SourceParachain>>, Self::Error> {
|
||||
let encoded_best_finalized_source_para_block = self
|
||||
.client
|
||||
.state_call(
|
||||
P::SourceParachain::BEST_FINALIZED_HEADER_ID_METHOD.into(),
|
||||
Bytes(Vec::new()),
|
||||
Some(at_block.1),
|
||||
)
|
||||
.await?;
|
||||
) -> Result<
|
||||
Option<(HeaderIdOf<P::SourceRelayChain>, HeaderIdOf<P::SourceParachain>)>,
|
||||
Self::Error,
|
||||
> {
|
||||
// read best parachain head from the target bridge-parachains pallet
|
||||
let storage_key = ParasInfoKeyProvider::final_key(
|
||||
P::SourceRelayChain::WITH_CHAIN_BRIDGE_PARACHAINS_PALLET_NAME,
|
||||
&P::SourceParachain::PARACHAIN_ID.into(),
|
||||
);
|
||||
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(
|
||||
&mut &encoded_best_finalized_source_para_block.0[..],
|
||||
)
|
||||
.map_err(SubstrateError::ResponseParseFailed)?)
|
||||
// now we need to get full header ids. For source relay chain it is simple, because we
|
||||
// are connected
|
||||
let relay_header_id = self
|
||||
.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(),
|
||||
¶_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(
|
||||
@@ -128,14 +177,16 @@ where
|
||||
at_relay_block: HeaderIdOf<P::SourceRelayChain>,
|
||||
updated_head_hash: ParaHash,
|
||||
proof: ParaHeadsProof,
|
||||
is_free_execution_expected: bool,
|
||||
) -> Result<Self::TransactionTracker, Self::Error> {
|
||||
let transaction_params = self.transaction_params.clone();
|
||||
let call = P::SubmitParachainHeadsCallBuilder::build_submit_parachain_heads_call(
|
||||
at_relay_block,
|
||||
vec![(ParaId(P::SourceParachain::PARACHAIN_ID), updated_head_hash)],
|
||||
proof,
|
||||
is_free_execution_expected,
|
||||
);
|
||||
self.client
|
||||
self.target_client
|
||||
.submit_and_watch_signed_extrinsic(
|
||||
&transaction_params.signer,
|
||||
move |best_block_id, transaction_nonce| {
|
||||
|
||||
Reference in New Issue
Block a user