referrerpolicy=no-referrer-when-downgrade

substrate_relay_helper/finality_base/
mod.rs

1// Copyright 2019-2023 Parity Technologies (UK) Ltd.
2// This file is part of Parity Bridges Common.
3
4// Parity Bridges Common is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8
9// Parity Bridges Common is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12// GNU General Public License for more details.
13
14// You should have received a copy of the GNU General Public License
15// along with Parity Bridges Common.  If not, see <http://www.gnu.org/licenses/>.
16
17//! Types and functions intended to ease adding of new Substrate -> Substrate
18//! finality pipelines.
19
20pub mod engine;
21
22use crate::finality_base::engine::Engine;
23
24use async_trait::async_trait;
25use bp_runtime::{HashOf, HeaderIdOf};
26use codec::Decode;
27use futures::{stream::unfold, Stream, StreamExt};
28use relay_substrate_client::{Chain, Client, Error};
29use std::{fmt::Debug, pin::Pin};
30
31/// Substrate -> Substrate finality related pipeline.
32#[async_trait]
33pub trait SubstrateFinalityPipeline: 'static + Clone + Debug + Send + Sync {
34	/// Headers of this chain are submitted to the `TargetChain`.
35	type SourceChain: Chain;
36	/// Headers of the `SourceChain` are submitted to this chain.
37	type TargetChain: Chain;
38	/// Finality engine.
39	type FinalityEngine: Engine<Self::SourceChain>;
40}
41
42/// Substrate finality proof. Specific to the used `FinalityEngine`.
43pub type SubstrateFinalityProof<P> = <<P as SubstrateFinalityPipeline>::FinalityEngine as Engine<
44	<P as SubstrateFinalityPipeline>::SourceChain,
45>>::FinalityProof;
46
47/// Substrate finality proofs stream.
48pub type SubstrateFinalityProofsStream<P> =
49	Pin<Box<dyn Stream<Item = SubstrateFinalityProof<P>> + Send>>;
50
51/// Subscribe to new finality proofs.
52pub async fn finality_proofs<P: SubstrateFinalityPipeline>(
53	client: &impl Client<P::SourceChain>,
54) -> Result<SubstrateFinalityProofsStream<P>, Error> {
55	Ok(unfold(
56		P::FinalityEngine::source_finality_proofs(client).await?,
57		move |mut subscription| async move {
58			loop {
59				let log_error = |err| {
60					log::error!(
61						target: "bridge",
62						"Failed to read justification target from the {} justifications stream: {:?}",
63						P::SourceChain::NAME,
64						err,
65					);
66				};
67
68				let next_justification = subscription.next().await?;
69
70				let decoded_justification =
71					<P::FinalityEngine as Engine<P::SourceChain>>::FinalityProof::decode(
72						&mut &next_justification[..],
73					);
74
75				let justification = match decoded_justification {
76					Ok(j) => j,
77					Err(err) => {
78						log_error(format!("decode failed with error {err:?}"));
79						continue
80					},
81				};
82
83				return Some((justification, subscription))
84			}
85		},
86	)
87	.boxed())
88}
89
90/// Get the id of the best `SourceChain` header known to the `TargetChain` at the provided
91/// target block using the exposed runtime API method.
92///
93/// The runtime API method should be `<TargetChain>FinalityApi::best_finalized()`.
94pub async fn best_synced_header_id<SourceChain, TargetChain>(
95	target_client: &impl Client<TargetChain>,
96	at: HashOf<TargetChain>,
97) -> Result<Option<HeaderIdOf<SourceChain>>, Error>
98where
99	SourceChain: Chain,
100	TargetChain: Chain,
101{
102	// now let's read id of best finalized peer header at our best finalized block
103	target_client
104		.state_call(at, SourceChain::BEST_FINALIZED_HEADER_ID_METHOD.into(), ())
105		.await
106}