1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106
// Copyright 2019-2023 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/>.
//! Types and functions intended to ease adding of new Substrate -> Substrate
//! finality pipelines.
pub mod engine;
use crate::finality_base::engine::Engine;
use async_trait::async_trait;
use bp_runtime::{HashOf, HeaderIdOf};
use codec::Decode;
use futures::{stream::unfold, Stream, StreamExt};
use relay_substrate_client::{Chain, Client, Error};
use std::{fmt::Debug, pin::Pin};
/// Substrate -> Substrate finality related pipeline.
#[async_trait]
pub trait SubstrateFinalityPipeline: '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;
/// Finality engine.
type FinalityEngine: Engine<Self::SourceChain>;
}
/// Substrate finality proof. Specific to the used `FinalityEngine`.
pub type SubstrateFinalityProof<P> = <<P as SubstrateFinalityPipeline>::FinalityEngine as Engine<
<P as SubstrateFinalityPipeline>::SourceChain,
>>::FinalityProof;
/// Substrate finality proofs stream.
pub type SubstrateFinalityProofsStream<P> =
Pin<Box<dyn Stream<Item = SubstrateFinalityProof<P>> + Send>>;
/// Subscribe to new finality proofs.
pub async fn finality_proofs<P: SubstrateFinalityPipeline>(
client: &impl Client<P::SourceChain>,
) -> Result<SubstrateFinalityProofsStream<P>, Error> {
Ok(unfold(
P::FinalityEngine::source_finality_proofs(client).await?,
move |mut subscription| async move {
loop {
let log_error = |err| {
log::error!(
target: "bridge",
"Failed to read justification target from the {} justifications stream: {:?}",
P::SourceChain::NAME,
err,
);
};
let next_justification = subscription.next().await?;
let decoded_justification =
<P::FinalityEngine as Engine<P::SourceChain>>::FinalityProof::decode(
&mut &next_justification[..],
);
let justification = match decoded_justification {
Ok(j) => j,
Err(err) => {
log_error(format!("decode failed with error {err:?}"));
continue
},
};
return Some((justification, subscription))
}
},
)
.boxed())
}
/// Get the id of the best `SourceChain` header known to the `TargetChain` at the provided
/// target block using the exposed runtime API method.
///
/// The runtime API method should be `<TargetChain>FinalityApi::best_finalized()`.
pub async fn best_synced_header_id<SourceChain, TargetChain>(
target_client: &impl Client<TargetChain>,
at: HashOf<TargetChain>,
) -> Result<Option<HeaderIdOf<SourceChain>>, Error>
where
SourceChain: Chain,
TargetChain: Chain,
{
// now let's read id of best finalized peer header at our best finalized block
target_client
.state_call(at, SourceChain::BEST_FINALIZED_HEADER_ID_METHOD.into(), ())
.await
}