// 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 . //! Types and functions intended to ease adding of new Substrate -> Substrate //! finality proofs synchronization pipelines. use crate::{finality_source::SubstrateFinalitySource, finality_target::SubstrateFinalityTarget}; use bp_header_chain::justification::GrandpaJustification; use finality_relay::FinalitySyncPipeline; use pallet_bridge_grandpa::{Call as BridgeGrandpaCall, Config as BridgeGrandpaConfig}; use relay_substrate_client::{ transaction_stall_timeout, AccountIdOf, AccountKeyPairOf, BlockNumberOf, CallOf, Chain, Client, HashOf, HeaderOf, SyncHeader, TransactionSignScheme, }; use relay_utils::metrics::MetricsParams; use sp_core::Pair; use std::{fmt::Debug, marker::PhantomData}; /// Default limit of recent finality proofs. /// /// Finality delay of 4096 blocks is unlikely to happen in practice in /// Substrate+GRANDPA based chains (good to know). pub(crate) const RECENT_FINALITY_PROOFS_LIMIT: usize = 4096; /// Submit-finality-proofs transaction creation parameters. #[derive(Clone, Debug)] pub struct TransactionParams { /// Transactions author. pub transactions_signer: TS, /// Transactions mortality. pub transactions_mortality: Option, } /// Substrate -> Substrate finality proofs synchronization pipeline. pub trait SubstrateFinalitySyncPipeline: 'static + Clone + Debug + Send + Sync { /// Headers of this chain are submitted to the `TargetChain`. type SourceChain: Chain; /// Headers of the `SourceChain` are submitted to this chain. type TargetChain: Chain; /// How submit finality proof call is built? type SubmitFinalityProofCallBuilder: SubmitFinalityProofCallBuilder; /// Scheme used to sign target chain transactions. type TransactionSignScheme: TransactionSignScheme; /// Add relay guards if required. fn start_relay_guards( _target_client: &Client, _transaction_params: &TransactionParams>, ) { } } /// Adapter that allows all `SubstrateFinalitySyncPipeline` to act as `FinalitySyncPipeline`. #[derive(Clone, Debug)] pub struct FinalitySyncPipelineAdapter { _phantom: PhantomData

, } impl FinalitySyncPipeline for FinalitySyncPipelineAdapter

{ const SOURCE_NAME: &'static str = P::SourceChain::NAME; const TARGET_NAME: &'static str = P::TargetChain::NAME; type Hash = HashOf; type Number = BlockNumberOf; type Header = relay_substrate_client::SyncHeader>; type FinalityProof = GrandpaJustification>; } /// Different ways of building `submit_finality_proof` calls. pub trait SubmitFinalityProofCallBuilder { /// 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>, proof: GrandpaJustification>, ) -> CallOf; } /// Building `submit_finality_proof` call when you have direct access to the target /// chain runtime. pub struct DirectSubmitFinalityProofCallBuilder { _phantom: PhantomData<(P, R, I)>, } impl SubmitFinalityProofCallBuilder

for DirectSubmitFinalityProofCallBuilder where P: SubstrateFinalitySyncPipeline, R: BridgeGrandpaConfig, I: 'static, R::BridgedChain: bp_runtime::Chain

>, CallOf: From>, { fn build_submit_finality_proof_call( header: SyncHeader>, proof: GrandpaJustification>, ) -> CallOf { BridgeGrandpaCall::::submit_finality_proof { finality_target: Box::new(header.into_inner()), justification: proof, } .into() } } /// Macro that generates `SubmitFinalityProofCallBuilder` implementation for the case when /// you only have an access to the mocked version of target chain runtime. In this case you /// should provide "name" of the call variant for the bridge GRANDPA calls and the "name" of /// the variant for the `submit_finality_proof` call within that first option. #[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( source_client: Client, target_client: Client, only_mandatory_headers: bool, transaction_params: TransactionParams>, metrics_params: MetricsParams, ) -> anyhow::Result<()> where AccountIdOf: From< as Pair>::Public>, P::TransactionSignScheme: TransactionSignScheme, { log::info!( target: "bridge", "Starting {} -> {} finality proof relay", P::SourceChain::NAME, P::TargetChain::NAME, ); finality_relay::run( SubstrateFinalitySource::

::new(source_client, None), SubstrateFinalityTarget::

::new(target_client, transaction_params.clone()), finality_relay::FinalitySyncParams { tick: std::cmp::max( P::SourceChain::AVERAGE_BLOCK_INTERVAL, P::TargetChain::AVERAGE_BLOCK_INTERVAL, ), recent_finality_proofs_limit: RECENT_FINALITY_PROOFS_LIMIT, stall_timeout: transaction_stall_timeout( transaction_params.transactions_mortality, P::TargetChain::AVERAGE_BLOCK_INTERVAL, crate::STALL_TIMEOUT, ), only_mandatory_headers, }, metrics_params, futures::future::pending(), ) .await .map_err(|e| anyhow::format_err!("{}", e)) }