mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-05-30 21:01:02 +00:00
FinalityEngine in substrate relay (#1374)
* introduce FinalityEngine in relay code * add FinalityEngine to relay * spelling * fix test compilation * Update relays/lib-substrate-relay/src/finality/source.rs Co-authored-by: Adrian Catangiu <adrian@parity.io> Co-authored-by: Adrian Catangiu <adrian@parity.io>
This commit is contained in:
committed by
Bastian Köcher
parent
6a4144e8f2
commit
b3c8852bcf
@@ -18,7 +18,10 @@
|
|||||||
|
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use relay_polkadot_client::Polkadot;
|
use relay_polkadot_client::Polkadot;
|
||||||
use substrate_relay_helper::{finality_pipeline::SubstrateFinalitySyncPipeline, TransactionParams};
|
use substrate_relay_helper::{
|
||||||
|
finality::{engine::Grandpa as GrandpaFinalityEngine, SubstrateFinalitySyncPipeline},
|
||||||
|
TransactionParams,
|
||||||
|
};
|
||||||
|
|
||||||
/// 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.
|
||||||
@@ -47,6 +50,7 @@ impl SubstrateFinalitySyncPipeline for KusamaFinalityToPolkadot {
|
|||||||
type SourceChain = relay_kusama_client::Kusama;
|
type SourceChain = relay_kusama_client::Kusama;
|
||||||
type TargetChain = Polkadot;
|
type TargetChain = Polkadot;
|
||||||
|
|
||||||
|
type FinalityEngine = GrandpaFinalityEngine<Self::SourceChain>;
|
||||||
type SubmitFinalityProofCallBuilder = KusamaFinalityToPolkadotCallBuilder;
|
type SubmitFinalityProofCallBuilder = KusamaFinalityToPolkadotCallBuilder;
|
||||||
type TransactionSignScheme = Polkadot;
|
type TransactionSignScheme = Polkadot;
|
||||||
|
|
||||||
@@ -55,7 +59,7 @@ impl SubstrateFinalitySyncPipeline for KusamaFinalityToPolkadot {
|
|||||||
transaction_params: &TransactionParams<sp_core::sr25519::Pair>,
|
transaction_params: &TransactionParams<sp_core::sr25519::Pair>,
|
||||||
enable_version_guard: bool,
|
enable_version_guard: bool,
|
||||||
) -> relay_substrate_client::Result<()> {
|
) -> relay_substrate_client::Result<()> {
|
||||||
substrate_relay_helper::finality_guards::start::<Polkadot, Polkadot>(
|
substrate_relay_helper::finality::guards::start::<Polkadot, Polkadot>(
|
||||||
target_client,
|
target_client,
|
||||||
transaction_params,
|
transaction_params,
|
||||||
enable_version_guard,
|
enable_version_guard,
|
||||||
|
|||||||
@@ -16,8 +16,9 @@
|
|||||||
|
|
||||||
//! Millau-to-Rialto headers sync entrypoint.
|
//! Millau-to-Rialto headers sync entrypoint.
|
||||||
|
|
||||||
use substrate_relay_helper::finality_pipeline::{
|
use substrate_relay_helper::finality::{
|
||||||
DirectSubmitFinalityProofCallBuilder, SubstrateFinalitySyncPipeline,
|
engine::Grandpa as GrandpaFinalityEngine, DirectSubmitGrandpaFinalityProofCallBuilder,
|
||||||
|
SubstrateFinalitySyncPipeline,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Description of Millau -> Rialto finalized headers bridge.
|
/// Description of Millau -> Rialto finalized headers bridge.
|
||||||
@@ -28,7 +29,8 @@ impl SubstrateFinalitySyncPipeline for MillauFinalityToRialto {
|
|||||||
type SourceChain = relay_millau_client::Millau;
|
type SourceChain = relay_millau_client::Millau;
|
||||||
type TargetChain = relay_rialto_client::Rialto;
|
type TargetChain = relay_rialto_client::Rialto;
|
||||||
|
|
||||||
type SubmitFinalityProofCallBuilder = DirectSubmitFinalityProofCallBuilder<
|
type FinalityEngine = GrandpaFinalityEngine<Self::SourceChain>;
|
||||||
|
type SubmitFinalityProofCallBuilder = DirectSubmitGrandpaFinalityProofCallBuilder<
|
||||||
Self,
|
Self,
|
||||||
rialto_runtime::Runtime,
|
rialto_runtime::Runtime,
|
||||||
rialto_runtime::MillauGrandpaInstance,
|
rialto_runtime::MillauGrandpaInstance,
|
||||||
|
|||||||
@@ -18,7 +18,10 @@
|
|||||||
|
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use relay_kusama_client::Kusama;
|
use relay_kusama_client::Kusama;
|
||||||
use substrate_relay_helper::{finality_pipeline::SubstrateFinalitySyncPipeline, TransactionParams};
|
use substrate_relay_helper::{
|
||||||
|
finality::{engine::Grandpa as GrandpaFinalityEngine, SubstrateFinalitySyncPipeline},
|
||||||
|
TransactionParams,
|
||||||
|
};
|
||||||
|
|
||||||
/// 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.
|
||||||
@@ -47,6 +50,7 @@ impl SubstrateFinalitySyncPipeline for PolkadotFinalityToKusama {
|
|||||||
type SourceChain = relay_polkadot_client::Polkadot;
|
type SourceChain = relay_polkadot_client::Polkadot;
|
||||||
type TargetChain = Kusama;
|
type TargetChain = Kusama;
|
||||||
|
|
||||||
|
type FinalityEngine = GrandpaFinalityEngine<Self::SourceChain>;
|
||||||
type SubmitFinalityProofCallBuilder = PolkadotFinalityToKusamaCallBuilder;
|
type SubmitFinalityProofCallBuilder = PolkadotFinalityToKusamaCallBuilder;
|
||||||
type TransactionSignScheme = Kusama;
|
type TransactionSignScheme = Kusama;
|
||||||
|
|
||||||
@@ -55,7 +59,7 @@ impl SubstrateFinalitySyncPipeline for PolkadotFinalityToKusama {
|
|||||||
transaction_params: &TransactionParams<sp_core::sr25519::Pair>,
|
transaction_params: &TransactionParams<sp_core::sr25519::Pair>,
|
||||||
enable_version_guard: bool,
|
enable_version_guard: bool,
|
||||||
) -> relay_substrate_client::Result<()> {
|
) -> relay_substrate_client::Result<()> {
|
||||||
substrate_relay_helper::finality_guards::start::<Kusama, Kusama>(
|
substrate_relay_helper::finality::guards::start::<Kusama, Kusama>(
|
||||||
target_client,
|
target_client,
|
||||||
transaction_params,
|
transaction_params,
|
||||||
enable_version_guard,
|
enable_version_guard,
|
||||||
|
|||||||
@@ -16,8 +16,9 @@
|
|||||||
|
|
||||||
//! Rialto-to-Millau headers sync entrypoint.
|
//! Rialto-to-Millau headers sync entrypoint.
|
||||||
|
|
||||||
use substrate_relay_helper::finality_pipeline::{
|
use substrate_relay_helper::finality::{
|
||||||
DirectSubmitFinalityProofCallBuilder, SubstrateFinalitySyncPipeline,
|
engine::Grandpa as GrandpaFinalityEngine, DirectSubmitGrandpaFinalityProofCallBuilder,
|
||||||
|
SubstrateFinalitySyncPipeline,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Description of Millau -> Rialto finalized headers bridge.
|
/// Description of Millau -> Rialto finalized headers bridge.
|
||||||
@@ -28,7 +29,8 @@ impl SubstrateFinalitySyncPipeline for RialtoFinalityToMillau {
|
|||||||
type SourceChain = relay_rialto_client::Rialto;
|
type SourceChain = relay_rialto_client::Rialto;
|
||||||
type TargetChain = relay_millau_client::Millau;
|
type TargetChain = relay_millau_client::Millau;
|
||||||
|
|
||||||
type SubmitFinalityProofCallBuilder = DirectSubmitFinalityProofCallBuilder<
|
type FinalityEngine = GrandpaFinalityEngine<Self::SourceChain>;
|
||||||
|
type SubmitFinalityProofCallBuilder = DirectSubmitGrandpaFinalityProofCallBuilder<
|
||||||
Self,
|
Self,
|
||||||
millau_runtime::Runtime,
|
millau_runtime::Runtime,
|
||||||
millau_runtime::RialtoGrandpaInstance,
|
millau_runtime::RialtoGrandpaInstance,
|
||||||
|
|||||||
@@ -20,7 +20,10 @@ use crate::chains::wococo_headers_to_rococo::MAXIMAL_BALANCE_DECREASE_PER_DAY;
|
|||||||
|
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use relay_wococo_client::Wococo;
|
use relay_wococo_client::Wococo;
|
||||||
use substrate_relay_helper::{finality_pipeline::SubstrateFinalitySyncPipeline, TransactionParams};
|
use substrate_relay_helper::{
|
||||||
|
finality::{engine::Grandpa as GrandpaFinalityEngine, SubstrateFinalitySyncPipeline},
|
||||||
|
TransactionParams,
|
||||||
|
};
|
||||||
|
|
||||||
/// Description of Rococo -> Wococo finalized headers bridge.
|
/// Description of Rococo -> Wococo finalized headers bridge.
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
@@ -37,6 +40,7 @@ impl SubstrateFinalitySyncPipeline for RococoFinalityToWococo {
|
|||||||
type SourceChain = relay_rococo_client::Rococo;
|
type SourceChain = relay_rococo_client::Rococo;
|
||||||
type TargetChain = Wococo;
|
type TargetChain = Wococo;
|
||||||
|
|
||||||
|
type FinalityEngine = GrandpaFinalityEngine<Self::SourceChain>;
|
||||||
type SubmitFinalityProofCallBuilder = RococoFinalityToWococoCallBuilder;
|
type SubmitFinalityProofCallBuilder = RococoFinalityToWococoCallBuilder;
|
||||||
type TransactionSignScheme = Wococo;
|
type TransactionSignScheme = Wococo;
|
||||||
|
|
||||||
@@ -45,7 +49,7 @@ impl SubstrateFinalitySyncPipeline for RococoFinalityToWococo {
|
|||||||
transaction_params: &TransactionParams<sp_core::sr25519::Pair>,
|
transaction_params: &TransactionParams<sp_core::sr25519::Pair>,
|
||||||
enable_version_guard: bool,
|
enable_version_guard: bool,
|
||||||
) -> relay_substrate_client::Result<()> {
|
) -> relay_substrate_client::Result<()> {
|
||||||
substrate_relay_helper::finality_guards::start::<Wococo, Wococo>(
|
substrate_relay_helper::finality::guards::start::<Wococo, Wococo>(
|
||||||
target_client,
|
target_client,
|
||||||
transaction_params,
|
transaction_params,
|
||||||
enable_version_guard,
|
enable_version_guard,
|
||||||
|
|||||||
@@ -16,8 +16,9 @@
|
|||||||
|
|
||||||
//! Westend-to-Millau headers sync entrypoint.
|
//! Westend-to-Millau headers sync entrypoint.
|
||||||
|
|
||||||
use substrate_relay_helper::finality_pipeline::{
|
use substrate_relay_helper::finality::{
|
||||||
DirectSubmitFinalityProofCallBuilder, SubstrateFinalitySyncPipeline,
|
engine::Grandpa as GrandpaFinalityEngine, DirectSubmitGrandpaFinalityProofCallBuilder,
|
||||||
|
SubstrateFinalitySyncPipeline,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Description of Westend -> Millau finalized headers bridge.
|
/// Description of Westend -> Millau finalized headers bridge.
|
||||||
@@ -28,7 +29,8 @@ impl SubstrateFinalitySyncPipeline for WestendFinalityToMillau {
|
|||||||
type SourceChain = relay_westend_client::Westend;
|
type SourceChain = relay_westend_client::Westend;
|
||||||
type TargetChain = relay_millau_client::Millau;
|
type TargetChain = relay_millau_client::Millau;
|
||||||
|
|
||||||
type SubmitFinalityProofCallBuilder = DirectSubmitFinalityProofCallBuilder<
|
type FinalityEngine = GrandpaFinalityEngine<Self::SourceChain>;
|
||||||
|
type SubmitFinalityProofCallBuilder = DirectSubmitGrandpaFinalityProofCallBuilder<
|
||||||
Self,
|
Self,
|
||||||
millau_runtime::Runtime,
|
millau_runtime::Runtime,
|
||||||
millau_runtime::WestendGrandpaInstance,
|
millau_runtime::WestendGrandpaInstance,
|
||||||
|
|||||||
@@ -18,7 +18,10 @@
|
|||||||
|
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use relay_rococo_client::Rococo;
|
use relay_rococo_client::Rococo;
|
||||||
use substrate_relay_helper::{finality_pipeline::SubstrateFinalitySyncPipeline, TransactionParams};
|
use substrate_relay_helper::{
|
||||||
|
finality::{engine::Grandpa as GrandpaFinalityEngine, SubstrateFinalitySyncPipeline},
|
||||||
|
TransactionParams,
|
||||||
|
};
|
||||||
|
|
||||||
/// 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.
|
||||||
@@ -42,6 +45,7 @@ impl SubstrateFinalitySyncPipeline for WococoFinalityToRococo {
|
|||||||
type SourceChain = relay_wococo_client::Wococo;
|
type SourceChain = relay_wococo_client::Wococo;
|
||||||
type TargetChain = Rococo;
|
type TargetChain = Rococo;
|
||||||
|
|
||||||
|
type FinalityEngine = GrandpaFinalityEngine<Self::SourceChain>;
|
||||||
type SubmitFinalityProofCallBuilder = WococoFinalityToRococoCallBuilder;
|
type SubmitFinalityProofCallBuilder = WococoFinalityToRococoCallBuilder;
|
||||||
type TransactionSignScheme = Rococo;
|
type TransactionSignScheme = Rococo;
|
||||||
|
|
||||||
@@ -50,7 +54,7 @@ impl SubstrateFinalitySyncPipeline for WococoFinalityToRococo {
|
|||||||
transaction_params: &TransactionParams<sp_core::sr25519::Pair>,
|
transaction_params: &TransactionParams<sp_core::sr25519::Pair>,
|
||||||
enable_version_guard: bool,
|
enable_version_guard: bool,
|
||||||
) -> relay_substrate_client::Result<()> {
|
) -> relay_substrate_client::Result<()> {
|
||||||
substrate_relay_helper::finality_guards::start::<Rococo, Rococo>(
|
substrate_relay_helper::finality::guards::start::<Rococo, Rococo>(
|
||||||
target_client,
|
target_client,
|
||||||
transaction_params,
|
transaction_params,
|
||||||
enable_version_guard,
|
enable_version_guard,
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ use relay_substrate_client::{Chain, SignParam, TransactionSignScheme, UnsignedTr
|
|||||||
use sp_core::{Bytes, Pair};
|
use sp_core::{Bytes, Pair};
|
||||||
use structopt::StructOpt;
|
use structopt::StructOpt;
|
||||||
use strum::{EnumString, EnumVariantNames, VariantNames};
|
use strum::{EnumString, EnumVariantNames, VariantNames};
|
||||||
|
use substrate_relay_helper::finality::engine::Grandpa as GrandpaFinalityEngine;
|
||||||
|
|
||||||
/// Initialize bridge pallet.
|
/// Initialize bridge pallet.
|
||||||
#[derive(StructOpt)]
|
#[derive(StructOpt)]
|
||||||
@@ -56,6 +57,7 @@ macro_rules! select_bridge {
|
|||||||
InitBridgeName::MillauToRialto => {
|
InitBridgeName::MillauToRialto => {
|
||||||
type Source = relay_millau_client::Millau;
|
type Source = relay_millau_client::Millau;
|
||||||
type Target = relay_rialto_client::Rialto;
|
type Target = relay_rialto_client::Rialto;
|
||||||
|
type Engine = GrandpaFinalityEngine<Source>;
|
||||||
|
|
||||||
fn encode_init_bridge(
|
fn encode_init_bridge(
|
||||||
init_data: InitializationData<<Source as ChainBase>::Header>,
|
init_data: InitializationData<<Source as ChainBase>::Header>,
|
||||||
@@ -74,6 +76,7 @@ macro_rules! select_bridge {
|
|||||||
InitBridgeName::RialtoToMillau => {
|
InitBridgeName::RialtoToMillau => {
|
||||||
type Source = relay_rialto_client::Rialto;
|
type Source = relay_rialto_client::Rialto;
|
||||||
type Target = relay_millau_client::Millau;
|
type Target = relay_millau_client::Millau;
|
||||||
|
type Engine = GrandpaFinalityEngine<Source>;
|
||||||
|
|
||||||
fn encode_init_bridge(
|
fn encode_init_bridge(
|
||||||
init_data: InitializationData<<Source as ChainBase>::Header>,
|
init_data: InitializationData<<Source as ChainBase>::Header>,
|
||||||
@@ -92,6 +95,7 @@ macro_rules! select_bridge {
|
|||||||
InitBridgeName::WestendToMillau => {
|
InitBridgeName::WestendToMillau => {
|
||||||
type Source = relay_westend_client::Westend;
|
type Source = relay_westend_client::Westend;
|
||||||
type Target = relay_millau_client::Millau;
|
type Target = relay_millau_client::Millau;
|
||||||
|
type Engine = GrandpaFinalityEngine<Source>;
|
||||||
|
|
||||||
fn encode_init_bridge(
|
fn encode_init_bridge(
|
||||||
init_data: InitializationData<<Source as ChainBase>::Header>,
|
init_data: InitializationData<<Source as ChainBase>::Header>,
|
||||||
@@ -114,6 +118,7 @@ macro_rules! select_bridge {
|
|||||||
InitBridgeName::RococoToWococo => {
|
InitBridgeName::RococoToWococo => {
|
||||||
type Source = relay_rococo_client::Rococo;
|
type Source = relay_rococo_client::Rococo;
|
||||||
type Target = relay_wococo_client::Wococo;
|
type Target = relay_wococo_client::Wococo;
|
||||||
|
type Engine = GrandpaFinalityEngine<Source>;
|
||||||
|
|
||||||
fn encode_init_bridge(
|
fn encode_init_bridge(
|
||||||
init_data: InitializationData<<Source as ChainBase>::Header>,
|
init_data: InitializationData<<Source as ChainBase>::Header>,
|
||||||
@@ -130,6 +135,7 @@ macro_rules! select_bridge {
|
|||||||
InitBridgeName::WococoToRococo => {
|
InitBridgeName::WococoToRococo => {
|
||||||
type Source = relay_wococo_client::Wococo;
|
type Source = relay_wococo_client::Wococo;
|
||||||
type Target = relay_rococo_client::Rococo;
|
type Target = relay_rococo_client::Rococo;
|
||||||
|
type Engine = GrandpaFinalityEngine<Source>;
|
||||||
|
|
||||||
fn encode_init_bridge(
|
fn encode_init_bridge(
|
||||||
init_data: InitializationData<<Source as ChainBase>::Header>,
|
init_data: InitializationData<<Source as ChainBase>::Header>,
|
||||||
@@ -146,6 +152,7 @@ macro_rules! select_bridge {
|
|||||||
InitBridgeName::KusamaToPolkadot => {
|
InitBridgeName::KusamaToPolkadot => {
|
||||||
type Source = relay_kusama_client::Kusama;
|
type Source = relay_kusama_client::Kusama;
|
||||||
type Target = relay_polkadot_client::Polkadot;
|
type Target = relay_polkadot_client::Polkadot;
|
||||||
|
type Engine = GrandpaFinalityEngine<Source>;
|
||||||
|
|
||||||
fn encode_init_bridge(
|
fn encode_init_bridge(
|
||||||
init_data: InitializationData<<Source as ChainBase>::Header>,
|
init_data: InitializationData<<Source as ChainBase>::Header>,
|
||||||
@@ -162,6 +169,7 @@ macro_rules! select_bridge {
|
|||||||
InitBridgeName::PolkadotToKusama => {
|
InitBridgeName::PolkadotToKusama => {
|
||||||
type Source = relay_polkadot_client::Polkadot;
|
type Source = relay_polkadot_client::Polkadot;
|
||||||
type Target = relay_kusama_client::Kusama;
|
type Target = relay_kusama_client::Kusama;
|
||||||
|
type Engine = GrandpaFinalityEngine<Source>;
|
||||||
|
|
||||||
fn encode_init_bridge(
|
fn encode_init_bridge(
|
||||||
init_data: InitializationData<<Source as ChainBase>::Header>,
|
init_data: InitializationData<<Source as ChainBase>::Header>,
|
||||||
@@ -189,7 +197,7 @@ impl InitBridge {
|
|||||||
|
|
||||||
let (spec_version, transaction_version) =
|
let (spec_version, transaction_version) =
|
||||||
target_client.simple_runtime_version().await?;
|
target_client.simple_runtime_version().await?;
|
||||||
substrate_relay_helper::headers_initialize::initialize(
|
substrate_relay_helper::finality::initialize::initialize::<Engine, _, _, _>(
|
||||||
source_client,
|
source_client,
|
||||||
target_client.clone(),
|
target_client.clone(),
|
||||||
target_sign.public().into(),
|
target_sign.public().into(),
|
||||||
|
|||||||
@@ -24,7 +24,6 @@ use crate::{
|
|||||||
TargetConnectionParams, TargetSigningParams,
|
TargetConnectionParams, TargetSigningParams,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use bp_header_chain::justification::GrandpaJustification;
|
|
||||||
use bp_runtime::Chain;
|
use bp_runtime::Chain;
|
||||||
use codec::Encode;
|
use codec::Encode;
|
||||||
use finality_relay::{SourceClient, SourceHeader};
|
use finality_relay::{SourceClient, SourceHeader};
|
||||||
@@ -40,8 +39,12 @@ use std::convert::{TryFrom, TryInto};
|
|||||||
use structopt::StructOpt;
|
use structopt::StructOpt;
|
||||||
use strum::{EnumString, EnumVariantNames, VariantNames};
|
use strum::{EnumString, EnumVariantNames, VariantNames};
|
||||||
use substrate_relay_helper::{
|
use substrate_relay_helper::{
|
||||||
finality_pipeline::SubstrateFinalitySyncPipeline, finality_source::SubstrateFinalitySource,
|
finality::{
|
||||||
finality_target::SubstrateFinalityTarget, messages_source::read_client_state,
|
source::{SubstrateFinalityProof, SubstrateFinalitySource},
|
||||||
|
target::SubstrateFinalityTarget,
|
||||||
|
SubstrateFinalitySyncPipeline,
|
||||||
|
},
|
||||||
|
messages_source::read_client_state,
|
||||||
TransactionParams,
|
TransactionParams,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -299,7 +302,7 @@ impl ReinitBridge {
|
|||||||
/// Mandatory header and its finality proof.
|
/// Mandatory header and its finality proof.
|
||||||
type HeaderAndProof<P> = (
|
type HeaderAndProof<P> = (
|
||||||
SyncHeader<HeaderOf<<P as SubstrateFinalitySyncPipeline>::SourceChain>>,
|
SyncHeader<HeaderOf<<P as SubstrateFinalitySyncPipeline>::SourceChain>>,
|
||||||
GrandpaJustification<HeaderOf<<P as SubstrateFinalitySyncPipeline>::SourceChain>>,
|
SubstrateFinalityProof<P>,
|
||||||
);
|
);
|
||||||
/// Vector of mandatory headers and their finality proofs.
|
/// Vector of mandatory headers and their finality proofs.
|
||||||
type HeadersAndProofs<P> = Vec<HeaderAndProof<P>>;
|
type HeadersAndProofs<P> = Vec<HeaderAndProof<P>>;
|
||||||
@@ -425,6 +428,7 @@ fn make_mandatory_headers_batches<
|
|||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::cli::{RuntimeVersionType, SourceRuntimeVersionParams, TargetRuntimeVersionParams};
|
use crate::cli::{RuntimeVersionType, SourceRuntimeVersionParams, TargetRuntimeVersionParams};
|
||||||
|
use bp_header_chain::justification::GrandpaJustification;
|
||||||
use bp_test_utils::{make_default_justification, test_header};
|
use bp_test_utils::{make_default_justification, test_header};
|
||||||
use relay_polkadot_client::Polkadot;
|
use relay_polkadot_client::Polkadot;
|
||||||
use sp_runtime::{traits::Header as _, DigestItem};
|
use sp_runtime::{traits::Header as _, DigestItem};
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ use structopt::StructOpt;
|
|||||||
use strum::{EnumString, EnumVariantNames, VariantNames};
|
use strum::{EnumString, EnumVariantNames, VariantNames};
|
||||||
|
|
||||||
use relay_utils::metrics::{GlobalMetrics, StandaloneMetric};
|
use relay_utils::metrics::{GlobalMetrics, StandaloneMetric};
|
||||||
use substrate_relay_helper::finality_pipeline::SubstrateFinalitySyncPipeline;
|
use substrate_relay_helper::finality::SubstrateFinalitySyncPipeline;
|
||||||
|
|
||||||
use crate::cli::{
|
use crate::cli::{
|
||||||
PrometheusParams, SourceConnectionParams, TargetConnectionParams, TargetSigningParams,
|
PrometheusParams, SourceConnectionParams, TargetConnectionParams, TargetSigningParams,
|
||||||
@@ -136,7 +136,7 @@ impl RelayHeaders {
|
|||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
substrate_relay_helper::finality_pipeline::run::<Finality>(
|
substrate_relay_helper::finality::run::<Finality>(
|
||||||
source_client,
|
source_client,
|
||||||
target_client,
|
target_client,
|
||||||
self.only_mandatory_headers,
|
self.only_mandatory_headers,
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ use relay_substrate_client::{
|
|||||||
use relay_utils::metrics::MetricsParams;
|
use relay_utils::metrics::MetricsParams;
|
||||||
use sp_core::{Bytes, Pair};
|
use sp_core::{Bytes, Pair};
|
||||||
use substrate_relay_helper::{
|
use substrate_relay_helper::{
|
||||||
finality_pipeline::SubstrateFinalitySyncPipeline, messages_lane::MessagesRelayParams,
|
finality::SubstrateFinalitySyncPipeline, messages_lane::MessagesRelayParams,
|
||||||
on_demand_headers::OnDemandHeadersRelay, TransactionParams,
|
on_demand_headers::OnDemandHeadersRelay, TransactionParams,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -704,8 +704,8 @@ impl<C: Chain> Client<C> {
|
|||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return new justifications stream.
|
/// Return new GRANDPA justifications stream.
|
||||||
pub async fn subscribe_justifications(&self) -> Result<Subscription<Bytes>> {
|
pub async fn subscribe_grandpa_justifications(&self) -> Result<Subscription<Bytes>> {
|
||||||
let subscription = self
|
let subscription = self
|
||||||
.jsonrpsee_execute(move |client| async move {
|
.jsonrpsee_execute(move |client| async move {
|
||||||
Ok(client
|
Ok(client
|
||||||
|
|||||||
@@ -45,9 +45,9 @@ pub enum Error {
|
|||||||
/// Account does not exist on the chain.
|
/// Account does not exist on the chain.
|
||||||
#[error("Account does not exist on the chain.")]
|
#[error("Account does not exist on the chain.")]
|
||||||
AccountDoesNotExist,
|
AccountDoesNotExist,
|
||||||
/// Runtime storage is missing mandatory ":code:" entry.
|
/// Runtime storage is missing some mandatory value.
|
||||||
#[error("Mandatory :code: entry is missing from runtime storage.")]
|
#[error("Mandatory storage value is missing from the runtime storage.")]
|
||||||
MissingMandatoryCodeEntry,
|
MissingMandatoryStorageValue,
|
||||||
/// The client we're connected to is not synced, so we can't rely on its state.
|
/// The client we're connected to is not synced, so we can't rely on its state.
|
||||||
#[error("Substrate client is not synced {0}.")]
|
#[error("Substrate client is not synced {0}.")]
|
||||||
ClientNotSynced(Health),
|
ClientNotSynced(Health),
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ impl<C: Chain> StorageProofOverheadMetric<C> {
|
|||||||
let maybe_encoded_storage_value =
|
let maybe_encoded_storage_value =
|
||||||
storage_value_reader.read_value(CODE).map_err(Error::StorageProofError)?;
|
storage_value_reader.read_value(CODE).map_err(Error::StorageProofError)?;
|
||||||
let encoded_storage_value_size =
|
let encoded_storage_value_size =
|
||||||
maybe_encoded_storage_value.ok_or(Error::MissingMandatoryCodeEntry)?.len();
|
maybe_encoded_storage_value.ok_or(Error::MissingMandatoryStorageValue)?.len();
|
||||||
|
|
||||||
Ok(storage_proof_size - encoded_storage_value_size)
|
Ok(storage_proof_size - encoded_storage_value_size)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,226 @@
|
|||||||
|
// Copyright 2019-2021 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity Bridges Common.
|
||||||
|
|
||||||
|
// Parity Bridges Common is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity Bridges Common is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// 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/>.
|
||||||
|
|
||||||
|
//! Support of different finality engines, available in Substrate.
|
||||||
|
|
||||||
|
use crate::error::Error;
|
||||||
|
use async_trait::async_trait;
|
||||||
|
use bp_header_chain::{
|
||||||
|
find_grandpa_authorities_scheduled_change,
|
||||||
|
justification::{verify_justification, GrandpaJustification},
|
||||||
|
FinalityProof,
|
||||||
|
};
|
||||||
|
use codec::{Decode, Encode};
|
||||||
|
use finality_grandpa::voter_set::VoterSet;
|
||||||
|
use num_traits::{One, Zero};
|
||||||
|
use relay_substrate_client::{
|
||||||
|
BlockNumberOf, Chain, ChainWithGrandpa, Client, Error as SubstrateError, HashOf, HeaderOf,
|
||||||
|
Subscription,
|
||||||
|
};
|
||||||
|
use sp_core::{storage::StorageKey, Bytes};
|
||||||
|
use sp_finality_grandpa::AuthorityList as GrandpaAuthoritiesSet;
|
||||||
|
use sp_runtime::{traits::Header, ConsensusEngineId};
|
||||||
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
|
/// Finality enfine, used by the Substrate chain.
|
||||||
|
#[async_trait]
|
||||||
|
pub trait Engine<C: Chain> {
|
||||||
|
/// Unique consensus engine identifier.
|
||||||
|
const ID: ConsensusEngineId;
|
||||||
|
/// Type of finality proofs, used by consensus engine.
|
||||||
|
type FinalityProof: FinalityProof<BlockNumberOf<C>> + Decode + Encode;
|
||||||
|
/// Type of bridge pallet initialization data.
|
||||||
|
type InitializationData: std::fmt::Debug + Send + Sync + 'static;
|
||||||
|
|
||||||
|
/// Returns storage key at the bridged (target) chain that corresponds to the `bool` value,
|
||||||
|
/// which is true when the bridge pallet is halted.
|
||||||
|
fn is_halted_key() -> StorageKey;
|
||||||
|
/// Returns storage at the bridged (target) chain that corresponds to some value that is
|
||||||
|
/// missing from the storage until bridge pallet is initialized.
|
||||||
|
///
|
||||||
|
/// Note that we don't care about type of the value - just if it present or not.
|
||||||
|
fn is_initialized_key() -> StorageKey;
|
||||||
|
/// A method to subscribe to encoded finality proofs, given source client.
|
||||||
|
async fn finality_proofs(client: Client<C>) -> Result<Subscription<Bytes>, SubstrateError>;
|
||||||
|
/// Prepare initialization data for the finality bridge pallet.
|
||||||
|
async fn prepare_initialization_data(
|
||||||
|
client: Client<C>,
|
||||||
|
) -> Result<Self::InitializationData, Error<HashOf<C>, BlockNumberOf<C>>>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// GRANDPA finality engine.
|
||||||
|
pub struct Grandpa<C>(PhantomData<C>);
|
||||||
|
|
||||||
|
impl<C: ChainWithGrandpa> Grandpa<C> {
|
||||||
|
/// Read header by hash from the source client.
|
||||||
|
async fn source_header(
|
||||||
|
source_client: &Client<C>,
|
||||||
|
header_hash: C::Hash,
|
||||||
|
) -> Result<C::Header, Error<HashOf<C>, BlockNumberOf<C>>> {
|
||||||
|
source_client
|
||||||
|
.header_by_hash(header_hash)
|
||||||
|
.await
|
||||||
|
.map_err(|err| Error::RetrieveHeader(C::NAME, header_hash, err))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Read GRANDPA authorities set at given header.
|
||||||
|
async fn source_authorities_set(
|
||||||
|
source_client: &Client<C>,
|
||||||
|
header_hash: C::Hash,
|
||||||
|
) -> Result<GrandpaAuthoritiesSet, Error<HashOf<C>, BlockNumberOf<C>>> {
|
||||||
|
let raw_authorities_set = source_client
|
||||||
|
.grandpa_authorities_set(header_hash)
|
||||||
|
.await
|
||||||
|
.map_err(|err| Error::RetrieveAuthorities(C::NAME, header_hash, err))?;
|
||||||
|
GrandpaAuthoritiesSet::decode(&mut &raw_authorities_set[..])
|
||||||
|
.map_err(|err| Error::DecodeAuthorities(C::NAME, header_hash, err))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
impl<C: ChainWithGrandpa> Engine<C> for Grandpa<C> {
|
||||||
|
const ID: ConsensusEngineId = sp_finality_grandpa::GRANDPA_ENGINE_ID;
|
||||||
|
type FinalityProof = GrandpaJustification<HeaderOf<C>>;
|
||||||
|
type InitializationData = bp_header_chain::InitializationData<C::Header>;
|
||||||
|
|
||||||
|
fn is_halted_key() -> StorageKey {
|
||||||
|
bp_header_chain::storage_keys::is_halted_key(C::WITH_CHAIN_GRANDPA_PALLET_NAME)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_initialized_key() -> StorageKey {
|
||||||
|
bp_header_chain::storage_keys::best_finalized_hash_key(C::WITH_CHAIN_GRANDPA_PALLET_NAME)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn finality_proofs(client: Client<C>) -> Result<Subscription<Bytes>, SubstrateError> {
|
||||||
|
client.subscribe_grandpa_justifications().await
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Prepare initialization data for the GRANDPA verifier pallet.
|
||||||
|
async fn prepare_initialization_data(
|
||||||
|
source_client: Client<C>,
|
||||||
|
) -> Result<Self::InitializationData, Error<HashOf<C>, BlockNumberOf<C>>> {
|
||||||
|
// In ideal world we just need to get best finalized header and then to read GRANDPA
|
||||||
|
// authorities set (`pallet_grandpa::CurrentSetId` + `GrandpaApi::grandpa_authorities()`) at
|
||||||
|
// this header.
|
||||||
|
//
|
||||||
|
// But now there are problems with this approach - `CurrentSetId` may return invalid value.
|
||||||
|
// So here we're waiting for the next justification, read the authorities set and then try
|
||||||
|
// to figure out the set id with bruteforce.
|
||||||
|
let justifications = source_client
|
||||||
|
.subscribe_grandpa_justifications()
|
||||||
|
.await
|
||||||
|
.map_err(|err| Error::Subscribe(C::NAME, err))?;
|
||||||
|
// Read next justification - the header that it finalizes will be used as initial header.
|
||||||
|
let justification = justifications
|
||||||
|
.next()
|
||||||
|
.await
|
||||||
|
.map_err(|e| Error::ReadJustification(C::NAME, e))
|
||||||
|
.and_then(|justification| {
|
||||||
|
justification.ok_or(Error::ReadJustificationStreamEnded(C::NAME))
|
||||||
|
})?;
|
||||||
|
|
||||||
|
// Read initial header.
|
||||||
|
let justification: GrandpaJustification<C::Header> =
|
||||||
|
Decode::decode(&mut &justification.0[..])
|
||||||
|
.map_err(|err| Error::DecodeJustification(C::NAME, err))?;
|
||||||
|
|
||||||
|
let (initial_header_hash, initial_header_number) =
|
||||||
|
(justification.commit.target_hash, justification.commit.target_number);
|
||||||
|
|
||||||
|
let initial_header = Self::source_header(&source_client, initial_header_hash).await?;
|
||||||
|
log::trace!(target: "bridge", "Selected {} initial header: {}/{}",
|
||||||
|
C::NAME,
|
||||||
|
initial_header_number,
|
||||||
|
initial_header_hash,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Read GRANDPA authorities set at initial header.
|
||||||
|
let initial_authorities_set =
|
||||||
|
Self::source_authorities_set(&source_client, initial_header_hash).await?;
|
||||||
|
log::trace!(target: "bridge", "Selected {} initial authorities set: {:?}",
|
||||||
|
C::NAME,
|
||||||
|
initial_authorities_set,
|
||||||
|
);
|
||||||
|
|
||||||
|
// If initial header changes the GRANDPA authorities set, then we need previous authorities
|
||||||
|
// to verify justification.
|
||||||
|
let mut authorities_for_verification = initial_authorities_set.clone();
|
||||||
|
let scheduled_change = find_grandpa_authorities_scheduled_change(&initial_header);
|
||||||
|
assert!(
|
||||||
|
scheduled_change.as_ref().map(|c| c.delay.is_zero()).unwrap_or(true),
|
||||||
|
"GRANDPA authorities change at {} scheduled to happen in {:?} blocks. We expect\
|
||||||
|
regular hange to have zero delay",
|
||||||
|
initial_header_hash,
|
||||||
|
scheduled_change.as_ref().map(|c| c.delay),
|
||||||
|
);
|
||||||
|
let schedules_change = scheduled_change.is_some();
|
||||||
|
if schedules_change {
|
||||||
|
authorities_for_verification =
|
||||||
|
Self::source_authorities_set(&source_client, *initial_header.parent_hash()).await?;
|
||||||
|
log::trace!(
|
||||||
|
target: "bridge",
|
||||||
|
"Selected {} header is scheduling GRANDPA authorities set changes. Using previous set: {:?}",
|
||||||
|
C::NAME,
|
||||||
|
authorities_for_verification,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now let's try to guess authorities set id by verifying justification.
|
||||||
|
let mut initial_authorities_set_id = 0;
|
||||||
|
let mut min_possible_block_number = C::BlockNumber::zero();
|
||||||
|
let authorities_for_verification = VoterSet::new(authorities_for_verification.clone())
|
||||||
|
.ok_or(Error::ReadInvalidAuthorities(C::NAME, authorities_for_verification))?;
|
||||||
|
loop {
|
||||||
|
log::trace!(
|
||||||
|
target: "bridge", "Trying {} GRANDPA authorities set id: {}",
|
||||||
|
C::NAME,
|
||||||
|
initial_authorities_set_id,
|
||||||
|
);
|
||||||
|
|
||||||
|
let is_valid_set_id = verify_justification::<C::Header>(
|
||||||
|
(initial_header_hash, initial_header_number),
|
||||||
|
initial_authorities_set_id,
|
||||||
|
&authorities_for_verification,
|
||||||
|
&justification,
|
||||||
|
)
|
||||||
|
.is_ok();
|
||||||
|
|
||||||
|
if is_valid_set_id {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
initial_authorities_set_id += 1;
|
||||||
|
min_possible_block_number += One::one();
|
||||||
|
if min_possible_block_number > initial_header_number {
|
||||||
|
// there can't be more authorities set changes than headers => if we have reached
|
||||||
|
// `initial_block_number` and still have not found correct value of
|
||||||
|
// `initial_authorities_set_id`, then something else is broken => fail
|
||||||
|
return Err(Error::GuessInitialAuthorities(C::NAME, initial_header_number))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(bp_header_chain::InitializationData {
|
||||||
|
header: Box::new(initial_header),
|
||||||
|
authority_list: initial_authorities_set,
|
||||||
|
set_id: if schedules_change {
|
||||||
|
initial_authorities_set_id + 1
|
||||||
|
} else {
|
||||||
|
initial_authorities_set_id
|
||||||
|
},
|
||||||
|
is_halted: false,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,121 @@
|
|||||||
|
// Copyright 2019-2021 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity Bridges Common.
|
||||||
|
|
||||||
|
// Parity Bridges Common is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity Bridges Common is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// 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/>.
|
||||||
|
|
||||||
|
//! Initialize Substrate -> Substrate finality bridge.
|
||||||
|
//!
|
||||||
|
//! Initialization is a transaction that calls `initialize()` function of the
|
||||||
|
//! finality pallet (GRANDPA/BEEFY/...). This transaction brings initial header
|
||||||
|
//! and authorities set from source to target chain. The finality sync starts
|
||||||
|
//! with this header.
|
||||||
|
|
||||||
|
use crate::{error::Error, finality::engine::Engine};
|
||||||
|
|
||||||
|
use relay_substrate_client::{BlockNumberOf, Chain, Client, Error as SubstrateError, HashOf};
|
||||||
|
use sp_core::Bytes;
|
||||||
|
use sp_runtime::traits::Header as HeaderT;
|
||||||
|
|
||||||
|
/// Submit headers-bridge initialization transaction.
|
||||||
|
pub async fn initialize<E: Engine<SourceChain>, SourceChain: Chain, TargetChain: Chain, F>(
|
||||||
|
source_client: Client<SourceChain>,
|
||||||
|
target_client: Client<TargetChain>,
|
||||||
|
target_transactions_signer: TargetChain::AccountId,
|
||||||
|
prepare_initialize_transaction: F,
|
||||||
|
) where
|
||||||
|
F: FnOnce(TargetChain::Index, E::InitializationData) -> Result<Bytes, SubstrateError>
|
||||||
|
+ Send
|
||||||
|
+ 'static,
|
||||||
|
{
|
||||||
|
let result = do_initialize::<E, _, _, _>(
|
||||||
|
source_client,
|
||||||
|
target_client,
|
||||||
|
target_transactions_signer,
|
||||||
|
prepare_initialize_transaction,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
match result {
|
||||||
|
Ok(Some(tx_hash)) => log::info!(
|
||||||
|
target: "bridge",
|
||||||
|
"Successfully submitted {}-headers bridge initialization transaction to {}: {:?}",
|
||||||
|
SourceChain::NAME,
|
||||||
|
TargetChain::NAME,
|
||||||
|
tx_hash,
|
||||||
|
),
|
||||||
|
Ok(None) => (),
|
||||||
|
Err(err) => log::error!(
|
||||||
|
target: "bridge",
|
||||||
|
"Failed to submit {}-headers bridge initialization transaction to {}: {:?}",
|
||||||
|
SourceChain::NAME,
|
||||||
|
TargetChain::NAME,
|
||||||
|
err,
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Craft and submit initialization transaction, returning any error that may occur.
|
||||||
|
async fn do_initialize<E: Engine<SourceChain>, SourceChain: Chain, TargetChain: Chain, F>(
|
||||||
|
source_client: Client<SourceChain>,
|
||||||
|
target_client: Client<TargetChain>,
|
||||||
|
target_transactions_signer: TargetChain::AccountId,
|
||||||
|
prepare_initialize_transaction: F,
|
||||||
|
) -> Result<
|
||||||
|
Option<TargetChain::Hash>,
|
||||||
|
Error<SourceChain::Hash, <SourceChain::Header as HeaderT>::Number>,
|
||||||
|
>
|
||||||
|
where
|
||||||
|
F: FnOnce(TargetChain::Index, E::InitializationData) -> Result<Bytes, SubstrateError>
|
||||||
|
+ Send
|
||||||
|
+ 'static,
|
||||||
|
{
|
||||||
|
let is_initialized = is_initialized::<E, SourceChain, TargetChain>(&target_client).await?;
|
||||||
|
if is_initialized {
|
||||||
|
log::info!(
|
||||||
|
target: "bridge",
|
||||||
|
"{}-headers bridge at {} is already initialized. Skipping",
|
||||||
|
SourceChain::NAME,
|
||||||
|
TargetChain::NAME,
|
||||||
|
);
|
||||||
|
return Ok(None)
|
||||||
|
}
|
||||||
|
|
||||||
|
let initialization_data = E::prepare_initialization_data(source_client).await?;
|
||||||
|
log::info!(
|
||||||
|
target: "bridge",
|
||||||
|
"Prepared initialization data for {}-headers bridge at {}: {:?}",
|
||||||
|
SourceChain::NAME,
|
||||||
|
TargetChain::NAME,
|
||||||
|
initialization_data,
|
||||||
|
);
|
||||||
|
|
||||||
|
let initialization_tx_hash = target_client
|
||||||
|
.submit_signed_extrinsic(target_transactions_signer, move |_, transaction_nonce| {
|
||||||
|
prepare_initialize_transaction(transaction_nonce, initialization_data)
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
.map_err(|err| Error::SubmitTransaction(TargetChain::NAME, err))?;
|
||||||
|
Ok(Some(initialization_tx_hash))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns `Ok(true)` if bridge has already been initialized.
|
||||||
|
async fn is_initialized<E: Engine<SourceChain>, SourceChain: Chain, TargetChain: Chain>(
|
||||||
|
target_client: &Client<TargetChain>,
|
||||||
|
) -> Result<bool, Error<HashOf<SourceChain>, BlockNumberOf<SourceChain>>> {
|
||||||
|
Ok(target_client
|
||||||
|
.raw_storage_value(E::is_initialized_key(), None)
|
||||||
|
.await
|
||||||
|
.map_err(|err| Error::RetrieveBestFinalizedHeaderHash(SourceChain::NAME, err))?
|
||||||
|
.is_some())
|
||||||
|
}
|
||||||
+27
-12
@@ -18,7 +18,11 @@
|
|||||||
//! finality proofs synchronization pipelines.
|
//! finality proofs synchronization pipelines.
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
finality_source::SubstrateFinalitySource, finality_target::SubstrateFinalityTarget,
|
finality::{
|
||||||
|
engine::Engine,
|
||||||
|
source::{SubstrateFinalityProof, SubstrateFinalitySource},
|
||||||
|
target::SubstrateFinalityTarget,
|
||||||
|
},
|
||||||
TransactionParams,
|
TransactionParams,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -27,13 +31,19 @@ use bp_header_chain::justification::GrandpaJustification;
|
|||||||
use finality_relay::FinalitySyncPipeline;
|
use finality_relay::FinalitySyncPipeline;
|
||||||
use pallet_bridge_grandpa::{Call as BridgeGrandpaCall, Config as BridgeGrandpaConfig};
|
use pallet_bridge_grandpa::{Call as BridgeGrandpaCall, Config as BridgeGrandpaConfig};
|
||||||
use relay_substrate_client::{
|
use relay_substrate_client::{
|
||||||
transaction_stall_timeout, AccountIdOf, AccountKeyPairOf, BlockNumberOf, CallOf, Chain,
|
transaction_stall_timeout, AccountIdOf, AccountKeyPairOf, BlockNumberOf, CallOf, Chain, Client,
|
||||||
ChainWithGrandpa, Client, HashOf, HeaderOf, SyncHeader, TransactionSignScheme,
|
HashOf, HeaderOf, SyncHeader, TransactionSignScheme,
|
||||||
};
|
};
|
||||||
use relay_utils::metrics::MetricsParams;
|
use relay_utils::metrics::MetricsParams;
|
||||||
use sp_core::Pair;
|
use sp_core::Pair;
|
||||||
use std::{fmt::Debug, marker::PhantomData};
|
use std::{fmt::Debug, marker::PhantomData};
|
||||||
|
|
||||||
|
pub mod engine;
|
||||||
|
pub mod guards;
|
||||||
|
pub mod initialize;
|
||||||
|
pub mod source;
|
||||||
|
pub mod target;
|
||||||
|
|
||||||
/// Default limit of recent finality proofs.
|
/// Default limit of recent finality proofs.
|
||||||
///
|
///
|
||||||
/// Finality delay of 4096 blocks is unlikely to happen in practice in
|
/// Finality delay of 4096 blocks is unlikely to happen in practice in
|
||||||
@@ -44,10 +54,12 @@ pub(crate) const RECENT_FINALITY_PROOFS_LIMIT: usize = 4096;
|
|||||||
#[async_trait]
|
#[async_trait]
|
||||||
pub trait SubstrateFinalitySyncPipeline: 'static + Clone + Debug + Send + Sync {
|
pub trait SubstrateFinalitySyncPipeline: 'static + Clone + Debug + Send + Sync {
|
||||||
/// Headers of this chain are submitted to the `TargetChain`.
|
/// Headers of this chain are submitted to the `TargetChain`.
|
||||||
type SourceChain: ChainWithGrandpa;
|
type SourceChain: Chain;
|
||||||
/// Headers of the `SourceChain` are submitted to this chain.
|
/// Headers of the `SourceChain` are submitted to this chain.
|
||||||
type TargetChain: Chain;
|
type TargetChain: Chain;
|
||||||
|
|
||||||
|
/// Finality engine.
|
||||||
|
type FinalityEngine: Engine<Self::SourceChain>;
|
||||||
/// How submit finality proof call is built?
|
/// How submit finality proof call is built?
|
||||||
type SubmitFinalityProofCallBuilder: SubmitFinalityProofCallBuilder<Self>;
|
type SubmitFinalityProofCallBuilder: SubmitFinalityProofCallBuilder<Self>;
|
||||||
/// Scheme used to sign target chain transactions.
|
/// Scheme used to sign target chain transactions.
|
||||||
@@ -76,7 +88,7 @@ impl<P: SubstrateFinalitySyncPipeline> FinalitySyncPipeline for FinalitySyncPipe
|
|||||||
type Hash = HashOf<P::SourceChain>;
|
type Hash = HashOf<P::SourceChain>;
|
||||||
type Number = BlockNumberOf<P::SourceChain>;
|
type Number = BlockNumberOf<P::SourceChain>;
|
||||||
type Header = relay_substrate_client::SyncHeader<HeaderOf<P::SourceChain>>;
|
type Header = relay_substrate_client::SyncHeader<HeaderOf<P::SourceChain>>;
|
||||||
type FinalityProof = GrandpaJustification<HeaderOf<P::SourceChain>>;
|
type FinalityProof = SubstrateFinalityProof<P>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Different ways of building `submit_finality_proof` calls.
|
/// Different ways of building `submit_finality_proof` calls.
|
||||||
@@ -85,23 +97,26 @@ pub trait SubmitFinalityProofCallBuilder<P: SubstrateFinalitySyncPipeline> {
|
|||||||
/// function of bridge GRANDPA module at the target chain.
|
/// function of bridge GRANDPA module at the target chain.
|
||||||
fn build_submit_finality_proof_call(
|
fn build_submit_finality_proof_call(
|
||||||
header: SyncHeader<HeaderOf<P::SourceChain>>,
|
header: SyncHeader<HeaderOf<P::SourceChain>>,
|
||||||
proof: GrandpaJustification<HeaderOf<P::SourceChain>>,
|
proof: SubstrateFinalityProof<P>,
|
||||||
) -> CallOf<P::TargetChain>;
|
) -> CallOf<P::TargetChain>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Building `submit_finality_proof` call when you have direct access to the target
|
/// Building `submit_finality_proof` call when you have direct access to the target
|
||||||
/// chain runtime.
|
/// chain runtime.
|
||||||
pub struct DirectSubmitFinalityProofCallBuilder<P, R, I> {
|
pub struct DirectSubmitGrandpaFinalityProofCallBuilder<P, R, I> {
|
||||||
_phantom: PhantomData<(P, R, I)>,
|
_phantom: PhantomData<(P, R, I)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<P, R, I> SubmitFinalityProofCallBuilder<P> for DirectSubmitFinalityProofCallBuilder<P, R, I>
|
impl<P, R, I> SubmitFinalityProofCallBuilder<P>
|
||||||
|
for DirectSubmitGrandpaFinalityProofCallBuilder<P, R, I>
|
||||||
where
|
where
|
||||||
P: SubstrateFinalitySyncPipeline,
|
P: SubstrateFinalitySyncPipeline,
|
||||||
R: BridgeGrandpaConfig<I>,
|
R: BridgeGrandpaConfig<I>,
|
||||||
I: 'static,
|
I: 'static,
|
||||||
R::BridgedChain: bp_runtime::Chain<Header = HeaderOf<P::SourceChain>>,
|
R::BridgedChain: bp_runtime::Chain<Header = HeaderOf<P::SourceChain>>,
|
||||||
CallOf<P::TargetChain>: From<BridgeGrandpaCall<R, I>>,
|
CallOf<P::TargetChain>: From<BridgeGrandpaCall<R, I>>,
|
||||||
|
P::FinalityEngine:
|
||||||
|
Engine<P::SourceChain, FinalityProof = GrandpaJustification<HeaderOf<P::SourceChain>>>,
|
||||||
{
|
{
|
||||||
fn build_submit_finality_proof_call(
|
fn build_submit_finality_proof_call(
|
||||||
header: SyncHeader<HeaderOf<P::SourceChain>>,
|
header: SyncHeader<HeaderOf<P::SourceChain>>,
|
||||||
@@ -125,22 +140,22 @@ macro_rules! generate_mocked_submit_finality_proof_call_builder {
|
|||||||
($pipeline:ident, $mocked_builder:ident, $bridge_grandpa:path, $submit_finality_proof:path) => {
|
($pipeline:ident, $mocked_builder:ident, $bridge_grandpa:path, $submit_finality_proof:path) => {
|
||||||
pub struct $mocked_builder;
|
pub struct $mocked_builder;
|
||||||
|
|
||||||
impl $crate::finality_pipeline::SubmitFinalityProofCallBuilder<$pipeline>
|
impl $crate::finality::SubmitFinalityProofCallBuilder<$pipeline>
|
||||||
for $mocked_builder
|
for $mocked_builder
|
||||||
{
|
{
|
||||||
fn build_submit_finality_proof_call(
|
fn build_submit_finality_proof_call(
|
||||||
header: relay_substrate_client::SyncHeader<
|
header: relay_substrate_client::SyncHeader<
|
||||||
relay_substrate_client::HeaderOf<
|
relay_substrate_client::HeaderOf<
|
||||||
<$pipeline as $crate::finality_pipeline::SubstrateFinalitySyncPipeline>::SourceChain
|
<$pipeline as $crate::finality::SubstrateFinalitySyncPipeline>::SourceChain
|
||||||
>
|
>
|
||||||
>,
|
>,
|
||||||
proof: bp_header_chain::justification::GrandpaJustification<
|
proof: bp_header_chain::justification::GrandpaJustification<
|
||||||
relay_substrate_client::HeaderOf<
|
relay_substrate_client::HeaderOf<
|
||||||
<$pipeline as $crate::finality_pipeline::SubstrateFinalitySyncPipeline>::SourceChain
|
<$pipeline as $crate::finality::SubstrateFinalitySyncPipeline>::SourceChain
|
||||||
>
|
>
|
||||||
>,
|
>,
|
||||||
) -> relay_substrate_client::CallOf<
|
) -> relay_substrate_client::CallOf<
|
||||||
<$pipeline as $crate::finality_pipeline::SubstrateFinalitySyncPipeline>::TargetChain
|
<$pipeline as $crate::finality::SubstrateFinalitySyncPipeline>::TargetChain
|
||||||
> {
|
> {
|
||||||
$bridge_grandpa($submit_finality_proof(Box::new(header.into_inner()), proof))
|
$bridge_grandpa($submit_finality_proof(Box::new(header.into_inner()), proof))
|
||||||
}
|
}
|
||||||
+14
-11
@@ -16,11 +16,10 @@
|
|||||||
|
|
||||||
//! Default generic implementation of finality source for basic Substrate client.
|
//! Default generic implementation of finality source for basic Substrate client.
|
||||||
|
|
||||||
use crate::finality_pipeline::{FinalitySyncPipelineAdapter, SubstrateFinalitySyncPipeline};
|
use crate::finality::{engine::Engine, FinalitySyncPipelineAdapter, SubstrateFinalitySyncPipeline};
|
||||||
|
|
||||||
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 codec::Decode;
|
use codec::Decode;
|
||||||
use finality_relay::SourceClient;
|
use finality_relay::SourceClient;
|
||||||
use futures::stream::{unfold, Stream, StreamExt};
|
use futures::stream::{unfold, Stream, StreamExt};
|
||||||
@@ -38,13 +37,19 @@ pub type RequiredHeaderNumberRef<C> = Arc<Mutex<<C as bp_runtime::Chain>::BlockN
|
|||||||
pub type SubstrateFinalityProofsStream<P> = Pin<
|
pub type SubstrateFinalityProofsStream<P> = Pin<
|
||||||
Box<
|
Box<
|
||||||
dyn Stream<
|
dyn Stream<
|
||||||
Item = GrandpaJustification<
|
Item = <<P as SubstrateFinalitySyncPipeline>::FinalityEngine as Engine<
|
||||||
HeaderOf<<P as SubstrateFinalitySyncPipeline>::SourceChain>,
|
<P as SubstrateFinalitySyncPipeline>::SourceChain,
|
||||||
>,
|
>>::FinalityProof,
|
||||||
> + Send,
|
> + Send,
|
||||||
>,
|
>,
|
||||||
>;
|
>;
|
||||||
|
|
||||||
|
/// Substrate finality proof. Specific to the used `FinalityEngine`.
|
||||||
|
pub type SubstrateFinalityProof<P> =
|
||||||
|
<<P as SubstrateFinalitySyncPipeline>::FinalityEngine as Engine<
|
||||||
|
<P as SubstrateFinalitySyncPipeline>::SourceChain,
|
||||||
|
>>::FinalityProof;
|
||||||
|
|
||||||
/// Substrate node as finality source.
|
/// Substrate node as finality source.
|
||||||
pub struct SubstrateFinalitySource<P: SubstrateFinalitySyncPipeline> {
|
pub struct SubstrateFinalitySource<P: SubstrateFinalitySyncPipeline> {
|
||||||
client: Client<P::SourceChain>,
|
client: Client<P::SourceChain>,
|
||||||
@@ -120,7 +125,7 @@ impl<P: SubstrateFinalitySyncPipeline> SourceClient<FinalitySyncPipelineAdapter<
|
|||||||
) -> Result<
|
) -> Result<
|
||||||
(
|
(
|
||||||
relay_substrate_client::SyncHeader<HeaderOf<P::SourceChain>>,
|
relay_substrate_client::SyncHeader<HeaderOf<P::SourceChain>>,
|
||||||
Option<GrandpaJustification<HeaderOf<P::SourceChain>>>,
|
Option<SubstrateFinalityProof<P>>,
|
||||||
),
|
),
|
||||||
Error,
|
Error,
|
||||||
> {
|
> {
|
||||||
@@ -130,9 +135,7 @@ impl<P: SubstrateFinalitySyncPipeline> SourceClient<FinalitySyncPipelineAdapter<
|
|||||||
let justification = signed_block
|
let justification = signed_block
|
||||||
.justification()
|
.justification()
|
||||||
.map(|raw_justification| {
|
.map(|raw_justification| {
|
||||||
GrandpaJustification::<HeaderOf<P::SourceChain>>::decode(
|
SubstrateFinalityProof::<P>::decode(&mut raw_justification.as_slice())
|
||||||
&mut raw_justification.as_slice(),
|
|
||||||
)
|
|
||||||
})
|
})
|
||||||
.transpose()
|
.transpose()
|
||||||
.map_err(Error::ResponseParseFailed)?;
|
.map_err(Error::ResponseParseFailed)?;
|
||||||
@@ -142,7 +145,7 @@ impl<P: SubstrateFinalitySyncPipeline> SourceClient<FinalitySyncPipelineAdapter<
|
|||||||
|
|
||||||
async fn finality_proofs(&self) -> Result<Self::FinalityProofsStream, Error> {
|
async fn finality_proofs(&self) -> Result<Self::FinalityProofsStream, Error> {
|
||||||
Ok(unfold(
|
Ok(unfold(
|
||||||
self.client.clone().subscribe_justifications().await?,
|
P::FinalityEngine::finality_proofs(self.client.clone()).await?,
|
||||||
move |subscription| async move {
|
move |subscription| async move {
|
||||||
loop {
|
loop {
|
||||||
let log_error = |err| {
|
let log_error = |err| {
|
||||||
@@ -161,7 +164,7 @@ impl<P: SubstrateFinalitySyncPipeline> SourceClient<FinalitySyncPipelineAdapter<
|
|||||||
.ok()??;
|
.ok()??;
|
||||||
|
|
||||||
let decoded_justification =
|
let decoded_justification =
|
||||||
GrandpaJustification::<HeaderOf<P::SourceChain>>::decode(
|
<P::FinalityEngine as Engine<P::SourceChain>>::FinalityProof::decode(
|
||||||
&mut &next_justification[..],
|
&mut &next_justification[..],
|
||||||
);
|
);
|
||||||
|
|
||||||
+10
-15
@@ -14,24 +14,22 @@
|
|||||||
// 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 client as Substrate finality proof target. The chain we connect to should have
|
//! Substrate client as Substrate finality proof target.
|
||||||
//! bridge GRANDPA pallet deployed and provide `<BridgedChainName>FinalityApi` to allow bridging
|
|
||||||
//! with <BridgedName> chain.
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
finality_pipeline::{
|
finality::{
|
||||||
FinalitySyncPipelineAdapter, SubmitFinalityProofCallBuilder, SubstrateFinalitySyncPipeline,
|
engine::Engine, source::SubstrateFinalityProof, FinalitySyncPipelineAdapter,
|
||||||
|
SubmitFinalityProofCallBuilder, SubstrateFinalitySyncPipeline,
|
||||||
},
|
},
|
||||||
TransactionParams,
|
TransactionParams,
|
||||||
};
|
};
|
||||||
|
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use bp_header_chain::{justification::GrandpaJustification, storage_keys::is_halted_key};
|
|
||||||
use codec::Encode;
|
use codec::Encode;
|
||||||
use finality_relay::TargetClient;
|
use finality_relay::TargetClient;
|
||||||
use relay_substrate_client::{
|
use relay_substrate_client::{
|
||||||
AccountIdOf, AccountKeyPairOf, Chain, ChainWithGrandpa, Client, Error, HeaderIdOf, HeaderOf,
|
AccountIdOf, AccountKeyPairOf, Chain, Client, Error, HeaderIdOf, HeaderOf, SignParam,
|
||||||
SignParam, SyncHeader, TransactionEra, TransactionSignScheme, UnsignedTransaction,
|
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};
|
use sp_core::{Bytes, Pair};
|
||||||
@@ -51,12 +49,9 @@ impl<P: SubstrateFinalitySyncPipeline> SubstrateFinalityTarget<P> {
|
|||||||
SubstrateFinalityTarget { client, transaction_params }
|
SubstrateFinalityTarget { client, transaction_params }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Ensure that the GRANDPA pallet at target chain is active.
|
/// Ensure that the bridge pallet at target chain is active.
|
||||||
pub async fn ensure_pallet_active(&self) -> Result<(), Error> {
|
pub async fn ensure_pallet_active(&self) -> Result<(), Error> {
|
||||||
let is_halted = self
|
let is_halted = self.client.storage_value(P::FinalityEngine::is_halted_key(), None).await?;
|
||||||
.client
|
|
||||||
.storage_value(is_halted_key(P::SourceChain::WITH_CHAIN_GRANDPA_PALLET_NAME), None)
|
|
||||||
.await?;
|
|
||||||
if is_halted.unwrap_or(false) {
|
if is_halted.unwrap_or(false) {
|
||||||
Err(Error::BridgePalletIsHalted)
|
Err(Error::BridgePalletIsHalted)
|
||||||
} else {
|
} else {
|
||||||
@@ -94,7 +89,7 @@ where
|
|||||||
// 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?;
|
||||||
// we can't relay finality if GRANDPA pallet at target chain is halted
|
// we can't relay finality if bridge pallet at target chain is halted
|
||||||
self.ensure_pallet_active().await?;
|
self.ensure_pallet_active().await?;
|
||||||
|
|
||||||
Ok(crate::messages_source::read_client_state::<P::TargetChain, P::SourceChain>(
|
Ok(crate::messages_source::read_client_state::<P::TargetChain, P::SourceChain>(
|
||||||
@@ -109,7 +104,7 @@ where
|
|||||||
async fn submit_finality_proof(
|
async fn submit_finality_proof(
|
||||||
&self,
|
&self,
|
||||||
header: SyncHeader<HeaderOf<P::SourceChain>>,
|
header: SyncHeader<HeaderOf<P::SourceChain>>,
|
||||||
proof: GrandpaJustification<HeaderOf<P::SourceChain>>,
|
proof: SubstrateFinalityProof<P>,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
let genesis_hash = *self.client.genesis_hash();
|
let genesis_hash = *self.client.genesis_hash();
|
||||||
let transaction_params = self.transaction_params.clone();
|
let transaction_params = self.transaction_params.clone();
|
||||||
@@ -1,282 +0,0 @@
|
|||||||
// Copyright 2019-2021 Parity Technologies (UK) Ltd.
|
|
||||||
// This file is part of Parity Bridges Common.
|
|
||||||
|
|
||||||
// Parity Bridges Common is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
|
|
||||||
// Parity Bridges Common is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
|
|
||||||
// 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/>.
|
|
||||||
|
|
||||||
//! Initialize Substrate -> Substrate headers bridge.
|
|
||||||
//!
|
|
||||||
//! Initialization is a transaction that calls `initialize()` function of the
|
|
||||||
//! `pallet-bridge-grandpa` pallet. This transaction brings initial header
|
|
||||||
//! and authorities set from source to target chain. The headers sync starts
|
|
||||||
//! with this header.
|
|
||||||
|
|
||||||
use crate::error::Error;
|
|
||||||
|
|
||||||
use bp_header_chain::{
|
|
||||||
find_grandpa_authorities_scheduled_change,
|
|
||||||
justification::{verify_justification, GrandpaJustification},
|
|
||||||
InitializationData,
|
|
||||||
};
|
|
||||||
use codec::Decode;
|
|
||||||
use finality_grandpa::voter_set::VoterSet;
|
|
||||||
use num_traits::{One, Zero};
|
|
||||||
use relay_substrate_client::{
|
|
||||||
BlockNumberOf, Chain, ChainWithGrandpa, Client, Error as SubstrateError, HashOf,
|
|
||||||
};
|
|
||||||
use sp_core::Bytes;
|
|
||||||
use sp_finality_grandpa::AuthorityList as GrandpaAuthoritiesSet;
|
|
||||||
use sp_runtime::traits::Header as HeaderT;
|
|
||||||
|
|
||||||
/// Submit headers-bridge initialization transaction.
|
|
||||||
pub async fn initialize<SourceChain: ChainWithGrandpa, TargetChain: Chain>(
|
|
||||||
source_client: Client<SourceChain>,
|
|
||||||
target_client: Client<TargetChain>,
|
|
||||||
target_transactions_signer: TargetChain::AccountId,
|
|
||||||
prepare_initialize_transaction: impl FnOnce(
|
|
||||||
TargetChain::Index,
|
|
||||||
InitializationData<SourceChain::Header>,
|
|
||||||
) -> Result<Bytes, SubstrateError>
|
|
||||||
+ Send
|
|
||||||
+ 'static,
|
|
||||||
) {
|
|
||||||
let result = do_initialize(
|
|
||||||
source_client,
|
|
||||||
target_client,
|
|
||||||
target_transactions_signer,
|
|
||||||
prepare_initialize_transaction,
|
|
||||||
)
|
|
||||||
.await;
|
|
||||||
|
|
||||||
match result {
|
|
||||||
Ok(Some(tx_hash)) => log::info!(
|
|
||||||
target: "bridge",
|
|
||||||
"Successfully submitted {}-headers bridge initialization transaction to {}: {:?}",
|
|
||||||
SourceChain::NAME,
|
|
||||||
TargetChain::NAME,
|
|
||||||
tx_hash,
|
|
||||||
),
|
|
||||||
Ok(None) => (),
|
|
||||||
Err(err) => log::error!(
|
|
||||||
target: "bridge",
|
|
||||||
"Failed to submit {}-headers bridge initialization transaction to {}: {:?}",
|
|
||||||
SourceChain::NAME,
|
|
||||||
TargetChain::NAME,
|
|
||||||
err,
|
|
||||||
),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Craft and submit initialization transaction, returning any error that may occur.
|
|
||||||
async fn do_initialize<SourceChain: ChainWithGrandpa, TargetChain: Chain>(
|
|
||||||
source_client: Client<SourceChain>,
|
|
||||||
target_client: Client<TargetChain>,
|
|
||||||
target_transactions_signer: TargetChain::AccountId,
|
|
||||||
prepare_initialize_transaction: impl FnOnce(
|
|
||||||
TargetChain::Index,
|
|
||||||
InitializationData<SourceChain::Header>,
|
|
||||||
) -> Result<Bytes, SubstrateError>
|
|
||||||
+ Send
|
|
||||||
+ 'static,
|
|
||||||
) -> Result<
|
|
||||||
Option<TargetChain::Hash>,
|
|
||||||
Error<SourceChain::Hash, <SourceChain::Header as HeaderT>::Number>,
|
|
||||||
> {
|
|
||||||
let is_initialized = is_initialized::<SourceChain, TargetChain>(&target_client).await?;
|
|
||||||
if is_initialized {
|
|
||||||
log::info!(
|
|
||||||
target: "bridge",
|
|
||||||
"{}-headers bridge at {} is already initialized. Skipping",
|
|
||||||
SourceChain::NAME,
|
|
||||||
TargetChain::NAME,
|
|
||||||
);
|
|
||||||
return Ok(None)
|
|
||||||
}
|
|
||||||
|
|
||||||
let initialization_data = prepare_initialization_data(source_client).await?;
|
|
||||||
log::info!(
|
|
||||||
target: "bridge",
|
|
||||||
"Prepared initialization data for {}-headers bridge at {}: {:?}",
|
|
||||||
SourceChain::NAME,
|
|
||||||
TargetChain::NAME,
|
|
||||||
initialization_data,
|
|
||||||
);
|
|
||||||
|
|
||||||
let initialization_tx_hash = target_client
|
|
||||||
.submit_signed_extrinsic(target_transactions_signer, move |_, transaction_nonce| {
|
|
||||||
prepare_initialize_transaction(transaction_nonce, initialization_data)
|
|
||||||
})
|
|
||||||
.await
|
|
||||||
.map_err(|err| Error::SubmitTransaction(TargetChain::NAME, err))?;
|
|
||||||
Ok(Some(initialization_tx_hash))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns `Ok(true)` if bridge has already been initialized.
|
|
||||||
async fn is_initialized<SourceChain: ChainWithGrandpa, TargetChain: Chain>(
|
|
||||||
target_client: &Client<TargetChain>,
|
|
||||||
) -> Result<bool, Error<HashOf<SourceChain>, BlockNumberOf<SourceChain>>> {
|
|
||||||
Ok(target_client
|
|
||||||
.raw_storage_value(
|
|
||||||
bp_header_chain::storage_keys::best_finalized_hash_key(
|
|
||||||
SourceChain::WITH_CHAIN_GRANDPA_PALLET_NAME,
|
|
||||||
),
|
|
||||||
None,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
.map_err(|err| Error::RetrieveBestFinalizedHeaderHash(SourceChain::NAME, err))?
|
|
||||||
.is_some())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Prepare initialization data for the GRANDPA verifier pallet.
|
|
||||||
async fn prepare_initialization_data<SourceChain: Chain>(
|
|
||||||
source_client: Client<SourceChain>,
|
|
||||||
) -> Result<
|
|
||||||
InitializationData<SourceChain::Header>,
|
|
||||||
Error<SourceChain::Hash, <SourceChain::Header as HeaderT>::Number>,
|
|
||||||
> {
|
|
||||||
// In ideal world we just need to get best finalized header and then to read GRANDPA authorities
|
|
||||||
// set (`pallet_grandpa::CurrentSetId` + `GrandpaApi::grandpa_authorities()`) at this header.
|
|
||||||
//
|
|
||||||
// But now there are problems with this approach - `CurrentSetId` may return invalid value. So
|
|
||||||
// here we're waiting for the next justification, read the authorities set and then try to
|
|
||||||
// figure out the set id with bruteforce.
|
|
||||||
let justifications = source_client
|
|
||||||
.subscribe_justifications()
|
|
||||||
.await
|
|
||||||
.map_err(|err| Error::Subscribe(SourceChain::NAME, err))?;
|
|
||||||
// Read next justification - the header that it finalizes will be used as initial header.
|
|
||||||
let justification = justifications
|
|
||||||
.next()
|
|
||||||
.await
|
|
||||||
.map_err(|e| Error::ReadJustification(SourceChain::NAME, e))
|
|
||||||
.and_then(|justification| {
|
|
||||||
justification.ok_or(Error::ReadJustificationStreamEnded(SourceChain::NAME))
|
|
||||||
})?;
|
|
||||||
|
|
||||||
// Read initial header.
|
|
||||||
let justification: GrandpaJustification<SourceChain::Header> =
|
|
||||||
Decode::decode(&mut &justification.0[..])
|
|
||||||
.map_err(|err| Error::DecodeJustification(SourceChain::NAME, err))?;
|
|
||||||
|
|
||||||
let (initial_header_hash, initial_header_number) =
|
|
||||||
(justification.commit.target_hash, justification.commit.target_number);
|
|
||||||
|
|
||||||
let initial_header = source_header(&source_client, initial_header_hash).await?;
|
|
||||||
log::trace!(target: "bridge", "Selected {} initial header: {}/{}",
|
|
||||||
SourceChain::NAME,
|
|
||||||
initial_header_number,
|
|
||||||
initial_header_hash,
|
|
||||||
);
|
|
||||||
|
|
||||||
// Read GRANDPA authorities set at initial header.
|
|
||||||
let initial_authorities_set =
|
|
||||||
source_authorities_set(&source_client, initial_header_hash).await?;
|
|
||||||
log::trace!(target: "bridge", "Selected {} initial authorities set: {:?}",
|
|
||||||
SourceChain::NAME,
|
|
||||||
initial_authorities_set,
|
|
||||||
);
|
|
||||||
|
|
||||||
// If initial header changes the GRANDPA authorities set, then we need previous authorities
|
|
||||||
// to verify justification.
|
|
||||||
let mut authorities_for_verification = initial_authorities_set.clone();
|
|
||||||
let scheduled_change = find_grandpa_authorities_scheduled_change(&initial_header);
|
|
||||||
assert!(
|
|
||||||
scheduled_change.as_ref().map(|c| c.delay.is_zero()).unwrap_or(true),
|
|
||||||
"GRANDPA authorities change at {} scheduled to happen in {:?} blocks. We expect\
|
|
||||||
regular hange to have zero delay",
|
|
||||||
initial_header_hash,
|
|
||||||
scheduled_change.as_ref().map(|c| c.delay),
|
|
||||||
);
|
|
||||||
let schedules_change = scheduled_change.is_some();
|
|
||||||
if schedules_change {
|
|
||||||
authorities_for_verification =
|
|
||||||
source_authorities_set(&source_client, *initial_header.parent_hash()).await?;
|
|
||||||
log::trace!(
|
|
||||||
target: "bridge",
|
|
||||||
"Selected {} header is scheduling GRANDPA authorities set changes. Using previous set: {:?}",
|
|
||||||
SourceChain::NAME,
|
|
||||||
authorities_for_verification,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now let's try to guess authorities set id by verifying justification.
|
|
||||||
let mut initial_authorities_set_id = 0;
|
|
||||||
let mut min_possible_block_number = SourceChain::BlockNumber::zero();
|
|
||||||
let authorities_for_verification = VoterSet::new(authorities_for_verification.clone())
|
|
||||||
.ok_or(Error::ReadInvalidAuthorities(SourceChain::NAME, authorities_for_verification))?;
|
|
||||||
loop {
|
|
||||||
log::trace!(
|
|
||||||
target: "bridge", "Trying {} GRANDPA authorities set id: {}",
|
|
||||||
SourceChain::NAME,
|
|
||||||
initial_authorities_set_id,
|
|
||||||
);
|
|
||||||
|
|
||||||
let is_valid_set_id = verify_justification::<SourceChain::Header>(
|
|
||||||
(initial_header_hash, initial_header_number),
|
|
||||||
initial_authorities_set_id,
|
|
||||||
&authorities_for_verification,
|
|
||||||
&justification,
|
|
||||||
)
|
|
||||||
.is_ok();
|
|
||||||
|
|
||||||
if is_valid_set_id {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
initial_authorities_set_id += 1;
|
|
||||||
min_possible_block_number += One::one();
|
|
||||||
if min_possible_block_number > initial_header_number {
|
|
||||||
// there can't be more authorities set changes than headers => if we have reached
|
|
||||||
// `initial_block_number` and still have not found correct value of
|
|
||||||
// `initial_authorities_set_id`, then something else is broken => fail
|
|
||||||
return Err(Error::GuessInitialAuthorities(SourceChain::NAME, initial_header_number))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(InitializationData {
|
|
||||||
header: Box::new(initial_header),
|
|
||||||
authority_list: initial_authorities_set,
|
|
||||||
set_id: if schedules_change {
|
|
||||||
initial_authorities_set_id + 1
|
|
||||||
} else {
|
|
||||||
initial_authorities_set_id
|
|
||||||
},
|
|
||||||
is_halted: false,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Read header by hash from the source client.
|
|
||||||
async fn source_header<SourceChain: Chain>(
|
|
||||||
source_client: &Client<SourceChain>,
|
|
||||||
header_hash: SourceChain::Hash,
|
|
||||||
) -> Result<SourceChain::Header, Error<SourceChain::Hash, <SourceChain::Header as HeaderT>::Number>>
|
|
||||||
{
|
|
||||||
source_client
|
|
||||||
.header_by_hash(header_hash)
|
|
||||||
.await
|
|
||||||
.map_err(|err| Error::RetrieveHeader(SourceChain::NAME, header_hash, err))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Read GRANDPA authorities set at given header.
|
|
||||||
async fn source_authorities_set<SourceChain: Chain>(
|
|
||||||
source_client: &Client<SourceChain>,
|
|
||||||
header_hash: SourceChain::Hash,
|
|
||||||
) -> Result<GrandpaAuthoritiesSet, Error<SourceChain::Hash, <SourceChain::Header as HeaderT>::Number>>
|
|
||||||
{
|
|
||||||
let raw_authorities_set = source_client
|
|
||||||
.grandpa_authorities_set(header_hash)
|
|
||||||
.await
|
|
||||||
.map_err(|err| Error::RetrieveAuthorities(SourceChain::NAME, header_hash, err))?;
|
|
||||||
GrandpaAuthoritiesSet::decode(&mut &raw_authorities_set[..])
|
|
||||||
.map_err(|err| Error::DecodeAuthorities(SourceChain::NAME, header_hash, err))
|
|
||||||
}
|
|
||||||
@@ -22,11 +22,7 @@ use std::time::Duration;
|
|||||||
|
|
||||||
pub mod conversion_rate_update;
|
pub mod conversion_rate_update;
|
||||||
pub mod error;
|
pub mod error;
|
||||||
pub mod finality_guards;
|
pub mod finality;
|
||||||
pub mod finality_pipeline;
|
|
||||||
pub mod finality_source;
|
|
||||||
pub mod finality_target;
|
|
||||||
pub mod headers_initialize;
|
|
||||||
pub mod helpers;
|
pub mod helpers;
|
||||||
pub mod messages_lane;
|
pub mod messages_lane;
|
||||||
pub mod messages_metrics;
|
pub mod messages_metrics;
|
||||||
|
|||||||
@@ -30,9 +30,11 @@ use relay_utils::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
finality_pipeline::{SubstrateFinalitySyncPipeline, RECENT_FINALITY_PROOFS_LIMIT},
|
finality::{
|
||||||
finality_source::{RequiredHeaderNumberRef, SubstrateFinalitySource},
|
source::{RequiredHeaderNumberRef, SubstrateFinalitySource},
|
||||||
finality_target::SubstrateFinalityTarget,
|
target::SubstrateFinalityTarget,
|
||||||
|
SubstrateFinalitySyncPipeline, RECENT_FINALITY_PROOFS_LIMIT,
|
||||||
|
},
|
||||||
TransactionParams, STALL_TIMEOUT,
|
TransactionParams, STALL_TIMEOUT,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user