Refactor finality relay helpers (#1220)

* refactor finality relay helper definitions

* add missing doc

* removed commented code

* fmt

* disable rustfmt for macro

* move best_finalized method const to relay chain def
This commit is contained in:
Svyatoslav Nikolsky
2021-12-03 14:43:33 +03:00
committed by Bastian Köcher
parent f84590817b
commit e675b13042
37 changed files with 475 additions and 823 deletions
-8
View File
@@ -731,10 +731,6 @@ impl_runtime_apis! {
let header = BridgeRialtoGrandpa::best_finalized(); let header = BridgeRialtoGrandpa::best_finalized();
(header.number, header.hash()) (header.number, header.hash())
} }
fn is_known_header(hash: bp_rialto::Hash) -> bool {
BridgeRialtoGrandpa::is_known_header(hash)
}
} }
impl bp_westend::WestendFinalityApi<Block> for Runtime { impl bp_westend::WestendFinalityApi<Block> for Runtime {
@@ -742,10 +738,6 @@ impl_runtime_apis! {
let header = BridgeWestendGrandpa::best_finalized(); let header = BridgeWestendGrandpa::best_finalized();
(header.number, header.hash()) (header.number, header.hash())
} }
fn is_known_header(hash: bp_westend::Hash) -> bool {
BridgeWestendGrandpa::is_known_header(hash)
}
} }
impl bp_rialto::ToRialtoOutboundLaneApi<Block, Balance, ToRialtoMessagePayload> for Runtime { impl bp_rialto::ToRialtoOutboundLaneApi<Block, Balance, ToRialtoMessagePayload> for Runtime {
-4
View File
@@ -662,10 +662,6 @@ impl_runtime_apis! {
let header = BridgeMillauGrandpa::best_finalized(); let header = BridgeMillauGrandpa::best_finalized();
(header.number, header.hash()) (header.number, header.hash())
} }
fn is_known_header(hash: bp_millau::Hash) -> bool {
BridgeMillauGrandpa::is_known_header(hash)
}
} }
impl sp_transaction_pool::runtime_api::TaggedTransactionQueue<Block> for Runtime { impl sp_transaction_pool::runtime_api::TaggedTransactionQueue<Block> for Runtime {
@@ -90,8 +90,6 @@ pub const POLKADOT_TO_KUSAMA_CONVERSION_RATE_PARAMETER_NAME: &str =
/// Name of the `KusamaFinalityApi::best_finalized` runtime method. /// Name of the `KusamaFinalityApi::best_finalized` runtime method.
pub const BEST_FINALIZED_KUSAMA_HEADER_METHOD: &str = "KusamaFinalityApi_best_finalized"; pub const BEST_FINALIZED_KUSAMA_HEADER_METHOD: &str = "KusamaFinalityApi_best_finalized";
/// Name of the `KusamaFinalityApi::is_known_header` runtime method.
pub const IS_KNOWN_KUSAMA_HEADER_METHOD: &str = "KusamaFinalityApi_is_known_header";
/// Name of the `ToKusamaOutboundLaneApi::estimate_message_delivery_and_dispatch_fee` runtime /// Name of the `ToKusamaOutboundLaneApi::estimate_message_delivery_and_dispatch_fee` runtime
/// method. /// method.
@@ -124,8 +122,6 @@ sp_api::decl_runtime_apis! {
pub trait KusamaFinalityApi { pub trait KusamaFinalityApi {
/// Returns number and hash of the best finalized header known to the bridge module. /// Returns number and hash of the best finalized header known to the bridge module.
fn best_finalized() -> (BlockNumber, Hash); fn best_finalized() -> (BlockNumber, Hash);
/// Returns true if the header is known to the runtime.
fn is_known_header(hash: Hash) -> bool;
} }
/// Outbound message lane API for messages that are sent to Kusama chain. /// Outbound message lane API for messages that are sent to Kusama chain.
@@ -298,8 +298,6 @@ sp_api::decl_runtime_apis! {
pub trait MillauFinalityApi { pub trait MillauFinalityApi {
/// Returns number and hash of the best finalized header known to the bridge module. /// Returns number and hash of the best finalized header known to the bridge module.
fn best_finalized() -> (BlockNumber, Hash); fn best_finalized() -> (BlockNumber, Hash);
/// Returns true if the header is known to the runtime.
fn is_known_header(hash: Hash) -> bool;
} }
/// Outbound message lane API for messages that are sent to Millau chain. /// Outbound message lane API for messages that are sent to Millau chain.
@@ -90,8 +90,6 @@ pub const KUSAMA_TO_POLKADOT_CONVERSION_RATE_PARAMETER_NAME: &str =
/// Name of the `PolkadotFinalityApi::best_finalized` runtime method. /// Name of the `PolkadotFinalityApi::best_finalized` runtime method.
pub const BEST_FINALIZED_POLKADOT_HEADER_METHOD: &str = "PolkadotFinalityApi_best_finalized"; pub const BEST_FINALIZED_POLKADOT_HEADER_METHOD: &str = "PolkadotFinalityApi_best_finalized";
/// Name of the `PolkadotFinalityApi::is_known_header` runtime method.
pub const IS_KNOWN_POLKADOT_HEADER_METHOD: &str = "PolkadotFinalityApi_is_known_header";
/// Name of the `ToPolkadotOutboundLaneApi::estimate_message_delivery_and_dispatch_fee` runtime /// Name of the `ToPolkadotOutboundLaneApi::estimate_message_delivery_and_dispatch_fee` runtime
/// method. /// method.
@@ -124,8 +122,6 @@ sp_api::decl_runtime_apis! {
pub trait PolkadotFinalityApi { pub trait PolkadotFinalityApi {
/// Returns number and hash of the best finalized header known to the bridge module. /// Returns number and hash of the best finalized header known to the bridge module.
fn best_finalized() -> (BlockNumber, Hash); fn best_finalized() -> (BlockNumber, Hash);
/// Returns true if the header is known to the runtime.
fn is_known_header(hash: Hash) -> bool;
} }
/// Outbound message lane API for messages that are sent to Polkadot chain. /// Outbound message lane API for messages that are sent to Polkadot chain.
@@ -271,8 +271,6 @@ sp_api::decl_runtime_apis! {
pub trait RialtoFinalityApi { pub trait RialtoFinalityApi {
/// Returns number and hash of the best finalized header known to the bridge module. /// Returns number and hash of the best finalized header known to the bridge module.
fn best_finalized() -> (BlockNumber, Hash); fn best_finalized() -> (BlockNumber, Hash);
/// Returns true if the header is known to the runtime.
fn is_known_header(hash: Hash) -> bool;
} }
/// Outbound message lane API for messages that are sent to Rialto chain. /// Outbound message lane API for messages that are sent to Rialto chain.
@@ -79,8 +79,6 @@ pub const WITH_WOCOCO_MESSAGES_PALLET_NAME: &str = "BridgeWococoMessages";
/// Name of the `RococoFinalityApi::best_finalized` runtime method. /// Name of the `RococoFinalityApi::best_finalized` runtime method.
pub const BEST_FINALIZED_ROCOCO_HEADER_METHOD: &str = "RococoFinalityApi_best_finalized"; pub const BEST_FINALIZED_ROCOCO_HEADER_METHOD: &str = "RococoFinalityApi_best_finalized";
/// Name of the `RococoFinalityApi::is_known_header` runtime method.
pub const IS_KNOWN_ROCOCO_HEADER_METHOD: &str = "RococoFinalityApi_is_known_header";
/// Name of the `ToRococoOutboundLaneApi::estimate_message_delivery_and_dispatch_fee` runtime /// Name of the `ToRococoOutboundLaneApi::estimate_message_delivery_and_dispatch_fee` runtime
/// method. /// method.
@@ -125,8 +123,6 @@ sp_api::decl_runtime_apis! {
pub trait RococoFinalityApi { pub trait RococoFinalityApi {
/// Returns number and hash of the best finalized header known to the bridge module. /// Returns number and hash of the best finalized header known to the bridge module.
fn best_finalized() -> (BlockNumber, Hash); fn best_finalized() -> (BlockNumber, Hash);
/// Returns true if the header is known to the runtime.
fn is_known_header(hash: Hash) -> bool;
} }
/// Outbound message lane API for messages that are sent to Rococo chain. /// Outbound message lane API for messages that are sent to Rococo chain.
@@ -90,8 +90,6 @@ pub fn derive_account_from_rococo_id(id: bp_runtime::SourceAccount<AccountId>) -
/// Name of the `WestendFinalityApi::best_finalized` runtime method. /// Name of the `WestendFinalityApi::best_finalized` runtime method.
pub const BEST_FINALIZED_WESTEND_HEADER_METHOD: &str = "WestendFinalityApi_best_finalized"; pub const BEST_FINALIZED_WESTEND_HEADER_METHOD: &str = "WestendFinalityApi_best_finalized";
/// Name of the `WestendFinalityApi::is_known_header` runtime method.
pub const IS_KNOWN_WESTEND_HEADER_METHOD: &str = "WestendFinalityApi_is_known_header";
/// Name of the `ToWestendOutboundLaneApi::estimate_message_delivery_and_dispatch_fee` runtime /// Name of the `ToWestendOutboundLaneApi::estimate_message_delivery_and_dispatch_fee` runtime
/// method. /// method.
@@ -131,8 +129,6 @@ sp_api::decl_runtime_apis! {
pub trait WestendFinalityApi { pub trait WestendFinalityApi {
/// Returns number and hash of the best finalized header known to the bridge module. /// Returns number and hash of the best finalized header known to the bridge module.
fn best_finalized() -> (BlockNumber, Hash); fn best_finalized() -> (BlockNumber, Hash);
/// Returns true if the header is known to the runtime.
fn is_known_header(hash: Hash) -> bool;
} }
/// Outbound message lane API for messages that are sent to Westend chain. /// Outbound message lane API for messages that are sent to Westend chain.
@@ -44,8 +44,6 @@ pub const WITH_ROCOCO_MESSAGES_PALLET_NAME: &str = "BridgeRococoMessages";
/// Name of the `WococoFinalityApi::best_finalized` runtime method. /// Name of the `WococoFinalityApi::best_finalized` runtime method.
pub const BEST_FINALIZED_WOCOCO_HEADER_METHOD: &str = "WococoFinalityApi_best_finalized"; pub const BEST_FINALIZED_WOCOCO_HEADER_METHOD: &str = "WococoFinalityApi_best_finalized";
/// Name of the `WococoFinalityApi::is_known_header` runtime method.
pub const IS_KNOWN_WOCOCO_HEADER_METHOD: &str = "WococoFinalityApi_is_known_header";
/// Name of the `ToWococoOutboundLaneApi::estimate_message_delivery_and_dispatch_fee` runtime /// Name of the `ToWococoOutboundLaneApi::estimate_message_delivery_and_dispatch_fee` runtime
/// method. /// method.
@@ -78,8 +76,6 @@ sp_api::decl_runtime_apis! {
pub trait WococoFinalityApi { pub trait WococoFinalityApi {
/// Returns number and hash of the best finalized header known to the bridge module. /// Returns number and hash of the best finalized header known to the bridge module.
fn best_finalized() -> (BlockNumber, Hash); fn best_finalized() -> (BlockNumber, Hash);
/// Returns true if the header is known to the runtime.
fn is_known_header(hash: Hash) -> bool;
} }
/// Outbound message lane API for messages that are sent to Wococo chain. /// Outbound message lane API for messages that are sent to Wococo chain.
+2 -1
View File
@@ -15,7 +15,7 @@
// along with Parity Bridges Common. If not, see <http://www.gnu.org/licenses/>. // along with Parity Bridges Common. If not, see <http://www.gnu.org/licenses/>.
use frame_support::Parameter; use frame_support::Parameter;
use num_traits::{AsPrimitive, Bounded, CheckedSub, SaturatingAdd, Zero}; use num_traits::{AsPrimitive, Bounded, CheckedSub, Saturating, SaturatingAdd, Zero};
use sp_runtime::{ use sp_runtime::{
traits::{ traits::{
AtLeast32Bit, AtLeast32BitUnsigned, Hash as HashT, Header as HeaderT, MaybeDisplay, AtLeast32Bit, AtLeast32BitUnsigned, Hash as HashT, Header as HeaderT, MaybeDisplay,
@@ -46,6 +46,7 @@ pub trait Chain: Send + Sync + 'static {
+ MaybeMallocSizeOf + MaybeMallocSizeOf
+ AsPrimitive<usize> + AsPrimitive<usize>
+ Default + Default
+ Saturating
// original `sp_runtime::traits::Header::BlockNumber` doesn't have this trait, but // original `sp_runtime::traits::Header::BlockNumber` doesn't have this trait, but
// `sp_runtime::generic::Era` requires block number -> `u64` conversion. // `sp_runtime::generic::Era` requires block number -> `u64` conversion.
+ Into<u64>; + Into<u64>;
@@ -16,17 +16,8 @@
//! Kusama-to-Polkadot headers sync entrypoint. //! Kusama-to-Polkadot headers sync entrypoint.
use codec::Encode; use sp_core::Pair;
use sp_core::{Bytes, Pair}; use substrate_relay_helper::finality_pipeline::{SubstrateFinalitySyncPipeline, TransactionParams};
use bp_header_chain::justification::GrandpaJustification;
use relay_kusama_client::{Kusama, SyncHeader as KusamaSyncHeader};
use relay_polkadot_client::{Polkadot, SigningParams as PolkadotSigningParams};
use relay_substrate_client::{Client, TransactionSignScheme, UnsignedTransaction};
use relay_utils::metrics::MetricsParams;
use substrate_relay_helper::finality_pipeline::{
SubstrateFinalitySyncPipeline, SubstrateFinalityToSubstrate,
};
/// Maximal saturating difference between `balance(now)` and `balance(now-24h)` to treat /// Maximal saturating difference between `balance(now)` and `balance(now-24h)` to treat
/// relay as gone wild. /// relay as gone wild.
@@ -35,77 +26,37 @@ use substrate_relay_helper::finality_pipeline::{
/// DOT, but let's round up to 30 DOT here. /// DOT, but let's round up to 30 DOT here.
pub(crate) const MAXIMAL_BALANCE_DECREASE_PER_DAY: bp_polkadot::Balance = 30_000_000_000; pub(crate) const MAXIMAL_BALANCE_DECREASE_PER_DAY: bp_polkadot::Balance = 30_000_000_000;
/// Kusama-to-Polkadot finality sync pipeline. /// Description of Kusama -> Polkadot finalized headers bridge.
pub(crate) type FinalityPipelineKusamaFinalityToPolkadot =
SubstrateFinalityToSubstrate<Kusama, Polkadot, PolkadotSigningParams>;
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub(crate) struct KusamaFinalityToPolkadot { pub struct KusamaFinalityToPolkadot;
finality_pipeline: FinalityPipelineKusamaFinalityToPolkadot, substrate_relay_helper::generate_mocked_submit_finality_proof_call_builder!(
} KusamaFinalityToPolkadot,
KusamaFinalityToPolkadotCallBuilder,
impl KusamaFinalityToPolkadot { relay_polkadot_client::runtime::Call::BridgeKusamaGrandpa,
pub fn new(target_client: Client<Polkadot>, target_sign: PolkadotSigningParams) -> Self { relay_polkadot_client::runtime::BridgeKusamaGrandpaCall::submit_finality_proof
Self { );
finality_pipeline: FinalityPipelineKusamaFinalityToPolkadot::new(
target_client,
target_sign,
),
}
}
}
impl SubstrateFinalitySyncPipeline for KusamaFinalityToPolkadot { impl SubstrateFinalitySyncPipeline for KusamaFinalityToPolkadot {
type FinalitySyncPipeline = FinalityPipelineKusamaFinalityToPolkadot; type SourceChain = relay_kusama_client::Kusama;
type TargetChain = relay_polkadot_client::Polkadot;
const BEST_FINALIZED_SOURCE_HEADER_ID_AT_TARGET: &'static str = type SubmitFinalityProofCallBuilder = KusamaFinalityToPolkadotCallBuilder;
bp_kusama::BEST_FINALIZED_KUSAMA_HEADER_METHOD; type TransactionSignScheme = relay_polkadot_client::Polkadot;
type TargetChain = Polkadot; fn start_relay_guards(
target_client: &relay_substrate_client::Client<relay_polkadot_client::Polkadot>,
fn customize_metrics(params: MetricsParams) -> anyhow::Result<MetricsParams> { transaction_params: &TransactionParams<sp_core::sr25519::Pair>,
crate::chains::add_polkadot_kusama_price_metrics::<Self::FinalitySyncPipeline>(params) ) {
}
fn start_relay_guards(&self) {
relay_substrate_client::guard::abort_on_spec_version_change( relay_substrate_client::guard::abort_on_spec_version_change(
self.finality_pipeline.target_client.clone(), target_client.clone(),
bp_polkadot::VERSION.spec_version, bp_polkadot::VERSION.spec_version,
); );
relay_substrate_client::guard::abort_when_account_balance_decreased( relay_substrate_client::guard::abort_when_account_balance_decreased(
self.finality_pipeline.target_client.clone(), target_client.clone(),
self.transactions_author(), transaction_params.transactions_signer.public().into(),
MAXIMAL_BALANCE_DECREASE_PER_DAY, MAXIMAL_BALANCE_DECREASE_PER_DAY,
); );
} }
fn transactions_author(&self) -> bp_polkadot::AccountId {
(*self.finality_pipeline.target_sign.public().as_array_ref()).into()
}
fn make_submit_finality_proof_transaction(
&self,
era: bp_runtime::TransactionEraOf<Polkadot>,
transaction_nonce: bp_runtime::IndexOf<Polkadot>,
header: KusamaSyncHeader,
proof: GrandpaJustification<bp_kusama::Header>,
) -> Bytes {
let call = relay_polkadot_client::runtime::Call::BridgeKusamaGrandpa(
relay_polkadot_client::runtime::BridgeKusamaGrandpaCall::submit_finality_proof(
Box::new(header.into_inner()),
proof,
),
);
let genesis_hash = *self.finality_pipeline.target_client.genesis_hash();
let transaction = Polkadot::sign_transaction(
genesis_hash,
&self.finality_pipeline.target_sign,
era,
UnsignedTransaction::new(call, transaction_nonce),
);
Bytes(transaction.encode())
}
} }
#[cfg(test)] #[cfg(test)]
@@ -16,65 +16,22 @@
//! Millau-to-Rialto headers sync entrypoint. //! Millau-to-Rialto headers sync entrypoint.
use codec::Encode;
use sp_core::{Bytes, Pair};
use bp_header_chain::justification::GrandpaJustification;
use relay_millau_client::{Millau, SyncHeader as MillauSyncHeader};
use relay_rialto_client::{Rialto, SigningParams as RialtoSigningParams};
use relay_substrate_client::{Client, IndexOf, TransactionSignScheme, UnsignedTransaction};
use substrate_relay_helper::finality_pipeline::{ use substrate_relay_helper::finality_pipeline::{
SubstrateFinalitySyncPipeline, SubstrateFinalityToSubstrate, DirectSubmitFinalityProofCallBuilder, SubstrateFinalitySyncPipeline,
}; };
/// Millau-to-Rialto finality sync pipeline. /// Description of Millau -> Rialto finalized headers bridge.
pub(crate) type FinalityPipelineMillauToRialto =
SubstrateFinalityToSubstrate<Millau, Rialto, RialtoSigningParams>;
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub(crate) struct MillauFinalityToRialto { pub struct MillauFinalityToRialto;
finality_pipeline: FinalityPipelineMillauToRialto,
}
impl MillauFinalityToRialto {
pub fn new(target_client: Client<Rialto>, target_sign: RialtoSigningParams) -> Self {
Self { finality_pipeline: FinalityPipelineMillauToRialto::new(target_client, target_sign) }
}
}
impl SubstrateFinalitySyncPipeline for MillauFinalityToRialto { impl SubstrateFinalitySyncPipeline for MillauFinalityToRialto {
type FinalitySyncPipeline = FinalityPipelineMillauToRialto; type SourceChain = relay_millau_client::Millau;
type TargetChain = relay_rialto_client::Rialto;
const BEST_FINALIZED_SOURCE_HEADER_ID_AT_TARGET: &'static str = type SubmitFinalityProofCallBuilder = DirectSubmitFinalityProofCallBuilder<
bp_millau::BEST_FINALIZED_MILLAU_HEADER_METHOD; Self,
rialto_runtime::Runtime,
type TargetChain = Rialto; rialto_runtime::MillauGrandpaInstance,
>;
fn transactions_author(&self) -> bp_rialto::AccountId { type TransactionSignScheme = relay_rialto_client::Rialto;
(*self.finality_pipeline.target_sign.public().as_array_ref()).into()
}
fn make_submit_finality_proof_transaction(
&self,
era: bp_runtime::TransactionEraOf<Rialto>,
transaction_nonce: IndexOf<Rialto>,
header: MillauSyncHeader,
proof: GrandpaJustification<bp_millau::Header>,
) -> Bytes {
let call = rialto_runtime::BridgeGrandpaMillauCall::submit_finality_proof {
finality_target: Box::new(header.into_inner()),
justification: proof,
}
.into();
let genesis_hash = *self.finality_pipeline.target_client.genesis_hash();
let transaction = Rialto::sign_transaction(
genesis_hash,
&self.finality_pipeline.target_sign,
era,
UnsignedTransaction::new(call, transaction_nonce),
);
Bytes(transaction.encode())
}
} }
@@ -39,18 +39,6 @@ mod rococo;
mod westend; mod westend;
mod wococo; mod wococo;
use relay_utils::metrics::{MetricsParams, StandaloneMetric};
pub(crate) fn add_polkadot_kusama_price_metrics<T: finality_relay::FinalitySyncPipeline>(
params: MetricsParams,
) -> anyhow::Result<MetricsParams> {
substrate_relay_helper::helpers::token_price_metric(polkadot::TOKEN_ID)?
.register_and_spawn(&params.registry)?;
substrate_relay_helper::helpers::token_price_metric(kusama::TOKEN_ID)?
.register_and_spawn(&params.registry)?;
Ok(params)
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::cli::{encode_call, send_message}; use crate::cli::{encode_call, send_message};
@@ -16,17 +16,8 @@
//! Polkadot-to-Kusama headers sync entrypoint. //! Polkadot-to-Kusama headers sync entrypoint.
use codec::Encode; use sp_core::Pair;
use sp_core::{Bytes, Pair}; use substrate_relay_helper::finality_pipeline::{SubstrateFinalitySyncPipeline, TransactionParams};
use bp_header_chain::justification::GrandpaJustification;
use relay_kusama_client::{Kusama, SigningParams as KusamaSigningParams};
use relay_polkadot_client::{Polkadot, SyncHeader as PolkadotSyncHeader};
use relay_substrate_client::{Client, TransactionSignScheme, UnsignedTransaction};
use relay_utils::metrics::MetricsParams;
use substrate_relay_helper::finality_pipeline::{
SubstrateFinalitySyncPipeline, SubstrateFinalityToSubstrate,
};
/// Maximal saturating difference between `balance(now)` and `balance(now-24h)` to treat /// Maximal saturating difference between `balance(now)` and `balance(now-24h)` to treat
/// relay as gone wild. /// relay as gone wild.
@@ -35,77 +26,37 @@ use substrate_relay_helper::finality_pipeline::{
/// KSM, but let's round up to 0.1 KSM here. /// KSM, but let's round up to 0.1 KSM here.
pub(crate) const MAXIMAL_BALANCE_DECREASE_PER_DAY: bp_polkadot::Balance = 100_000_000_000; pub(crate) const MAXIMAL_BALANCE_DECREASE_PER_DAY: bp_polkadot::Balance = 100_000_000_000;
/// Polkadot-to-Kusama finality sync pipeline. /// Description of Polkadot -> Kusama finalized headers bridge.
pub(crate) type FinalityPipelinePolkadotFinalityToKusama =
SubstrateFinalityToSubstrate<Polkadot, Kusama, KusamaSigningParams>;
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub(crate) struct PolkadotFinalityToKusama { pub struct PolkadotFinalityToKusama;
finality_pipeline: FinalityPipelinePolkadotFinalityToKusama, substrate_relay_helper::generate_mocked_submit_finality_proof_call_builder!(
} PolkadotFinalityToKusama,
PolkadotFinalityToKusamaCallBuilder,
impl PolkadotFinalityToKusama { relay_kusama_client::runtime::Call::BridgePolkadotGrandpa,
pub fn new(target_client: Client<Kusama>, target_sign: KusamaSigningParams) -> Self { relay_kusama_client::runtime::BridgePolkadotGrandpaCall::submit_finality_proof
Self { );
finality_pipeline: FinalityPipelinePolkadotFinalityToKusama::new(
target_client,
target_sign,
),
}
}
}
impl SubstrateFinalitySyncPipeline for PolkadotFinalityToKusama { impl SubstrateFinalitySyncPipeline for PolkadotFinalityToKusama {
type FinalitySyncPipeline = FinalityPipelinePolkadotFinalityToKusama; type SourceChain = relay_polkadot_client::Polkadot;
type TargetChain = relay_kusama_client::Kusama;
const BEST_FINALIZED_SOURCE_HEADER_ID_AT_TARGET: &'static str = type SubmitFinalityProofCallBuilder = PolkadotFinalityToKusamaCallBuilder;
bp_polkadot::BEST_FINALIZED_POLKADOT_HEADER_METHOD; type TransactionSignScheme = relay_kusama_client::Kusama;
type TargetChain = Kusama; fn start_relay_guards(
target_client: &relay_substrate_client::Client<relay_kusama_client::Kusama>,
fn customize_metrics(params: MetricsParams) -> anyhow::Result<MetricsParams> { transaction_params: &TransactionParams<sp_core::sr25519::Pair>,
crate::chains::add_polkadot_kusama_price_metrics::<Self::FinalitySyncPipeline>(params) ) {
}
fn start_relay_guards(&self) {
relay_substrate_client::guard::abort_on_spec_version_change( relay_substrate_client::guard::abort_on_spec_version_change(
self.finality_pipeline.target_client.clone(), target_client.clone(),
bp_kusama::VERSION.spec_version, bp_kusama::VERSION.spec_version,
); );
relay_substrate_client::guard::abort_when_account_balance_decreased( relay_substrate_client::guard::abort_when_account_balance_decreased(
self.finality_pipeline.target_client.clone(), target_client.clone(),
self.transactions_author(), transaction_params.transactions_signer.public().into(),
MAXIMAL_BALANCE_DECREASE_PER_DAY, MAXIMAL_BALANCE_DECREASE_PER_DAY,
); );
} }
fn transactions_author(&self) -> bp_kusama::AccountId {
(*self.finality_pipeline.target_sign.public().as_array_ref()).into()
}
fn make_submit_finality_proof_transaction(
&self,
era: bp_runtime::TransactionEraOf<Kusama>,
transaction_nonce: bp_runtime::IndexOf<Kusama>,
header: PolkadotSyncHeader,
proof: GrandpaJustification<bp_polkadot::Header>,
) -> Bytes {
let call = relay_kusama_client::runtime::Call::BridgePolkadotGrandpa(
relay_kusama_client::runtime::BridgePolkadotGrandpaCall::submit_finality_proof(
Box::new(header.into_inner()),
proof,
),
);
let genesis_hash = *self.finality_pipeline.target_client.genesis_hash();
let transaction = Kusama::sign_transaction(
genesis_hash,
&self.finality_pipeline.target_sign,
era,
UnsignedTransaction::new(call, transaction_nonce),
);
Bytes(transaction.encode())
}
} }
#[cfg(test)] #[cfg(test)]
@@ -16,73 +16,22 @@
//! Rialto-to-Millau headers sync entrypoint. //! Rialto-to-Millau headers sync entrypoint.
use codec::Encode;
use sp_core::{Bytes, Pair};
use bp_header_chain::justification::GrandpaJustification;
use relay_millau_client::{Millau, SigningParams as MillauSigningParams};
use relay_rialto_client::{Rialto, SyncHeader as RialtoSyncHeader};
use relay_substrate_client::{Client, IndexOf, TransactionSignScheme, UnsignedTransaction};
use substrate_relay_helper::finality_pipeline::{ use substrate_relay_helper::finality_pipeline::{
SubstrateFinalitySyncPipeline, SubstrateFinalityToSubstrate, DirectSubmitFinalityProofCallBuilder, SubstrateFinalitySyncPipeline,
}; };
/// Rialto-to-Millau finality sync pipeline. /// Description of Millau -> Rialto finalized headers bridge.
pub(crate) type FinalityPipelineRialtoFinalityToMillau =
SubstrateFinalityToSubstrate<Rialto, Millau, MillauSigningParams>;
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct RialtoFinalityToMillau { pub struct RialtoFinalityToMillau;
finality_pipeline: FinalityPipelineRialtoFinalityToMillau,
}
impl RialtoFinalityToMillau {
pub fn new(target_client: Client<Millau>, target_sign: MillauSigningParams) -> Self {
Self {
finality_pipeline: FinalityPipelineRialtoFinalityToMillau::new(
target_client,
target_sign,
),
}
}
}
impl SubstrateFinalitySyncPipeline for RialtoFinalityToMillau { impl SubstrateFinalitySyncPipeline for RialtoFinalityToMillau {
type FinalitySyncPipeline = FinalityPipelineRialtoFinalityToMillau; type SourceChain = relay_rialto_client::Rialto;
type TargetChain = relay_millau_client::Millau;
const BEST_FINALIZED_SOURCE_HEADER_ID_AT_TARGET: &'static str = type SubmitFinalityProofCallBuilder = DirectSubmitFinalityProofCallBuilder<
bp_rialto::BEST_FINALIZED_RIALTO_HEADER_METHOD; Self,
type TargetChain = Millau;
fn transactions_author(&self) -> bp_millau::AccountId {
(*self.finality_pipeline.target_sign.public().as_array_ref()).into()
}
fn make_submit_finality_proof_transaction(
&self,
era: bp_runtime::TransactionEraOf<Millau>,
transaction_nonce: IndexOf<Millau>,
header: RialtoSyncHeader,
proof: GrandpaJustification<bp_rialto::Header>,
) -> Bytes {
let call = millau_runtime::BridgeGrandpaCall::<
millau_runtime::Runtime, millau_runtime::Runtime,
millau_runtime::RialtoGrandpaInstance, millau_runtime::RialtoGrandpaInstance,
>::submit_finality_proof { >;
finality_target: Box::new(header.into_inner()), type TransactionSignScheme = relay_millau_client::Millau;
justification: proof,
}
.into();
let genesis_hash = *self.finality_pipeline.target_client.genesis_hash();
let transaction = Millau::sign_transaction(
genesis_hash,
&self.finality_pipeline.target_sign,
era,
UnsignedTransaction::new(call, transaction_nonce),
);
Bytes(transaction.encode())
}
} }
@@ -16,89 +16,40 @@
//! Rococo-to-Wococo headers sync entrypoint. //! Rococo-to-Wococo headers sync entrypoint.
use codec::Encode;
use sp_core::{Bytes, Pair};
use bp_header_chain::justification::GrandpaJustification;
use relay_rococo_client::{Rococo, SyncHeader as RococoSyncHeader};
use relay_substrate_client::{Client, IndexOf, TransactionSignScheme, UnsignedTransaction};
use relay_utils::metrics::MetricsParams;
use relay_wococo_client::{SigningParams as WococoSigningParams, Wococo};
use substrate_relay_helper::finality_pipeline::{
SubstrateFinalitySyncPipeline, SubstrateFinalityToSubstrate,
};
use crate::chains::wococo_headers_to_rococo::MAXIMAL_BALANCE_DECREASE_PER_DAY; use crate::chains::wococo_headers_to_rococo::MAXIMAL_BALANCE_DECREASE_PER_DAY;
/// Rococo-to-Wococo finality sync pipeline. use sp_core::Pair;
pub(crate) type FinalityPipelineRococoFinalityToWococo = use substrate_relay_helper::finality_pipeline::{SubstrateFinalitySyncPipeline, TransactionParams};
SubstrateFinalityToSubstrate<Rococo, Wococo, WococoSigningParams>;
/// Description of Rococo -> Wococo finalized headers bridge.
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub(crate) struct RococoFinalityToWococo { pub struct RococoFinalityToWococo;
finality_pipeline: FinalityPipelineRococoFinalityToWococo, substrate_relay_helper::generate_mocked_submit_finality_proof_call_builder!(
} RococoFinalityToWococo,
RococoFinalityToWococoCallBuilder,
impl RococoFinalityToWococo { relay_wococo_client::runtime::Call::BridgeGrandpaRococo,
pub fn new(target_client: Client<Wococo>, target_sign: WococoSigningParams) -> Self { relay_wococo_client::runtime::BridgeGrandpaRococoCall::submit_finality_proof
Self { );
finality_pipeline: FinalityPipelineRococoFinalityToWococo::new(
target_client,
target_sign,
),
}
}
}
impl SubstrateFinalitySyncPipeline for RococoFinalityToWococo { impl SubstrateFinalitySyncPipeline for RococoFinalityToWococo {
type FinalitySyncPipeline = FinalityPipelineRococoFinalityToWococo; type SourceChain = relay_rococo_client::Rococo;
type TargetChain = relay_wococo_client::Wococo;
const BEST_FINALIZED_SOURCE_HEADER_ID_AT_TARGET: &'static str = type SubmitFinalityProofCallBuilder = RococoFinalityToWococoCallBuilder;
bp_rococo::BEST_FINALIZED_ROCOCO_HEADER_METHOD; type TransactionSignScheme = relay_wococo_client::Wococo;
type TargetChain = Wococo; fn start_relay_guards(
target_client: &relay_substrate_client::Client<relay_wococo_client::Wococo>,
fn customize_metrics(params: MetricsParams) -> anyhow::Result<MetricsParams> { transaction_params: &TransactionParams<sp_core::sr25519::Pair>,
crate::chains::add_polkadot_kusama_price_metrics::<Self::FinalitySyncPipeline>(params) ) {
}
fn start_relay_guards(&self) {
relay_substrate_client::guard::abort_on_spec_version_change( relay_substrate_client::guard::abort_on_spec_version_change(
self.finality_pipeline.target_client.clone(), target_client.clone(),
bp_wococo::VERSION.spec_version, bp_wococo::VERSION.spec_version,
); );
relay_substrate_client::guard::abort_when_account_balance_decreased( relay_substrate_client::guard::abort_when_account_balance_decreased(
self.finality_pipeline.target_client.clone(), target_client.clone(),
self.transactions_author(), transaction_params.transactions_signer.public().into(),
MAXIMAL_BALANCE_DECREASE_PER_DAY, MAXIMAL_BALANCE_DECREASE_PER_DAY,
); );
} }
fn transactions_author(&self) -> bp_wococo::AccountId {
(*self.finality_pipeline.target_sign.public().as_array_ref()).into()
}
fn make_submit_finality_proof_transaction(
&self,
era: bp_runtime::TransactionEraOf<Wococo>,
transaction_nonce: IndexOf<Wococo>,
header: RococoSyncHeader,
proof: GrandpaJustification<bp_rococo::Header>,
) -> Bytes {
let call = relay_wococo_client::runtime::Call::BridgeGrandpaRococo(
relay_wococo_client::runtime::BridgeGrandpaRococoCall::submit_finality_proof(
Box::new(header.into_inner()),
proof,
),
);
let genesis_hash = *self.finality_pipeline.target_client.genesis_hash();
let transaction = Wococo::sign_transaction(
genesis_hash,
&self.finality_pipeline.target_sign,
era,
UnsignedTransaction::new(call, transaction_nonce),
);
Bytes(transaction.encode())
}
} }
@@ -16,78 +16,22 @@
//! Westend-to-Millau headers sync entrypoint. //! Westend-to-Millau headers sync entrypoint.
use codec::Encode;
use sp_core::{Bytes, Pair};
use bp_header_chain::justification::GrandpaJustification;
use relay_millau_client::{Millau, SigningParams as MillauSigningParams};
use relay_substrate_client::{Client, IndexOf, TransactionSignScheme, UnsignedTransaction};
use relay_utils::metrics::MetricsParams;
use relay_westend_client::{SyncHeader as WestendSyncHeader, Westend};
use substrate_relay_helper::finality_pipeline::{ use substrate_relay_helper::finality_pipeline::{
SubstrateFinalitySyncPipeline, SubstrateFinalityToSubstrate, DirectSubmitFinalityProofCallBuilder, SubstrateFinalitySyncPipeline,
}; };
/// Westend-to-Millau finality sync pipeline. /// Description of Westend -> Millau finalized headers bridge.
pub(crate) type FinalityPipelineWestendFinalityToMillau =
SubstrateFinalityToSubstrate<Westend, Millau, MillauSigningParams>;
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub(crate) struct WestendFinalityToMillau { pub struct WestendFinalityToMillau;
finality_pipeline: FinalityPipelineWestendFinalityToMillau,
}
impl WestendFinalityToMillau {
pub fn new(target_client: Client<Millau>, target_sign: MillauSigningParams) -> Self {
Self {
finality_pipeline: FinalityPipelineWestendFinalityToMillau::new(
target_client,
target_sign,
),
}
}
}
impl SubstrateFinalitySyncPipeline for WestendFinalityToMillau { impl SubstrateFinalitySyncPipeline for WestendFinalityToMillau {
type FinalitySyncPipeline = FinalityPipelineWestendFinalityToMillau; type SourceChain = relay_westend_client::Westend;
type TargetChain = relay_millau_client::Millau;
const BEST_FINALIZED_SOURCE_HEADER_ID_AT_TARGET: &'static str = type SubmitFinalityProofCallBuilder = DirectSubmitFinalityProofCallBuilder<
bp_westend::BEST_FINALIZED_WESTEND_HEADER_METHOD; Self,
type TargetChain = Millau;
fn customize_metrics(params: MetricsParams) -> anyhow::Result<MetricsParams> {
crate::chains::add_polkadot_kusama_price_metrics::<Self::FinalitySyncPipeline>(params)
}
fn transactions_author(&self) -> bp_millau::AccountId {
(*self.finality_pipeline.target_sign.public().as_array_ref()).into()
}
fn make_submit_finality_proof_transaction(
&self,
era: bp_runtime::TransactionEraOf<Millau>,
transaction_nonce: IndexOf<Millau>,
header: WestendSyncHeader,
proof: GrandpaJustification<bp_westend::Header>,
) -> Bytes {
let call = millau_runtime::BridgeGrandpaCall::<
millau_runtime::Runtime, millau_runtime::Runtime,
millau_runtime::WestendGrandpaInstance, millau_runtime::WestendGrandpaInstance,
>::submit_finality_proof { >;
finality_target: Box::new(header.into_inner()), type TransactionSignScheme = relay_millau_client::Millau;
justification: proof,
}
.into();
let genesis_hash = *self.finality_pipeline.target_client.genesis_hash();
let transaction = Millau::sign_transaction(
genesis_hash,
&self.finality_pipeline.target_sign,
era,
UnsignedTransaction::new(call, transaction_nonce),
);
Bytes(transaction.encode())
}
} }
@@ -16,17 +16,8 @@
//! Wococo-to-Rococo headers sync entrypoint. //! Wococo-to-Rococo headers sync entrypoint.
use codec::Encode; use sp_core::Pair;
use sp_core::{Bytes, Pair}; use substrate_relay_helper::finality_pipeline::{SubstrateFinalitySyncPipeline, TransactionParams};
use bp_header_chain::justification::GrandpaJustification;
use relay_rococo_client::{Rococo, SigningParams as RococoSigningParams};
use relay_substrate_client::{Client, IndexOf, TransactionSignScheme, UnsignedTransaction};
use relay_utils::metrics::MetricsParams;
use relay_wococo_client::{SyncHeader as WococoSyncHeader, Wococo};
use substrate_relay_helper::finality_pipeline::{
SubstrateFinalitySyncPipeline, SubstrateFinalityToSubstrate,
};
/// Maximal saturating difference between `balance(now)` and `balance(now-24h)` to treat /// Maximal saturating difference between `balance(now)` and `balance(now-24h)` to treat
/// relay as gone wild. /// relay as gone wild.
@@ -35,77 +26,37 @@ use substrate_relay_helper::finality_pipeline::{
/// Note that this is in plancks, so this corresponds to `1500 UNITS`. /// Note that this is in plancks, so this corresponds to `1500 UNITS`.
pub(crate) const MAXIMAL_BALANCE_DECREASE_PER_DAY: bp_rococo::Balance = 1_500_000_000_000_000; pub(crate) const MAXIMAL_BALANCE_DECREASE_PER_DAY: bp_rococo::Balance = 1_500_000_000_000_000;
/// Wococo-to-Rococo finality sync pipeline. /// Description of Wococo -> Rococo finalized headers bridge.
pub(crate) type FinalityPipelineWococoFinalityToRococo =
SubstrateFinalityToSubstrate<Wococo, Rococo, RococoSigningParams>;
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub(crate) struct WococoFinalityToRococo { pub struct WococoFinalityToRococo;
finality_pipeline: FinalityPipelineWococoFinalityToRococo, substrate_relay_helper::generate_mocked_submit_finality_proof_call_builder!(
} WococoFinalityToRococo,
WococoFinalityToRococoCallBuilder,
impl WococoFinalityToRococo { relay_rococo_client::runtime::Call::BridgeGrandpaWococo,
pub fn new(target_client: Client<Rococo>, target_sign: RococoSigningParams) -> Self { relay_rococo_client::runtime::BridgeGrandpaWococoCall::submit_finality_proof
Self { );
finality_pipeline: FinalityPipelineWococoFinalityToRococo::new(
target_client,
target_sign,
),
}
}
}
impl SubstrateFinalitySyncPipeline for WococoFinalityToRococo { impl SubstrateFinalitySyncPipeline for WococoFinalityToRococo {
type FinalitySyncPipeline = FinalityPipelineWococoFinalityToRococo; type SourceChain = relay_wococo_client::Wococo;
type TargetChain = relay_rococo_client::Rococo;
const BEST_FINALIZED_SOURCE_HEADER_ID_AT_TARGET: &'static str = type SubmitFinalityProofCallBuilder = WococoFinalityToRococoCallBuilder;
bp_wococo::BEST_FINALIZED_WOCOCO_HEADER_METHOD; type TransactionSignScheme = relay_rococo_client::Rococo;
type TargetChain = Rococo; fn start_relay_guards(
target_client: &relay_substrate_client::Client<relay_rococo_client::Rococo>,
fn customize_metrics(params: MetricsParams) -> anyhow::Result<MetricsParams> { transaction_params: &TransactionParams<sp_core::sr25519::Pair>,
crate::chains::add_polkadot_kusama_price_metrics::<Self::FinalitySyncPipeline>(params) ) {
}
fn start_relay_guards(&self) {
relay_substrate_client::guard::abort_on_spec_version_change( relay_substrate_client::guard::abort_on_spec_version_change(
self.finality_pipeline.target_client.clone(), target_client.clone(),
bp_rococo::VERSION.spec_version, bp_rococo::VERSION.spec_version,
); );
relay_substrate_client::guard::abort_when_account_balance_decreased( relay_substrate_client::guard::abort_when_account_balance_decreased(
self.finality_pipeline.target_client.clone(), target_client.clone(),
self.transactions_author(), transaction_params.transactions_signer.public().into(),
MAXIMAL_BALANCE_DECREASE_PER_DAY, MAXIMAL_BALANCE_DECREASE_PER_DAY,
); );
} }
fn transactions_author(&self) -> bp_rococo::AccountId {
(*self.finality_pipeline.target_sign.public().as_array_ref()).into()
}
fn make_submit_finality_proof_transaction(
&self,
era: bp_runtime::TransactionEraOf<Rococo>,
transaction_nonce: IndexOf<Rococo>,
header: WococoSyncHeader,
proof: GrandpaJustification<bp_wococo::Header>,
) -> Bytes {
let call = relay_rococo_client::runtime::Call::BridgeGrandpaWococo(
relay_rococo_client::runtime::BridgeGrandpaWococoCall::submit_finality_proof(
Box::new(header.into_inner()),
proof,
),
);
let genesis_hash = *self.finality_pipeline.target_client.genesis_hash();
let transaction = Rococo::sign_transaction(
genesis_hash,
&self.finality_pipeline.target_sign,
era,
UnsignedTransaction::new(call, transaction_nonce),
);
Bytes(transaction.encode())
}
} }
#[cfg(test)] #[cfg(test)]
@@ -121,18 +121,22 @@ impl RelayHeaders {
let target_client = self.target.to_client::<Target>().await?; let target_client = self.target.to_client::<Target>().await?;
let target_transactions_mortality = self.target_sign.target_transactions_mortality; let target_transactions_mortality = self.target_sign.target_transactions_mortality;
let target_sign = self.target_sign.to_keypair::<Target>()?; let target_sign = self.target_sign.to_keypair::<Target>()?;
let metrics_params = Finality::customize_metrics(self.prometheus_params.into())?;
let metrics_params: relay_utils::metrics::MetricsParams = self.prometheus_params.into();
GlobalMetrics::new()?.register_and_spawn(&metrics_params.registry)?; GlobalMetrics::new()?.register_and_spawn(&metrics_params.registry)?;
let finality = Finality::new(target_client.clone(), target_sign); let target_transactions_params =
finality.start_relay_guards(); substrate_relay_helper::finality_pipeline::TransactionParams {
transactions_signer: target_sign,
transactions_mortality: target_transactions_mortality,
};
Finality::start_relay_guards(&target_client, &target_transactions_params);
substrate_relay_helper::finality_pipeline::run( substrate_relay_helper::finality_pipeline::run::<Finality>(
finality,
source_client, source_client,
target_client, target_client,
self.only_mandatory_headers, self.only_mandatory_headers,
target_transactions_mortality, target_transactions_params,
metrics_params, metrics_params,
) )
.await .await
@@ -489,25 +489,35 @@ impl RelayHeadersAndMessages {
} }
// start on-demand header relays // start on-demand header relays
let left_to_right_finality = let left_to_right_transaction_params =
LeftToRightFinality::new(right_client.clone(), right_sign.clone()); substrate_relay_helper::finality_pipeline::TransactionParams {
let right_to_left_finality = transactions_mortality: right_transactions_mortality,
RightToLeftFinality::new(left_client.clone(), left_sign.clone()); transactions_signer: right_sign.clone(),
left_to_right_finality.start_relay_guards(); };
right_to_left_finality.start_relay_guards(); let right_to_left_transaction_params =
let left_to_right_on_demand_headers = OnDemandHeadersRelay::new( substrate_relay_helper::finality_pipeline::TransactionParams {
transactions_mortality: left_transactions_mortality,
transactions_signer: left_sign.clone(),
};
LeftToRightFinality::start_relay_guards(
&right_client,
&left_to_right_transaction_params,
);
RightToLeftFinality::start_relay_guards(
&left_client,
&right_to_left_transaction_params,
);
let left_to_right_on_demand_headers = OnDemandHeadersRelay::new::<LeftToRightFinality>(
left_client.clone(), left_client.clone(),
right_client.clone(), right_client.clone(),
right_transactions_mortality, left_to_right_transaction_params,
left_to_right_finality,
MAX_MISSING_LEFT_HEADERS_AT_RIGHT, MAX_MISSING_LEFT_HEADERS_AT_RIGHT,
params.shared.only_mandatory_headers, params.shared.only_mandatory_headers,
); );
let right_to_left_on_demand_headers = OnDemandHeadersRelay::new( let right_to_left_on_demand_headers = OnDemandHeadersRelay::new::<RightToLeftFinality>(
right_client.clone(), right_client.clone(),
left_client.clone(), left_client.clone(),
left_transactions_mortality, right_to_left_transaction_params,
right_to_left_finality,
MAX_MISSING_RIGHT_HEADERS_AT_LEFT, MAX_MISSING_RIGHT_HEADERS_AT_LEFT,
params.shared.only_mandatory_headers, params.shared.only_mandatory_headers,
); );
+2
View File
@@ -48,6 +48,8 @@ impl ChainBase for Kusama {
impl Chain for Kusama { impl Chain for Kusama {
const NAME: &'static str = "Kusama"; const NAME: &'static str = "Kusama";
const BEST_FINALIZED_HEADER_ID_METHOD: &'static str =
bp_kusama::BEST_FINALIZED_KUSAMA_HEADER_METHOD;
const AVERAGE_BLOCK_INTERVAL: Duration = Duration::from_secs(6); const AVERAGE_BLOCK_INTERVAL: Duration = Duration::from_secs(6);
const STORAGE_PROOF_OVERHEAD: u32 = bp_kusama::EXTRA_STORAGE_PROOF_SIZE; const STORAGE_PROOF_OVERHEAD: u32 = bp_kusama::EXTRA_STORAGE_PROOF_SIZE;
const MAXIMAL_ENCODED_ACCOUNT_ID_SIZE: u32 = bp_kusama::MAXIMAL_ENCODED_ACCOUNT_ID_SIZE; const MAXIMAL_ENCODED_ACCOUNT_ID_SIZE: u32 = bp_kusama::MAXIMAL_ENCODED_ACCOUNT_ID_SIZE;
+2
View File
@@ -46,6 +46,8 @@ impl ChainBase for Millau {
impl Chain for Millau { impl Chain for Millau {
const NAME: &'static str = "Millau"; const NAME: &'static str = "Millau";
const BEST_FINALIZED_HEADER_ID_METHOD: &'static str =
bp_millau::BEST_FINALIZED_MILLAU_HEADER_METHOD;
const AVERAGE_BLOCK_INTERVAL: Duration = Duration::from_secs(5); const AVERAGE_BLOCK_INTERVAL: Duration = Duration::from_secs(5);
const STORAGE_PROOF_OVERHEAD: u32 = bp_millau::EXTRA_STORAGE_PROOF_SIZE; const STORAGE_PROOF_OVERHEAD: u32 = bp_millau::EXTRA_STORAGE_PROOF_SIZE;
const MAXIMAL_ENCODED_ACCOUNT_ID_SIZE: u32 = bp_millau::MAXIMAL_ENCODED_ACCOUNT_ID_SIZE; const MAXIMAL_ENCODED_ACCOUNT_ID_SIZE: u32 = bp_millau::MAXIMAL_ENCODED_ACCOUNT_ID_SIZE;
@@ -48,6 +48,8 @@ impl ChainBase for Polkadot {
impl Chain for Polkadot { impl Chain for Polkadot {
const NAME: &'static str = "Polkadot"; const NAME: &'static str = "Polkadot";
const BEST_FINALIZED_HEADER_ID_METHOD: &'static str =
bp_polkadot::BEST_FINALIZED_POLKADOT_HEADER_METHOD;
const AVERAGE_BLOCK_INTERVAL: Duration = Duration::from_secs(6); const AVERAGE_BLOCK_INTERVAL: Duration = Duration::from_secs(6);
const STORAGE_PROOF_OVERHEAD: u32 = bp_polkadot::EXTRA_STORAGE_PROOF_SIZE; const STORAGE_PROOF_OVERHEAD: u32 = bp_polkadot::EXTRA_STORAGE_PROOF_SIZE;
const MAXIMAL_ENCODED_ACCOUNT_ID_SIZE: u32 = bp_polkadot::MAXIMAL_ENCODED_ACCOUNT_ID_SIZE; const MAXIMAL_ENCODED_ACCOUNT_ID_SIZE: u32 = bp_polkadot::MAXIMAL_ENCODED_ACCOUNT_ID_SIZE;
@@ -41,6 +41,8 @@ impl ChainBase for RialtoParachain {
impl Chain for RialtoParachain { impl Chain for RialtoParachain {
const NAME: &'static str = "RialtoParachain"; const NAME: &'static str = "RialtoParachain";
// should be fixed/changed in https://github.com/paritytech/parity-bridges-common/pull/1199
const BEST_FINALIZED_HEADER_ID_METHOD: &'static str = "<UNIMPLEMENTED>";
const AVERAGE_BLOCK_INTERVAL: Duration = Duration::from_secs(5); const AVERAGE_BLOCK_INTERVAL: Duration = Duration::from_secs(5);
const STORAGE_PROOF_OVERHEAD: u32 = bp_rialto::EXTRA_STORAGE_PROOF_SIZE; const STORAGE_PROOF_OVERHEAD: u32 = bp_rialto::EXTRA_STORAGE_PROOF_SIZE;
const MAXIMAL_ENCODED_ACCOUNT_ID_SIZE: u32 = bp_rialto::MAXIMAL_ENCODED_ACCOUNT_ID_SIZE; const MAXIMAL_ENCODED_ACCOUNT_ID_SIZE: u32 = bp_rialto::MAXIMAL_ENCODED_ACCOUNT_ID_SIZE;
+2
View File
@@ -46,6 +46,8 @@ impl ChainBase for Rialto {
impl Chain for Rialto { impl Chain for Rialto {
const NAME: &'static str = "Rialto"; const NAME: &'static str = "Rialto";
const BEST_FINALIZED_HEADER_ID_METHOD: &'static str =
bp_rialto::BEST_FINALIZED_RIALTO_HEADER_METHOD;
const AVERAGE_BLOCK_INTERVAL: Duration = Duration::from_secs(5); const AVERAGE_BLOCK_INTERVAL: Duration = Duration::from_secs(5);
const STORAGE_PROOF_OVERHEAD: u32 = bp_rialto::EXTRA_STORAGE_PROOF_SIZE; const STORAGE_PROOF_OVERHEAD: u32 = bp_rialto::EXTRA_STORAGE_PROOF_SIZE;
const MAXIMAL_ENCODED_ACCOUNT_ID_SIZE: u32 = bp_rialto::MAXIMAL_ENCODED_ACCOUNT_ID_SIZE; const MAXIMAL_ENCODED_ACCOUNT_ID_SIZE: u32 = bp_rialto::MAXIMAL_ENCODED_ACCOUNT_ID_SIZE;
+2
View File
@@ -51,6 +51,8 @@ impl ChainBase for Rococo {
impl Chain for Rococo { impl Chain for Rococo {
const NAME: &'static str = "Rococo"; const NAME: &'static str = "Rococo";
const BEST_FINALIZED_HEADER_ID_METHOD: &'static str =
bp_rococo::BEST_FINALIZED_ROCOCO_HEADER_METHOD;
const AVERAGE_BLOCK_INTERVAL: Duration = Duration::from_secs(6); const AVERAGE_BLOCK_INTERVAL: Duration = Duration::from_secs(6);
const STORAGE_PROOF_OVERHEAD: u32 = bp_rococo::EXTRA_STORAGE_PROOF_SIZE; const STORAGE_PROOF_OVERHEAD: u32 = bp_rococo::EXTRA_STORAGE_PROOF_SIZE;
const MAXIMAL_ENCODED_ACCOUNT_ID_SIZE: u32 = bp_rococo::MAXIMAL_ENCODED_ACCOUNT_ID_SIZE; const MAXIMAL_ENCODED_ACCOUNT_ID_SIZE: u32 = bp_rococo::MAXIMAL_ENCODED_ACCOUNT_ID_SIZE;
+11 -1
View File
@@ -32,6 +32,13 @@ use std::{fmt::Debug, time::Duration};
pub trait Chain: ChainBase + Clone { pub trait Chain: ChainBase + Clone {
/// Chain name. /// Chain name.
const NAME: &'static str; const NAME: &'static str;
/// Name of the runtime API method that is returning best known finalized header number
/// and hash (as tuple).
///
/// Keep in mind that this method is normally provided by the other chain, which is
/// bridged with this chain.
const BEST_FINALIZED_HEADER_ID_METHOD: &'static str;
/// Average block interval. /// Average block interval.
/// ///
/// How often blocks are produced on that chain. It's suggested to set this value /// How often blocks are produced on that chain. It's suggested to set this value
@@ -45,7 +52,7 @@ pub trait Chain: ChainBase + Clone {
/// Block type. /// Block type.
type SignedBlock: Member + Serialize + DeserializeOwned + BlockWithJustification<Self::Header>; type SignedBlock: Member + Serialize + DeserializeOwned + BlockWithJustification<Self::Header>;
/// The aggregated `Call` type. /// The aggregated `Call` type.
type Call: Clone + Dispatchable + Debug; type Call: Clone + Dispatchable + Debug + Send;
/// Type that is used by the chain, to convert from weight to fee. /// Type that is used by the chain, to convert from weight to fee.
type WeightToFee: WeightToFeePolynomial<Balance = Self::Balance>; type WeightToFee: WeightToFeePolynomial<Balance = Self::Balance>;
@@ -102,6 +109,9 @@ impl<C: Chain> UnsignedTransaction<C> {
} }
} }
/// Account key pair used by transactions signing scheme.
pub type AccountKeyPairOf<S> = <S as TransactionSignScheme>::AccountKeyPair;
/// Substrate-based chain transactions signing scheme. /// Substrate-based chain transactions signing scheme.
pub trait TransactionSignScheme { pub trait TransactionSignScheme {
/// Chain that this scheme is to be used. /// Chain that this scheme is to be used.
@@ -206,6 +206,7 @@ mod tests {
impl Chain for TestChain { impl Chain for TestChain {
const NAME: &'static str = "Test"; const NAME: &'static str = "Test";
const BEST_FINALIZED_HEADER_ID_METHOD: &'static str = "BestTestHeader";
const AVERAGE_BLOCK_INTERVAL: Duration = Duration::from_millis(1); const AVERAGE_BLOCK_INTERVAL: Duration = Duration::from_millis(1);
const STORAGE_PROOF_OVERHEAD: u32 = 0; const STORAGE_PROOF_OVERHEAD: u32 = 0;
const MAXIMAL_ENCODED_ACCOUNT_ID_SIZE: u32 = 0; const MAXIMAL_ENCODED_ACCOUNT_ID_SIZE: u32 = 0;
+2 -3
View File
@@ -24,7 +24,6 @@ mod error;
mod rpc; mod rpc;
mod sync_header; mod sync_header;
pub mod finality_source;
pub mod guard; pub mod guard;
pub mod metrics; pub mod metrics;
@@ -32,8 +31,8 @@ use std::time::Duration;
pub use crate::{ pub use crate::{
chain::{ chain::{
BlockWithJustification, CallOf, Chain, ChainWithBalances, TransactionSignScheme, AccountKeyPairOf, BlockWithJustification, CallOf, Chain, ChainWithBalances,
TransactionStatusOf, UnsignedTransaction, WeightToFeeOf, TransactionSignScheme, TransactionStatusOf, UnsignedTransaction, WeightToFeeOf,
}, },
client::{Client, OpaqueGrandpaAuthoritiesSet, Subscription}, client::{Client, OpaqueGrandpaAuthoritiesSet, Subscription},
error::{Error, Result}, error::{Error, Result},
+2
View File
@@ -44,6 +44,8 @@ impl ChainBase for Westend {
impl Chain for Westend { impl Chain for Westend {
const NAME: &'static str = "Westend"; const NAME: &'static str = "Westend";
const BEST_FINALIZED_HEADER_ID_METHOD: &'static str =
bp_westend::BEST_FINALIZED_WESTEND_HEADER_METHOD;
const AVERAGE_BLOCK_INTERVAL: Duration = Duration::from_secs(6); const AVERAGE_BLOCK_INTERVAL: Duration = Duration::from_secs(6);
const STORAGE_PROOF_OVERHEAD: u32 = bp_westend::EXTRA_STORAGE_PROOF_SIZE; const STORAGE_PROOF_OVERHEAD: u32 = bp_westend::EXTRA_STORAGE_PROOF_SIZE;
const MAXIMAL_ENCODED_ACCOUNT_ID_SIZE: u32 = bp_westend::MAXIMAL_ENCODED_ACCOUNT_ID_SIZE; const MAXIMAL_ENCODED_ACCOUNT_ID_SIZE: u32 = bp_westend::MAXIMAL_ENCODED_ACCOUNT_ID_SIZE;
+2
View File
@@ -51,6 +51,8 @@ impl ChainBase for Wococo {
impl Chain for Wococo { impl Chain for Wococo {
const NAME: &'static str = "Wococo"; const NAME: &'static str = "Wococo";
const BEST_FINALIZED_HEADER_ID_METHOD: &'static str =
bp_wococo::BEST_FINALIZED_WOCOCO_HEADER_METHOD;
const AVERAGE_BLOCK_INTERVAL: Duration = Duration::from_secs(6); const AVERAGE_BLOCK_INTERVAL: Duration = Duration::from_secs(6);
const STORAGE_PROOF_OVERHEAD: u32 = bp_wococo::EXTRA_STORAGE_PROOF_SIZE; const STORAGE_PROOF_OVERHEAD: u32 = bp_wococo::EXTRA_STORAGE_PROOF_SIZE;
const MAXIMAL_ENCODED_ACCOUNT_ID_SIZE: u32 = bp_wococo::MAXIMAL_ENCODED_ACCOUNT_ID_SIZE; const MAXIMAL_ENCODED_ACCOUNT_ID_SIZE: u32 = bp_wococo::MAXIMAL_ENCODED_ACCOUNT_ID_SIZE;
@@ -27,6 +27,7 @@ relay-utils = { path = "../utils" }
messages-relay = { path = "../messages" } messages-relay = { path = "../messages" }
relay-substrate-client = { path = "../client-substrate" } relay-substrate-client = { path = "../client-substrate" }
pallet-bridge-grandpa = { path = "../../modules/grandpa" }
pallet-bridge-messages = { path = "../../modules/messages" } pallet-bridge-messages = { path = "../../modules/messages" }
bp-runtime = { path = "../../primitives/runtime" } bp-runtime = { path = "../../primitives/runtime" }
@@ -14,18 +14,20 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with Parity Bridges Common. If not, see <http://www.gnu.org/licenses/>. // along with Parity Bridges Common. If not, see <http://www.gnu.org/licenses/>.
//! Substrate-to-Substrate headers sync entrypoint. //! Types and functions intended to ease adding of new Substrate -> Substrate
//! finality proofs synchronization pipelines.
use crate::{finality_target::SubstrateFinalityTarget, STALL_TIMEOUT}; use crate::{finality_source::SubstrateFinalitySource, finality_target::SubstrateFinalityTarget};
use bp_header_chain::justification::GrandpaJustification; use bp_header_chain::justification::GrandpaJustification;
use bp_runtime::AccountIdOf; use finality_relay::FinalitySyncPipeline;
use finality_relay::{FinalitySyncParams, FinalitySyncPipeline}; use pallet_bridge_grandpa::{Call as BridgeGrandpaCall, Config as BridgeGrandpaConfig};
use relay_substrate_client::{ use relay_substrate_client::{
finality_source::FinalitySource, BlockNumberOf, Chain, Client, HashOf, SyncHeader, transaction_stall_timeout, AccountIdOf, AccountKeyPairOf, BlockNumberOf, CallOf, Chain, Client,
HashOf, HeaderOf, SyncHeader, TransactionSignScheme,
}; };
use relay_utils::{metrics::MetricsParams, BlockNumberBase}; use relay_utils::metrics::MetricsParams;
use sp_core::Bytes; use sp_core::Pair;
use std::{fmt::Debug, marker::PhantomData}; use std::{fmt::Debug, marker::PhantomData};
/// Default limit of recent finality proofs. /// Default limit of recent finality proofs.
@@ -34,130 +36,152 @@ use std::{fmt::Debug, marker::PhantomData};
/// Substrate+GRANDPA based chains (good to know). /// Substrate+GRANDPA based chains (good to know).
pub(crate) const RECENT_FINALITY_PROOFS_LIMIT: usize = 4096; pub(crate) const RECENT_FINALITY_PROOFS_LIMIT: usize = 4096;
/// Headers sync pipeline for Substrate <-> Substrate relays. /// Submit-finality-proofs transaction creation parameters.
#[derive(Clone, Debug)]
pub struct TransactionParams<TS> {
/// Transactions author.
pub transactions_signer: TS,
/// Transactions mortality.
pub transactions_mortality: Option<u32>,
}
/// Substrate -> Substrate finality proofs synchronization pipeline.
pub trait SubstrateFinalitySyncPipeline: 'static + Clone + Debug + Send + Sync { pub trait SubstrateFinalitySyncPipeline: 'static + Clone + Debug + Send + Sync {
/// Pipeline for syncing finalized Source chain headers to Target chain. /// Headers of this chain are submitted to the `TargetChain`.
type FinalitySyncPipeline: FinalitySyncPipeline; type SourceChain: Chain;
/// Headers of the `SourceChain` are submitted to this chain.
/// Name of the runtime method that returns id of best finalized source header at target chain.
const BEST_FINALIZED_SOURCE_HEADER_ID_AT_TARGET: &'static str;
/// Chain with GRANDPA bridge pallet.
type TargetChain: Chain; type TargetChain: Chain;
/// Customize metrics exposed by headers sync loop. /// How submit finality proof call is built?
fn customize_metrics(params: MetricsParams) -> anyhow::Result<MetricsParams> { type SubmitFinalityProofCallBuilder: SubmitFinalityProofCallBuilder<Self>;
Ok(params) /// Scheme used to sign target chain transactions.
} type TransactionSignScheme: TransactionSignScheme;
/// Start finality relay guards. /// Add relay guards if required.
/// fn start_relay_guards(
/// Different finality bridges may have different set of guards - e.g. on ephemeral chains we _target_client: &Client<Self::TargetChain>,
/// don't need a version guards, on test chains we don't care that much about relayer account _transaction_params: &TransactionParams<AccountKeyPairOf<Self::TransactionSignScheme>>,
/// balance, ... So the implementation is left to the specific bridges. ) {
fn start_relay_guards(&self) {}
/// Returns id of account that we're using to sign transactions at target chain.
fn transactions_author(&self) -> AccountIdOf<Self::TargetChain>;
/// Make submit header transaction.
fn make_submit_finality_proof_transaction(
&self,
era: bp_runtime::TransactionEraOf<Self::TargetChain>,
transaction_nonce: bp_runtime::IndexOf<Self::TargetChain>,
header: <Self::FinalitySyncPipeline as FinalitySyncPipeline>::Header,
proof: <Self::FinalitySyncPipeline as FinalitySyncPipeline>::FinalityProof,
) -> Bytes;
}
/// Substrate-to-Substrate finality proof pipeline.
#[derive(Clone)]
pub struct SubstrateFinalityToSubstrate<SourceChain, TargetChain: Chain, TargetSign> {
/// Client for the target chain.
pub target_client: Client<TargetChain>,
/// Data required to sign target chain transactions.
pub target_sign: TargetSign,
/// Unused generic arguments dump.
_marker: PhantomData<SourceChain>,
}
impl<SourceChain, TargetChain: Chain, TargetSign> Debug
for SubstrateFinalityToSubstrate<SourceChain, TargetChain, TargetSign>
{
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
f.debug_struct("SubstrateFinalityToSubstrate")
.field("target_client", &self.target_client)
.finish()
} }
} }
impl<SourceChain, TargetChain: Chain, TargetSign> /// Adapter that allows all `SubstrateFinalitySyncPipeline` to act as `FinalitySyncPipeline`.
SubstrateFinalityToSubstrate<SourceChain, TargetChain, TargetSign> #[derive(Clone, Debug)]
{ pub struct FinalitySyncPipelineAdapter<P: SubstrateFinalitySyncPipeline> {
/// Create new Substrate-to-Substrate headers pipeline. _phantom: PhantomData<P>,
pub fn new(target_client: Client<TargetChain>, target_sign: TargetSign) -> Self {
SubstrateFinalityToSubstrate { target_client, target_sign, _marker: Default::default() }
}
} }
impl<SourceChain, TargetChain, TargetSign> FinalitySyncPipeline impl<P: SubstrateFinalitySyncPipeline> FinalitySyncPipeline for FinalitySyncPipelineAdapter<P> {
for SubstrateFinalityToSubstrate<SourceChain, TargetChain, TargetSign> const SOURCE_NAME: &'static str = P::SourceChain::NAME;
const TARGET_NAME: &'static str = P::TargetChain::NAME;
type Hash = HashOf<P::SourceChain>;
type Number = BlockNumberOf<P::SourceChain>;
type Header = relay_substrate_client::SyncHeader<HeaderOf<P::SourceChain>>;
type FinalityProof = GrandpaJustification<HeaderOf<P::SourceChain>>;
}
/// Different ways of building `submit_finality_proof` calls.
pub trait SubmitFinalityProofCallBuilder<P: SubstrateFinalitySyncPipeline> {
/// Given source chain header and its finality proofs, build call of `submit_finality_proof`
/// function of bridge GRANDPA module at the target chain.
fn build_submit_finality_proof_call(
header: SyncHeader<HeaderOf<P::SourceChain>>,
proof: GrandpaJustification<HeaderOf<P::SourceChain>>,
) -> CallOf<P::TargetChain>;
}
/// Building `submit_finality_proof` call when you have direct access to the target
/// chain runtime.
pub struct DirectSubmitFinalityProofCallBuilder<P, R, I> {
_phantom: PhantomData<(P, R, I)>,
}
impl<P, R, I> SubmitFinalityProofCallBuilder<P> for DirectSubmitFinalityProofCallBuilder<P, R, I>
where where
SourceChain: Clone + Chain + Debug, P: SubstrateFinalitySyncPipeline,
BlockNumberOf<SourceChain>: BlockNumberBase, R: BridgeGrandpaConfig<I>,
TargetChain: Clone + Chain + Debug, I: 'static,
TargetSign: 'static + Clone + Send + Sync, R::BridgedChain: bp_runtime::Chain<Header = HeaderOf<P::SourceChain>>,
CallOf<P::TargetChain>: From<BridgeGrandpaCall<R, I>>,
{ {
const SOURCE_NAME: &'static str = SourceChain::NAME; fn build_submit_finality_proof_call(
const TARGET_NAME: &'static str = TargetChain::NAME; header: SyncHeader<HeaderOf<P::SourceChain>>,
proof: GrandpaJustification<HeaderOf<P::SourceChain>>,
type Hash = HashOf<SourceChain>; ) -> CallOf<P::TargetChain> {
type Number = BlockNumberOf<SourceChain>; BridgeGrandpaCall::<R, I>::submit_finality_proof {
type Header = SyncHeader<SourceChain::Header>; finality_target: Box::new(header.into_inner()),
type FinalityProof = GrandpaJustification<SourceChain::Header>; justification: proof,
}
.into()
}
} }
/// Run Substrate-to-Substrate finality sync. /// Macro that generates `SubmitFinalityProofCallBuilder` implementation for the case when
pub async fn run<SourceChain, TargetChain, P>( /// you only have an access to the mocked version of target chain runtime. In this case you
pipeline: P, /// should provide "name" of the call variant for the bridge GRANDPA calls and the "name" of
source_client: Client<SourceChain>, /// the variant for the `submit_finality_proof` call within that first option.
target_client: Client<TargetChain>, #[rustfmt::skip]
#[macro_export]
macro_rules! generate_mocked_submit_finality_proof_call_builder {
($pipeline:ident, $mocked_builder:ident, $bridge_grandpa:path, $submit_finality_proof:path) => {
pub struct $mocked_builder;
impl $crate::finality_pipeline::SubmitFinalityProofCallBuilder<$pipeline>
for $mocked_builder
{
fn build_submit_finality_proof_call(
header: relay_substrate_client::SyncHeader<
relay_substrate_client::HeaderOf<
<$pipeline as $crate::finality_pipeline::SubstrateFinalitySyncPipeline>::SourceChain
>
>,
proof: bp_header_chain::justification::GrandpaJustification<
relay_substrate_client::HeaderOf<
<$pipeline as $crate::finality_pipeline::SubstrateFinalitySyncPipeline>::SourceChain
>
>,
) -> relay_substrate_client::CallOf<
<$pipeline as $crate::finality_pipeline::SubstrateFinalitySyncPipeline>::TargetChain
> {
$bridge_grandpa($submit_finality_proof(Box::new(header.into_inner()), proof))
}
}
};
}
/// Run Substrate-to-Substrate finality sync loop.
pub async fn run<P: SubstrateFinalitySyncPipeline>(
source_client: Client<P::SourceChain>,
target_client: Client<P::TargetChain>,
only_mandatory_headers: bool, only_mandatory_headers: bool,
transactions_mortality: Option<u32>, transaction_params: TransactionParams<AccountKeyPairOf<P::TransactionSignScheme>>,
metrics_params: MetricsParams, metrics_params: MetricsParams,
) -> anyhow::Result<()> ) -> anyhow::Result<()>
where where
P: SubstrateFinalitySyncPipeline<TargetChain = TargetChain>, AccountIdOf<P::TargetChain>: From<<AccountKeyPairOf<P::TransactionSignScheme> as Pair>::Public>,
P::FinalitySyncPipeline: FinalitySyncPipeline< P::TransactionSignScheme: TransactionSignScheme<Chain = P::TargetChain>,
Hash = HashOf<SourceChain>,
Number = BlockNumberOf<SourceChain>,
Header = SyncHeader<SourceChain::Header>,
FinalityProof = GrandpaJustification<SourceChain::Header>,
>,
SourceChain: Clone + Chain,
BlockNumberOf<SourceChain>: BlockNumberBase,
TargetChain: Clone + Chain,
{ {
log::info!( log::info!(
target: "bridge", target: "bridge",
"Starting {} -> {} finality proof relay", "Starting {} -> {} finality proof relay",
SourceChain::NAME, P::SourceChain::NAME,
TargetChain::NAME, P::TargetChain::NAME,
); );
finality_relay::run( finality_relay::run(
FinalitySource::new(source_client, None), SubstrateFinalitySource::<P>::new(source_client, None),
SubstrateFinalityTarget::new(target_client, pipeline, transactions_mortality), SubstrateFinalityTarget::<P>::new(target_client, transaction_params.clone()),
FinalitySyncParams { finality_relay::FinalitySyncParams {
tick: std::cmp::max( tick: std::cmp::max(
SourceChain::AVERAGE_BLOCK_INTERVAL, P::SourceChain::AVERAGE_BLOCK_INTERVAL,
TargetChain::AVERAGE_BLOCK_INTERVAL, P::TargetChain::AVERAGE_BLOCK_INTERVAL,
), ),
recent_finality_proofs_limit: RECENT_FINALITY_PROOFS_LIMIT, recent_finality_proofs_limit: RECENT_FINALITY_PROOFS_LIMIT,
stall_timeout: relay_substrate_client::transaction_stall_timeout( stall_timeout: transaction_stall_timeout(
transactions_mortality, transaction_params.transactions_mortality,
TargetChain::AVERAGE_BLOCK_INTERVAL, P::TargetChain::AVERAGE_BLOCK_INTERVAL,
STALL_TIMEOUT, crate::STALL_TIMEOUT,
), ),
only_mandatory_headers, only_mandatory_headers,
}, },
@@ -16,49 +16,59 @@
//! Default generic implementation of finality source for basic Substrate client. //! Default generic implementation of finality source for basic Substrate client.
use crate::{ use crate::finality_pipeline::{FinalitySyncPipelineAdapter, SubstrateFinalitySyncPipeline};
chain::{BlockWithJustification, Chain},
client::Client,
error::Error,
sync_header::SyncHeader,
};
use async_std::sync::{Arc, Mutex}; use async_std::sync::{Arc, Mutex};
use async_trait::async_trait; use async_trait::async_trait;
use bp_header_chain::justification::GrandpaJustification; use bp_header_chain::justification::GrandpaJustification;
use codec::Decode; use codec::Decode;
use finality_relay::{FinalitySyncPipeline, SourceClient, SourceHeader}; use finality_relay::SourceClient;
use futures::stream::{unfold, Stream, StreamExt}; use futures::stream::{unfold, Stream, StreamExt};
use relay_substrate_client::{
BlockNumberOf, BlockWithJustification, Chain, Client, Error, HeaderOf,
};
use relay_utils::relay_loop::Client as RelayClient; use relay_utils::relay_loop::Client as RelayClient;
use sp_runtime::traits::Header as HeaderT; use sp_runtime::traits::Header as HeaderT;
use std::{marker::PhantomData, pin::Pin}; use std::pin::Pin;
/// Shared updatable reference to the maximal header number that we want to sync from the source. /// Shared updatable reference to the maximal header number that we want to sync from the source.
pub type RequiredHeaderNumberRef<C> = Arc<Mutex<<C as bp_runtime::Chain>::BlockNumber>>; pub type RequiredHeaderNumberRef<C> = Arc<Mutex<<C as bp_runtime::Chain>::BlockNumber>>;
/// Substrate finality proofs stream.
pub type SubstrateFinalityProofsStream<P> = Pin<
Box<
dyn Stream<
Item = GrandpaJustification<
HeaderOf<<P as SubstrateFinalitySyncPipeline>::SourceChain>,
>,
> + Send,
>,
>;
/// Substrate node as finality source. /// Substrate node as finality source.
pub struct FinalitySource<C: Chain, P> { pub struct SubstrateFinalitySource<P: SubstrateFinalitySyncPipeline> {
client: Client<C>, client: Client<P::SourceChain>,
maximal_header_number: Option<RequiredHeaderNumberRef<C>>, maximal_header_number: Option<RequiredHeaderNumberRef<P::SourceChain>>,
_phantom: PhantomData<P>,
} }
impl<C: Chain, P> FinalitySource<C, P> { impl<P: SubstrateFinalitySyncPipeline> SubstrateFinalitySource<P> {
/// Create new headers source using given client. /// Create new headers source using given client.
pub fn new( pub fn new(
client: Client<C>, client: Client<P::SourceChain>,
maximal_header_number: Option<RequiredHeaderNumberRef<C>>, maximal_header_number: Option<RequiredHeaderNumberRef<P::SourceChain>>,
) -> Self { ) -> Self {
FinalitySource { client, maximal_header_number, _phantom: Default::default() } SubstrateFinalitySource { client, maximal_header_number }
} }
/// Returns reference to the underlying RPC client. /// Returns reference to the underlying RPC client.
pub fn client(&self) -> &Client<C> { pub fn client(&self) -> &Client<P::SourceChain> {
&self.client &self.client
} }
/// Returns best finalized block number. /// Returns best finalized block number.
pub async fn on_chain_best_finalized_block_number(&self) -> Result<C::BlockNumber, Error> { pub async fn on_chain_best_finalized_block_number(
&self,
) -> Result<BlockNumberOf<P::SourceChain>, Error> {
// we **CAN** continue to relay finality proofs if source node is out of sync, because // we **CAN** continue to relay finality proofs if source node is out of sync, because
// target node may be missing proofs that are already available at the source // target node may be missing proofs that are already available at the source
let finalized_header_hash = self.client.best_finalized_header_hash().await?; let finalized_header_hash = self.client.best_finalized_header_hash().await?;
@@ -67,18 +77,17 @@ impl<C: Chain, P> FinalitySource<C, P> {
} }
} }
impl<C: Chain, P> Clone for FinalitySource<C, P> { impl<P: SubstrateFinalitySyncPipeline> Clone for SubstrateFinalitySource<P> {
fn clone(&self) -> Self { fn clone(&self) -> Self {
FinalitySource { SubstrateFinalitySource {
client: self.client.clone(), client: self.client.clone(),
maximal_header_number: self.maximal_header_number.clone(), maximal_header_number: self.maximal_header_number.clone(),
_phantom: Default::default(),
} }
} }
} }
#[async_trait] #[async_trait]
impl<C: Chain, P: FinalitySyncPipeline> RelayClient for FinalitySource<C, P> { impl<P: SubstrateFinalitySyncPipeline> RelayClient for SubstrateFinalitySource<P> {
type Error = Error; type Error = Error;
async fn reconnect(&mut self) -> Result<(), Error> { async fn reconnect(&mut self) -> Result<(), Error> {
@@ -87,21 +96,12 @@ impl<C: Chain, P: FinalitySyncPipeline> RelayClient for FinalitySource<C, P> {
} }
#[async_trait] #[async_trait]
impl<C, P> SourceClient<P> for FinalitySource<C, P> impl<P: SubstrateFinalitySyncPipeline> SourceClient<FinalitySyncPipelineAdapter<P>>
where for SubstrateFinalitySource<P>
C: Chain,
C::BlockNumber: relay_utils::BlockNumberBase,
P: FinalitySyncPipeline<
Hash = C::Hash,
Number = C::BlockNumber,
Header = SyncHeader<C::Header>,
FinalityProof = GrandpaJustification<C::Header>,
>,
P::Header: SourceHeader<C::BlockNumber>,
{ {
type FinalityProofsStream = Pin<Box<dyn Stream<Item = GrandpaJustification<C::Header>> + Send>>; type FinalityProofsStream = SubstrateFinalityProofsStream<P>;
async fn best_finalized_block_number(&self) -> Result<P::Number, Error> { async fn best_finalized_block_number(&self) -> Result<BlockNumberOf<P::SourceChain>, Error> {
let mut finalized_header_number = self.on_chain_best_finalized_block_number().await?; let mut finalized_header_number = self.on_chain_best_finalized_block_number().await?;
// never return block number larger than requested. This way we'll never sync headers // never return block number larger than requested. This way we'll never sync headers
// past `maximal_header_number` // past `maximal_header_number`
@@ -116,15 +116,23 @@ where
async fn header_and_finality_proof( async fn header_and_finality_proof(
&self, &self,
number: P::Number, number: BlockNumberOf<P::SourceChain>,
) -> Result<(P::Header, Option<P::FinalityProof>), Error> { ) -> Result<
(
relay_substrate_client::SyncHeader<HeaderOf<P::SourceChain>>,
Option<GrandpaJustification<HeaderOf<P::SourceChain>>>,
),
Error,
> {
let header_hash = self.client.block_hash_by_number(number).await?; let header_hash = self.client.block_hash_by_number(number).await?;
let signed_block = self.client.get_block(Some(header_hash)).await?; let signed_block = self.client.get_block(Some(header_hash)).await?;
let justification = signed_block let justification = signed_block
.justification() .justification()
.map(|raw_justification| { .map(|raw_justification| {
GrandpaJustification::<C::Header>::decode(&mut raw_justification.as_slice()) GrandpaJustification::<HeaderOf<P::SourceChain>>::decode(
&mut raw_justification.as_slice(),
)
}) })
.transpose() .transpose()
.map_err(Error::ResponseParseFailed)?; .map_err(Error::ResponseParseFailed)?;
@@ -141,7 +149,7 @@ where
log::error!( log::error!(
target: "bridge", target: "bridge",
"Failed to read justification target from the {} justifications stream: {:?}", "Failed to read justification target from the {} justifications stream: {:?}",
P::SOURCE_NAME, P::SourceChain::NAME,
err, err,
); );
}; };
@@ -153,7 +161,9 @@ where
.ok()??; .ok()??;
let decoded_justification = let decoded_justification =
GrandpaJustification::<C::Header>::decode(&mut &next_justification[..]); GrandpaJustification::<HeaderOf<P::SourceChain>>::decode(
&mut &next_justification[..],
);
let justification = match decoded_justification { let justification = match decoded_justification {
Ok(j) => j, Ok(j) => j,
@@ -15,70 +15,78 @@
// along with Parity Bridges Common. If not, see <http://www.gnu.org/licenses/>. // along with Parity Bridges Common. If not, see <http://www.gnu.org/licenses/>.
//! Substrate client as Substrate finality proof target. The chain we connect to should have //! Substrate client as Substrate finality proof target. The chain we connect to should have
//! runtime that implements `<BridgedChainName>FinalityApi` to allow bridging with //! bridge GRANDPA pallet deployed and provide `<BridgedChainName>FinalityApi` to allow bridging
//! <BridgedName> chain. //! with <BridgedName> chain.
use crate::finality_pipeline::SubstrateFinalitySyncPipeline; use crate::finality_pipeline::{
FinalitySyncPipelineAdapter, SubmitFinalityProofCallBuilder, SubstrateFinalitySyncPipeline,
TransactionParams,
};
use async_trait::async_trait; use async_trait::async_trait;
use codec::Decode; use bp_header_chain::justification::GrandpaJustification;
use finality_relay::{FinalitySyncPipeline, TargetClient}; use codec::Encode;
use relay_substrate_client::{Chain, Client, Error as SubstrateError}; use finality_relay::TargetClient;
use relay_substrate_client::{
AccountIdOf, AccountKeyPairOf, BlockNumberOf, Chain, Client, Error, HashOf, HeaderOf,
SyncHeader, TransactionEra, TransactionSignScheme, UnsignedTransaction,
};
use relay_utils::relay_loop::Client as RelayClient; use relay_utils::relay_loop::Client as RelayClient;
use sp_core::{Bytes, Pair};
/// Substrate client as Substrate finality target. /// Substrate client as Substrate finality target.
pub struct SubstrateFinalityTarget<C: Chain, P> { pub struct SubstrateFinalityTarget<P: SubstrateFinalitySyncPipeline> {
client: Client<C>, client: Client<P::TargetChain>,
pipeline: P, transaction_params: TransactionParams<AccountKeyPairOf<P::TransactionSignScheme>>,
transactions_mortality: Option<u32>,
} }
impl<C: Chain, P> SubstrateFinalityTarget<C, P> { impl<P: SubstrateFinalitySyncPipeline> SubstrateFinalityTarget<P> {
/// Create new Substrate headers target. /// Create new Substrate headers target.
pub fn new(client: Client<C>, pipeline: P, transactions_mortality: Option<u32>) -> Self { pub fn new(
SubstrateFinalityTarget { client, pipeline, transactions_mortality } client: Client<P::TargetChain>,
transaction_params: TransactionParams<AccountKeyPairOf<P::TransactionSignScheme>>,
) -> Self {
SubstrateFinalityTarget { client, transaction_params }
} }
} }
impl<C: Chain, P: SubstrateFinalitySyncPipeline> Clone for SubstrateFinalityTarget<C, P> { impl<P: SubstrateFinalitySyncPipeline> Clone for SubstrateFinalityTarget<P> {
fn clone(&self) -> Self { fn clone(&self) -> Self {
SubstrateFinalityTarget { SubstrateFinalityTarget {
client: self.client.clone(), client: self.client.clone(),
pipeline: self.pipeline.clone(), transaction_params: self.transaction_params.clone(),
transactions_mortality: self.transactions_mortality,
} }
} }
} }
#[async_trait] #[async_trait]
impl<C: Chain, P: SubstrateFinalitySyncPipeline> RelayClient for SubstrateFinalityTarget<C, P> { impl<P: SubstrateFinalitySyncPipeline> RelayClient for SubstrateFinalityTarget<P> {
type Error = SubstrateError; type Error = Error;
async fn reconnect(&mut self) -> Result<(), SubstrateError> { async fn reconnect(&mut self) -> Result<(), Error> {
self.client.reconnect().await self.client.reconnect().await
} }
} }
#[async_trait] #[async_trait]
impl<C, P> TargetClient<P::FinalitySyncPipeline> for SubstrateFinalityTarget<C, P> impl<P: SubstrateFinalitySyncPipeline> TargetClient<FinalitySyncPipelineAdapter<P>>
for SubstrateFinalityTarget<P>
where where
C: Chain, AccountIdOf<P::TargetChain>: From<<AccountKeyPairOf<P::TransactionSignScheme> as Pair>::Public>,
P: SubstrateFinalitySyncPipeline<TargetChain = C>, P::TransactionSignScheme: TransactionSignScheme<Chain = P::TargetChain>,
<P::FinalitySyncPipeline as FinalitySyncPipeline>::Number: Decode,
<P::FinalitySyncPipeline as FinalitySyncPipeline>::Hash: Decode,
{ {
async fn best_finalized_source_block_number( async fn best_finalized_source_block_number(
&self, &self,
) -> Result<<P::FinalitySyncPipeline as FinalitySyncPipeline>::Number, SubstrateError> { ) -> Result<BlockNumberOf<P::SourceChain>, Error> {
// we can't continue to relay finality if target node is out of sync, because // we can't continue to relay finality if target node is out of sync, because
// it may have already received (some of) headers that we're going to relay // it may have already received (some of) headers that we're going to relay
self.client.ensure_synced().await?; self.client.ensure_synced().await?;
Ok(crate::messages_source::read_client_state::< Ok(crate::messages_source::read_client_state::<
C, P::TargetChain,
<P::FinalitySyncPipeline as FinalitySyncPipeline>::Hash, HashOf<P::SourceChain>,
<P::FinalitySyncPipeline as FinalitySyncPipeline>::Number, BlockNumberOf<P::SourceChain>,
>(&self.client, P::BEST_FINALIZED_SOURCE_HEADER_ID_AT_TARGET) >(&self.client, P::SourceChain::BEST_FINALIZED_HEADER_ID_METHOD)
.await? .await?
.best_finalized_peer_at_best_self .best_finalized_peer_at_best_self
.0) .0)
@@ -86,24 +94,28 @@ where
async fn submit_finality_proof( async fn submit_finality_proof(
&self, &self,
header: <P::FinalitySyncPipeline as FinalitySyncPipeline>::Header, header: SyncHeader<HeaderOf<P::SourceChain>>,
proof: <P::FinalitySyncPipeline as FinalitySyncPipeline>::FinalityProof, proof: GrandpaJustification<HeaderOf<P::SourceChain>>,
) -> Result<(), SubstrateError> { ) -> Result<(), Error> {
let transactions_author = self.pipeline.transactions_author(); let genesis_hash = *self.client.genesis_hash();
let pipeline = self.pipeline.clone(); let transaction_params = self.transaction_params.clone();
let transactions_mortality = self.transactions_mortality; let call =
P::SubmitFinalityProofCallBuilder::build_submit_finality_proof_call(header, proof);
self.client self.client
.submit_signed_extrinsic( .submit_signed_extrinsic(
transactions_author, self.transaction_params.transactions_signer.public().into(),
move |best_block_id, transaction_nonce| { move |best_block_id, transaction_nonce| {
pipeline.make_submit_finality_proof_transaction( Bytes(
relay_substrate_client::TransactionEra::new( P::TransactionSignScheme::sign_transaction(
genesis_hash,
&transaction_params.transactions_signer,
TransactionEra::new(
best_block_id, best_block_id,
transactions_mortality, transaction_params.transactions_mortality,
), ),
transaction_nonce, UnsignedTransaction::new(call, transaction_nonce),
header, )
proof, .encode(),
) )
}, },
) )
@@ -23,6 +23,7 @@ use std::time::Duration;
pub mod conversion_rate_update; pub mod conversion_rate_update;
pub mod error; pub mod error;
pub mod finality_pipeline; pub mod finality_pipeline;
pub mod finality_source;
pub mod finality_target; pub mod finality_target;
pub mod headers_initialize; pub mod headers_initialize;
pub mod helpers; pub mod helpers;
@@ -16,29 +16,24 @@
//! On-demand Substrate -> Substrate headers relay. //! On-demand Substrate -> Substrate headers relay.
use std::fmt::Debug;
use async_std::sync::{Arc, Mutex}; use async_std::sync::{Arc, Mutex};
use futures::{select, FutureExt}; use futures::{select, FutureExt};
use num_traits::{CheckedSub, One, Zero}; use num_traits::{CheckedSub, One, Zero};
use finality_relay::{ use finality_relay::{FinalitySyncParams, SourceHeader, TargetClient as FinalityTargetClient};
FinalitySyncParams, FinalitySyncPipeline, SourceClient as FinalitySourceClient, SourceHeader,
TargetClient as FinalityTargetClient,
};
use relay_substrate_client::{ use relay_substrate_client::{
finality_source::{FinalitySource as SubstrateFinalitySource, RequiredHeaderNumberRef}, AccountIdOf, AccountKeyPairOf, BlockNumberOf, Chain, Client, HeaderIdOf, HeaderOf, SyncHeader,
Chain, Client, HeaderIdOf, SyncHeader, TransactionSignScheme,
}; };
use relay_utils::{ use relay_utils::{
metrics::MetricsParams, relay_loop::Client as RelayClient, BlockNumberBase, FailedClient, metrics::MetricsParams, relay_loop::Client as RelayClient, FailedClient, MaybeConnectionError,
MaybeConnectionError,
}; };
use crate::{ use crate::{
finality_pipeline::{ finality_pipeline::{
SubstrateFinalitySyncPipeline, SubstrateFinalityToSubstrate, RECENT_FINALITY_PROOFS_LIMIT, SubstrateFinalitySyncPipeline, TransactionParams, RECENT_FINALITY_PROOFS_LIMIT,
}, },
finality_source::{RequiredHeaderNumberRef, SubstrateFinalitySource},
finality_target::SubstrateFinalityTarget, finality_target::SubstrateFinalityTarget,
STALL_TIMEOUT, STALL_TIMEOUT,
}; };
@@ -58,40 +53,28 @@ pub struct OnDemandHeadersRelay<SourceChain: Chain> {
impl<SourceChain: Chain> OnDemandHeadersRelay<SourceChain> { impl<SourceChain: Chain> OnDemandHeadersRelay<SourceChain> {
/// Create new on-demand headers relay. /// Create new on-demand headers relay.
pub fn new<TargetChain: Chain, TargetSign, P>( pub fn new<P: SubstrateFinalitySyncPipeline<SourceChain = SourceChain>>(
source_client: Client<SourceChain>, source_client: Client<P::SourceChain>,
target_client: Client<TargetChain>, target_client: Client<P::TargetChain>,
target_transactions_mortality: Option<u32>, target_transaction_params: TransactionParams<AccountKeyPairOf<P::TransactionSignScheme>>,
pipeline: P, maximal_headers_difference: BlockNumberOf<P::SourceChain>,
maximal_headers_difference: SourceChain::BlockNumber,
only_mandatory_headers: bool, only_mandatory_headers: bool,
) -> Self ) -> Self
where where
SourceChain: Chain + Debug, AccountIdOf<P::TargetChain>:
SourceChain::BlockNumber: BlockNumberBase, From<<AccountKeyPairOf<P::TransactionSignScheme> as sp_core::Pair>::Public>,
TargetChain: Chain + Debug, P::TransactionSignScheme: TransactionSignScheme<Chain = P::TargetChain>,
TargetChain::BlockNumber: BlockNumberBase,
TargetSign: Clone + Send + Sync + 'static,
P: SubstrateFinalitySyncPipeline<
FinalitySyncPipeline = SubstrateFinalityToSubstrate<
SourceChain,
TargetChain,
TargetSign,
>,
TargetChain = TargetChain,
>,
{ {
let required_header_number = Arc::new(Mutex::new(Zero::zero())); let required_header_number = Arc::new(Mutex::new(Zero::zero()));
let this = OnDemandHeadersRelay { let this = OnDemandHeadersRelay {
relay_task_name: on_demand_headers_relay_name::<SourceChain, TargetChain>(), relay_task_name: on_demand_headers_relay_name::<P::SourceChain, P::TargetChain>(),
required_header_number: required_header_number.clone(), required_header_number: required_header_number.clone(),
}; };
async_std::task::spawn(async move { async_std::task::spawn(async move {
background_task( background_task::<P>(
source_client, source_client,
target_client, target_client,
target_transactions_mortality, target_transaction_params,
pipeline,
maximal_headers_difference, maximal_headers_difference,
only_mandatory_headers, only_mandatory_headers,
required_header_number, required_header_number,
@@ -120,35 +103,25 @@ impl<SourceChain: Chain> OnDemandHeadersRelay<SourceChain> {
} }
/// Background task that is responsible for starting headers relay. /// Background task that is responsible for starting headers relay.
async fn background_task<SourceChain, TargetChain, TargetSign, P>( async fn background_task<P: SubstrateFinalitySyncPipeline>(
source_client: Client<SourceChain>, source_client: Client<P::SourceChain>,
target_client: Client<TargetChain>, target_client: Client<P::TargetChain>,
target_transactions_mortality: Option<u32>, target_transaction_params: TransactionParams<AccountKeyPairOf<P::TransactionSignScheme>>,
pipeline: P, maximal_headers_difference: BlockNumberOf<P::SourceChain>,
maximal_headers_difference: SourceChain::BlockNumber,
only_mandatory_headers: bool, only_mandatory_headers: bool,
required_header_number: RequiredHeaderNumberRef<SourceChain>, required_header_number: RequiredHeaderNumberRef<P::SourceChain>,
) where ) where
SourceChain: Chain + Debug, AccountIdOf<P::TargetChain>:
SourceChain::BlockNumber: BlockNumberBase, From<<AccountKeyPairOf<P::TransactionSignScheme> as sp_core::Pair>::Public>,
TargetChain: Chain + Debug, P::TransactionSignScheme: TransactionSignScheme<Chain = P::TargetChain>,
TargetChain::BlockNumber: BlockNumberBase,
TargetSign: Clone + Send + Sync + 'static,
P: SubstrateFinalitySyncPipeline<
FinalitySyncPipeline = SubstrateFinalityToSubstrate<SourceChain, TargetChain, TargetSign>,
TargetChain = TargetChain,
>,
{ {
let relay_task_name = on_demand_headers_relay_name::<SourceChain, TargetChain>(); let relay_task_name = on_demand_headers_relay_name::<P::SourceChain, P::TargetChain>();
let mut finality_source = SubstrateFinalitySource::< let mut finality_source = SubstrateFinalitySource::<P>::new(
_, source_client.clone(),
SubstrateFinalityToSubstrate<SourceChain, TargetChain, TargetSign>, Some(required_header_number.clone()),
>::new(source_client.clone(), Some(required_header_number.clone()));
let mut finality_target = SubstrateFinalityTarget::new(
target_client.clone(),
pipeline.clone(),
target_transactions_mortality,
); );
let mut finality_target =
SubstrateFinalityTarget::new(target_client.clone(), target_transaction_params);
let mut latest_non_mandatory_at_source = Zero::zero(); let mut latest_non_mandatory_at_source = Zero::zero();
let mut restart_relay = true; let mut restart_relay = true;
@@ -157,7 +130,7 @@ async fn background_task<SourceChain, TargetChain, TargetSign, P>(
loop { loop {
select! { select! {
_ = async_std::task::sleep(TargetChain::AVERAGE_BLOCK_INTERVAL).fuse() => {}, _ = async_std::task::sleep(P::TargetChain::AVERAGE_BLOCK_INTERVAL).fuse() => {},
_ = finality_relay_task => { _ = finality_relay_task => {
// this should never happen in practice given the current code // this should never happen in practice given the current code
restart_relay = true; restart_relay = true;
@@ -179,12 +152,8 @@ async fn background_task<SourceChain, TargetChain, TargetSign, P>(
} }
// read best finalized source header number from target // read best finalized source header number from target
let best_finalized_source_header_at_target = best_finalized_source_header_at_target::< let best_finalized_source_header_at_target =
SourceChain, best_finalized_source_header_at_target::<P>(&finality_target, &relay_task_name).await;
_,
_,
>(&finality_target, &relay_task_name)
.await;
if matches!(best_finalized_source_header_at_target, Err(ref e) if e.is_connection_error()) { if matches!(best_finalized_source_header_at_target, Err(ref e) if e.is_connection_error()) {
relay_utils::relay_loop::reconnect_failed_client( relay_utils::relay_loop::reconnect_failed_client(
FailedClient::Target, FailedClient::Target,
@@ -199,7 +168,7 @@ async fn background_task<SourceChain, TargetChain, TargetSign, P>(
// submit mandatory header if some headers are missing // submit mandatory header if some headers are missing
let best_finalized_source_header_at_target_fmt = let best_finalized_source_header_at_target_fmt =
format!("{:?}", best_finalized_source_header_at_target); format!("{:?}", best_finalized_source_header_at_target);
let mandatory_scan_range = mandatory_headers_scan_range::<SourceChain>( let mandatory_scan_range = mandatory_headers_scan_range::<P::SourceChain>(
best_finalized_source_header_at_source.ok(), best_finalized_source_header_at_source.ok(),
best_finalized_source_header_at_target.ok(), best_finalized_source_header_at_target.ok(),
maximal_headers_difference, maximal_headers_difference,
@@ -247,8 +216,8 @@ async fn background_task<SourceChain, TargetChain, TargetSign, P>(
finality_target.clone(), finality_target.clone(),
FinalitySyncParams { FinalitySyncParams {
tick: std::cmp::max( tick: std::cmp::max(
SourceChain::AVERAGE_BLOCK_INTERVAL, P::SourceChain::AVERAGE_BLOCK_INTERVAL,
TargetChain::AVERAGE_BLOCK_INTERVAL, P::TargetChain::AVERAGE_BLOCK_INTERVAL,
), ),
recent_finality_proofs_limit: RECENT_FINALITY_PROOFS_LIMIT, recent_finality_proofs_limit: RECENT_FINALITY_PROOFS_LIMIT,
stall_timeout: STALL_TIMEOUT, stall_timeout: STALL_TIMEOUT,
@@ -316,17 +285,13 @@ async fn mandatory_headers_scan_range<C: Chain>(
/// it. /// it.
/// ///
/// Returns `true` if header was found and (asked to be) relayed and `false` otherwise. /// Returns `true` if header was found and (asked to be) relayed and `false` otherwise.
async fn relay_mandatory_header_from_range<SourceChain: Chain, P>( async fn relay_mandatory_header_from_range<P: SubstrateFinalitySyncPipeline>(
finality_source: &SubstrateFinalitySource<SourceChain, P>, finality_source: &SubstrateFinalitySource<P>,
required_header_number: &RequiredHeaderNumberRef<SourceChain>, required_header_number: &RequiredHeaderNumberRef<P::SourceChain>,
best_finalized_source_header_at_target: String, best_finalized_source_header_at_target: String,
range: (SourceChain::BlockNumber, SourceChain::BlockNumber), range: (BlockNumberOf<P::SourceChain>, BlockNumberOf<P::SourceChain>),
relay_task_name: &str, relay_task_name: &str,
) -> Result<bool, relay_substrate_client::Error> ) -> Result<bool, relay_substrate_client::Error> {
where
SubstrateFinalitySource<SourceChain, P>: FinalitySourceClient<P>,
P: FinalitySyncPipeline<Number = SourceChain::BlockNumber>,
{
// search for mandatory header first // search for mandatory header first
let mandatory_source_header_number = let mandatory_source_header_number =
find_mandatory_header_in_range(finality_source, range).await?; find_mandatory_header_in_range(finality_source, range).await?;
@@ -347,7 +312,7 @@ where
log::trace!( log::trace!(
target: "bridge", target: "bridge",
"Too many {} headers missing at target in {} relay ({} vs {}). Going to sync up to the mandatory {}", "Too many {} headers missing at target in {} relay ({} vs {}). Going to sync up to the mandatory {}",
SourceChain::NAME, P::SourceChain::NAME,
relay_task_name, relay_task_name,
best_finalized_source_header_at_target, best_finalized_source_header_at_target,
range.1, range.1,
@@ -361,14 +326,10 @@ where
/// Read best finalized source block number from source client. /// Read best finalized source block number from source client.
/// ///
/// Returns `None` if we have failed to read the number. /// Returns `None` if we have failed to read the number.
async fn best_finalized_source_header_at_source<SourceChain: Chain, P>( async fn best_finalized_source_header_at_source<P: SubstrateFinalitySyncPipeline>(
finality_source: &SubstrateFinalitySource<SourceChain, P>, finality_source: &SubstrateFinalitySource<P>,
relay_task_name: &str, relay_task_name: &str,
) -> Result<SourceChain::BlockNumber, relay_substrate_client::Error> ) -> Result<BlockNumberOf<P::SourceChain>, relay_substrate_client::Error> {
where
SubstrateFinalitySource<SourceChain, P>: FinalitySourceClient<P>,
P: FinalitySyncPipeline<Number = SourceChain::BlockNumber>,
{
finality_source.on_chain_best_finalized_block_number().await.map_err(|error| { finality_source.on_chain_best_finalized_block_number().await.map_err(|error| {
log::error!( log::error!(
target: "bridge", target: "bridge",
@@ -384,14 +345,14 @@ where
/// Read best finalized source block number from target client. /// Read best finalized source block number from target client.
/// ///
/// Returns `None` if we have failed to read the number. /// Returns `None` if we have failed to read the number.
async fn best_finalized_source_header_at_target<SourceChain: Chain, TargetChain: Chain, P>( async fn best_finalized_source_header_at_target<P: SubstrateFinalitySyncPipeline>(
finality_target: &SubstrateFinalityTarget<TargetChain, P>, finality_target: &SubstrateFinalityTarget<P>,
relay_task_name: &str, relay_task_name: &str,
) -> Result<SourceChain::BlockNumber, <SubstrateFinalityTarget<TargetChain, P> as RelayClient>::Error> ) -> Result<BlockNumberOf<P::SourceChain>, <SubstrateFinalityTarget<P> as RelayClient>::Error>
where where
SubstrateFinalityTarget<TargetChain, P>: FinalityTargetClient<P::FinalitySyncPipeline>, AccountIdOf<P::TargetChain>:
P: SubstrateFinalitySyncPipeline, From<<AccountKeyPairOf<P::TransactionSignScheme> as sp_core::Pair>::Public>,
P::FinalitySyncPipeline: FinalitySyncPipeline<Number = SourceChain::BlockNumber>, P::TransactionSignScheme: TransactionSignScheme<Chain = P::TargetChain>,
{ {
finality_target.best_finalized_source_block_number().await.map_err(|error| { finality_target.best_finalized_source_block_number().await.map_err(|error| {
log::error!( log::error!(
@@ -408,17 +369,13 @@ where
/// Read first mandatory header in given inclusive range. /// Read first mandatory header in given inclusive range.
/// ///
/// Returns `Ok(None)` if there were no mandatory headers in the range. /// Returns `Ok(None)` if there were no mandatory headers in the range.
async fn find_mandatory_header_in_range<SourceChain: Chain, P>( async fn find_mandatory_header_in_range<P: SubstrateFinalitySyncPipeline>(
finality_source: &SubstrateFinalitySource<SourceChain, P>, finality_source: &SubstrateFinalitySource<P>,
range: (SourceChain::BlockNumber, SourceChain::BlockNumber), range: (BlockNumberOf<P::SourceChain>, BlockNumberOf<P::SourceChain>),
) -> Result<Option<SourceChain::BlockNumber>, relay_substrate_client::Error> ) -> Result<Option<BlockNumberOf<P::SourceChain>>, relay_substrate_client::Error> {
where
SubstrateFinalitySource<SourceChain, P>: FinalitySourceClient<P>,
P: FinalitySyncPipeline<Number = SourceChain::BlockNumber>,
{
let mut current = range.0; let mut current = range.0;
while current <= range.1 { while current <= range.1 {
let header: SyncHeader<SourceChain::Header> = let header: SyncHeader<HeaderOf<P::SourceChain>> =
finality_source.client().header_by_number(current).await?.into(); finality_source.client().header_by_number(current).await?.into();
if header.is_mandatory() { if header.is_mandatory() {
return Ok(Some(current)) return Ok(Some(current))