From 7807b9de93b9bef3e21da8bb149c97d815905d62 Mon Sep 17 00:00:00 2001
From: Serban Iorga <serban@parity.io>
Date: Thu, 27 Jul 2023 15:50:17 +0300
Subject: [PATCH] GRANDPA module: store accepted justifications (#2298) (#2301)

Store accepted justifications in events.
---
 bridges/bin/millau/runtime/Cargo.toml         |  1 +
 bridges/bin/millau/runtime/src/lib.rs         | 10 +++++++
 .../bin/rialto-parachain/runtime/Cargo.toml   |  1 +
 .../bin/rialto-parachain/runtime/src/lib.rs   |  5 ++++
 bridges/bin/rialto/runtime/Cargo.toml         |  1 +
 bridges/bin/rialto/runtime/src/lib.rs         |  5 ++++
 bridges/modules/grandpa/src/lib.rs            | 28 +++++++++++++++----
 bridges/modules/parachains/src/lib.rs         | 24 ++++++++++------
 bridges/primitives/chain-kusama/src/lib.rs    |  2 +-
 bridges/primitives/chain-millau/src/lib.rs    |  4 +--
 bridges/primitives/chain-polkadot/src/lib.rs  |  2 +-
 bridges/primitives/chain-rialto/src/lib.rs    |  4 +--
 bridges/primitives/chain-rococo/src/lib.rs    |  2 +-
 bridges/primitives/chain-westend/src/lib.rs   |  3 +-
 bridges/primitives/chain-wococo/src/lib.rs    |  2 +-
 bridges/primitives/header-chain/src/lib.rs    | 16 ++++++++++-
 bridges/primitives/runtime/src/chain.rs       | 23 +++++++++++++--
 bridges/relays/client-kusama/src/lib.rs       | 11 ++++++--
 bridges/relays/client-millau/src/lib.rs       | 12 ++++++--
 bridges/relays/client-polkadot/src/lib.rs     | 13 +++++++--
 bridges/relays/client-rialto/src/lib.rs       | 12 ++++++--
 bridges/relays/client-rococo/src/lib.rs       | 10 ++++++-
 bridges/relays/client-substrate/src/chain.rs  | 22 +++++----------
 bridges/relays/client-westend/src/lib.rs      | 10 ++++++-
 bridges/relays/client-wococo/src/lib.rs       | 10 ++++++-
 .../src/finality/engine.rs                    | 21 +++++++++-----
 .../src/finality/source.rs                    |  2 +-
 27 files changed, 193 insertions(+), 63 deletions(-)

diff --git a/bridges/bin/millau/runtime/Cargo.toml b/bridges/bin/millau/runtime/Cargo.toml
index c92698edae2..f4ad89159e0 100644
--- a/bridges/bin/millau/runtime/Cargo.toml
+++ b/bridges/bin/millau/runtime/Cargo.toml
@@ -13,6 +13,7 @@ scale-info = { version = "2.9.0", default-features = false, features = ["derive"
 
 # Bridge dependencies
 
+bp-header-chain = { path = "../../../primitives/header-chain", default-features = false }
 bp-messages = { path = "../../../primitives/messages", default-features = false }
 bp-millau = { path = "../../../primitives/chain-millau", default-features = false }
 bp-parachains = { path = "../../../primitives/parachains", default-features = false }
diff --git a/bridges/bin/millau/runtime/src/lib.rs b/bridges/bin/millau/runtime/src/lib.rs
index dfd6fc322e5..f0e23cc8d77 100644
--- a/bridges/bin/millau/runtime/src/lib.rs
+++ b/bridges/bin/millau/runtime/src/lib.rs
@@ -882,12 +882,22 @@ impl_runtime_apis! {
 		fn best_finalized() -> Option<HeaderId<bp_rialto::Hash, bp_rialto::BlockNumber>> {
 			BridgeRialtoGrandpa::best_finalized()
 		}
+
+		fn accepted_grandpa_finality_proofs(
+		) -> Vec<bp_header_chain::justification::GrandpaJustification<bp_rialto::Header>> {
+			BridgeRialtoGrandpa::accepted_finality_proofs()
+		}
 	}
 
 	impl bp_westend::WestendFinalityApi<Block> for Runtime {
 		fn best_finalized() -> Option<HeaderId<bp_westend::Hash, bp_westend::BlockNumber>> {
 			BridgeWestendGrandpa::best_finalized()
 		}
+
+		fn accepted_grandpa_finality_proofs(
+		) -> Vec<bp_header_chain::justification::GrandpaJustification<bp_westend::Header>> {
+			BridgeWestendGrandpa::accepted_finality_proofs()
+		}
 	}
 
 	impl bp_westend::AssetHubWestendFinalityApi<Block> for Runtime {
diff --git a/bridges/bin/rialto-parachain/runtime/Cargo.toml b/bridges/bin/rialto-parachain/runtime/Cargo.toml
index 41ca0bff9bf..1b87205e9e9 100644
--- a/bridges/bin/rialto-parachain/runtime/Cargo.toml
+++ b/bridges/bin/rialto-parachain/runtime/Cargo.toml
@@ -16,6 +16,7 @@ scale-info = { version = "2.9.0", default-features = false, features = ["derive"
 
 # Bridge depedencies
 
+bp-header-chain = { path = "../../../primitives/header-chain", default-features = false }
 bp-messages = { path = "../../../primitives/messages", default-features = false }
 bp-millau = { path = "../../../primitives/chain-millau", default-features = false }
 bp-relayers = { path = "../../../primitives/relayers", default-features = false }
diff --git a/bridges/bin/rialto-parachain/runtime/src/lib.rs b/bridges/bin/rialto-parachain/runtime/src/lib.rs
index 18c915819d5..db3113ce448 100644
--- a/bridges/bin/rialto-parachain/runtime/src/lib.rs
+++ b/bridges/bin/rialto-parachain/runtime/src/lib.rs
@@ -746,6 +746,11 @@ impl_runtime_apis! {
 		fn best_finalized() -> Option<HeaderId<bp_millau::Hash, bp_millau::BlockNumber>> {
 			BridgeMillauGrandpa::best_finalized()
 		}
+
+		fn accepted_grandpa_finality_proofs(
+		) -> Vec<bp_header_chain::justification::GrandpaJustification<bp_millau::Header>> {
+			BridgeMillauGrandpa::accepted_finality_proofs()
+		}
 	}
 
 	impl bp_millau::ToMillauOutboundLaneApi<Block> for Runtime {
diff --git a/bridges/bin/rialto/runtime/Cargo.toml b/bridges/bin/rialto/runtime/Cargo.toml
index 2320665cf9a..7f1b18bf99c 100644
--- a/bridges/bin/rialto/runtime/Cargo.toml
+++ b/bridges/bin/rialto/runtime/Cargo.toml
@@ -12,6 +12,7 @@ scale-info = { version = "2.9.0", default-features = false, features = ["derive"
 
 # Bridge dependencies
 
+bp-header-chain = { path = "../../../primitives/header-chain", default-features = false }
 bp-messages = { path = "../../../primitives/messages", default-features = false }
 bp-millau = { path = "../../../primitives/chain-millau", default-features = false }
 bp-relayers = { path = "../../../primitives/relayers", default-features = false }
diff --git a/bridges/bin/rialto/runtime/src/lib.rs b/bridges/bin/rialto/runtime/src/lib.rs
index 1d93d24951e..b4e64072afc 100644
--- a/bridges/bin/rialto/runtime/src/lib.rs
+++ b/bridges/bin/rialto/runtime/src/lib.rs
@@ -694,6 +694,11 @@ impl_runtime_apis! {
 		fn best_finalized() -> Option<HeaderId<bp_millau::Hash, bp_millau::BlockNumber>> {
 			BridgeMillauGrandpa::best_finalized()
 		}
+
+		fn accepted_grandpa_finality_proofs(
+		) -> Vec<bp_header_chain::justification::GrandpaJustification<bp_millau::Header>> {
+			BridgeMillauGrandpa::accepted_finality_proofs()
+		}
 	}
 
 	impl sp_transaction_pool::runtime_api::TaggedTransactionQueue<Block> for Runtime {
diff --git a/bridges/modules/grandpa/src/lib.rs b/bridges/modules/grandpa/src/lib.rs
index eb49849ac88..fd9361948b6 100644
--- a/bridges/modules/grandpa/src/lib.rs
+++ b/bridges/modules/grandpa/src/lib.rs
@@ -49,7 +49,7 @@ use sp_runtime::{
 	traits::{Header as HeaderT, Zero},
 	SaturatedConversion,
 };
-use sp_std::{boxed::Box, convert::TryInto};
+use sp_std::{boxed::Box, convert::TryInto, prelude::*};
 
 mod call_ext;
 #[cfg(test)]
@@ -237,7 +237,7 @@ pub mod pallet {
 			let actual_weight = pre_dispatch_weight
 				.set_proof_size(pre_dispatch_weight.proof_size().saturating_sub(unused_proof_size));
 
-			Self::deposit_event(Event::UpdatedBestFinalizedHeader { number, hash });
+			Self::deposit_event(Event::UpdatedBestFinalizedHeader { number, hash, justification });
 
 			Ok(PostDispatchInfo { actual_weight: Some(actual_weight), pays_fee })
 		}
@@ -402,6 +402,8 @@ pub mod pallet {
 		UpdatedBestFinalizedHeader {
 			number: BridgedBlockNumber<T, I>,
 			hash: BridgedBlockHash<T, I>,
+			/// Justification.
+			justification: GrandpaJustification<BridgedHeader<T, I>>,
 		},
 	}
 
@@ -603,10 +605,22 @@ pub mod pallet {
 	}
 }
 
-impl<T: Config<I>, I: 'static> Pallet<T, I> {
-	/// Get the best finalized block number.
-	pub fn best_finalized_number() -> Option<BridgedBlockNumber<T, I>> {
-		BestFinalized::<T, I>::get().map(|id| id.number())
+impl<T: Config<I>, I: 'static> Pallet<T, I>
+where
+	<T as frame_system::Config>::RuntimeEvent: TryInto<Event<T, I>>,
+{
+	/// Get the GRANDPA justifications accepted in the current block.
+	pub fn accepted_finality_proofs() -> Vec<GrandpaJustification<BridgedHeader<T, I>>> {
+		frame_system::Pallet::<T>::read_events_no_consensus()
+			.filter_map(|event| {
+				if let Event::<T, I>::UpdatedBestFinalizedHeader { justification, .. } =
+					event.event.try_into().ok()?
+				{
+					return Some(justification)
+				}
+				None
+			})
+			.collect()
 	}
 }
 
@@ -913,10 +927,12 @@ mod tests {
 					event: TestEvent::Grandpa(Event::UpdatedBestFinalizedHeader {
 						number: *header.number(),
 						hash: header.hash(),
+						justification: justification.clone(),
 					}),
 					topics: vec![],
 				}],
 			);
+			assert_eq!(Pallet::<TestRuntime>::accepted_finality_proofs(), vec![justification]);
 		})
 	}
 
diff --git a/bridges/modules/parachains/src/lib.rs b/bridges/modules/parachains/src/lib.rs
index 4f78a45d4b7..3380b63aa5c 100644
--- a/bridges/modules/parachains/src/lib.rs
+++ b/bridges/modules/parachains/src/lib.rs
@@ -691,12 +691,13 @@ pub(crate) mod tests {
 	use super::*;
 	use crate::mock::{
 		run_test, test_relay_header, BigParachainHeader, RegularParachainHasher,
-		RegularParachainHeader, RuntimeEvent as TestEvent, RuntimeOrigin, TestRuntime,
-		UNTRACKED_PARACHAIN_ID,
+		RegularParachainHeader, RelayBlockHeader, RuntimeEvent as TestEvent, RuntimeOrigin,
+		TestRuntime, UNTRACKED_PARACHAIN_ID,
 	};
 	use bp_test_utils::prepare_parachain_heads_proof;
 	use codec::Encode;
 
+	use bp_header_chain::justification::GrandpaJustification;
 	use bp_parachains::{
 		BestParaHeadHash, BridgeParachainCall, ImportedParaHeadsKeyProvider, ParasInfoKeyProvider,
 	};
@@ -740,7 +741,10 @@ pub(crate) mod tests {
 		test_relay_header(0, state_root).hash()
 	}
 
-	fn proceed(num: RelayBlockNumber, state_root: RelayBlockHash) -> ParaHash {
+	fn proceed(
+		num: RelayBlockNumber,
+		state_root: RelayBlockHash,
+	) -> (ParaHash, GrandpaJustification<RelayBlockHeader>) {
 		pallet_bridge_grandpa::Pallet::<TestRuntime, BridgesGrandpaPalletInstance>::on_initialize(
 			0,
 		);
@@ -752,11 +756,11 @@ pub(crate) mod tests {
 			pallet_bridge_grandpa::Pallet::<TestRuntime, BridgesGrandpaPalletInstance>::submit_finality_proof(
 				RuntimeOrigin::signed(1),
 				Box::new(header),
-				justification,
+				justification.clone(),
 			)
 		);
 
-		hash
+		(hash, justification)
 	}
 
 	fn initial_best_head(parachain: u32) -> ParaInfo {
@@ -993,7 +997,7 @@ pub(crate) mod tests {
 			);
 
 			// import head#10 of parachain#1 at relay block #1
-			let relay_1_hash = proceed(1, state_root_10);
+			let (relay_1_hash, justification) = proceed(1, state_root_10);
 			assert_ok!(import_parachain_1_head(1, state_root_10, parachains_10, proof_10));
 			assert_eq!(
 				ParasInfo::<TestRuntime>::get(ParaId(1)),
@@ -1032,6 +1036,7 @@ pub(crate) mod tests {
 							pallet_bridge_grandpa::Event::UpdatedBestFinalizedHeader {
 								number: 1,
 								hash: relay_1_hash,
+								justification
 							}
 						),
 						topics: vec![],
@@ -1149,7 +1154,7 @@ pub(crate) mod tests {
 
 			// try to import head#0 of parachain#1 at relay block#1
 			// => call succeeds, but nothing is changed
-			let relay_1_hash = proceed(1, state_root);
+			let (relay_1_hash, justification) = proceed(1, state_root);
 			assert_ok!(import_parachain_1_head(1, state_root, parachains, proof));
 			assert_eq!(ParasInfo::<TestRuntime>::get(ParaId(1)), Some(initial_best_head(1)));
 			assert_eq!(
@@ -1169,6 +1174,7 @@ pub(crate) mod tests {
 							pallet_bridge_grandpa::Event::UpdatedBestFinalizedHeader {
 								number: 1,
 								hash: relay_1_hash,
+								justification
 							}
 						),
 						topics: vec![],
@@ -1197,7 +1203,7 @@ pub(crate) mod tests {
 			initialize(state_root_5);
 
 			// head#10 of parachain#1 at relay block#1
-			let relay_1_hash = proceed(1, state_root_10);
+			let (relay_1_hash, justification) = proceed(1, state_root_10);
 			assert_ok!(import_parachain_1_head(1, state_root_10, parachains_10, proof_10));
 			assert_eq!(
 				ParasInfo::<TestRuntime>::get(ParaId(1)),
@@ -1218,6 +1224,7 @@ pub(crate) mod tests {
 							pallet_bridge_grandpa::Event::UpdatedBestFinalizedHeader {
 								number: 1,
 								hash: relay_1_hash,
+								justification: justification.clone()
 							}
 						),
 						topics: vec![],
@@ -1255,6 +1262,7 @@ pub(crate) mod tests {
 							pallet_bridge_grandpa::Event::UpdatedBestFinalizedHeader {
 								number: 1,
 								hash: relay_1_hash,
+								justification
 							}
 						),
 						topics: vec![],
diff --git a/bridges/primitives/chain-kusama/src/lib.rs b/bridges/primitives/chain-kusama/src/lib.rs
index 229905a3d4a..80be182abfb 100644
--- a/bridges/primitives/chain-kusama/src/lib.rs
+++ b/bridges/primitives/chain-kusama/src/lib.rs
@@ -69,4 +69,4 @@ pub const WITH_KUSAMA_GRANDPA_PALLET_NAME: &str = "BridgeKusamaGrandpa";
 /// reserve.
 pub const MAX_NESTED_PARACHAIN_HEAD_DATA_SIZE: u32 = 128;
 
-decl_bridge_finality_runtime_apis!(kusama);
+decl_bridge_finality_runtime_apis!(kusama, grandpa);
diff --git a/bridges/primitives/chain-millau/src/lib.rs b/bridges/primitives/chain-millau/src/lib.rs
index a752b5f7114..7acaa2c4018 100644
--- a/bridges/primitives/chain-millau/src/lib.rs
+++ b/bridges/primitives/chain-millau/src/lib.rs
@@ -25,7 +25,7 @@ use bp_header_chain::ChainWithGrandpa;
 use bp_messages::{
 	InboundMessageDetails, LaneId, MessageNonce, MessagePayload, OutboundMessageDetails,
 };
-use bp_runtime::{decl_bridge_runtime_apis, Chain};
+use bp_runtime::{decl_bridge_finality_runtime_apis, decl_bridge_runtime_apis, Chain};
 use frame_support::{
 	dispatch::DispatchClass,
 	weights::{constants::WEIGHT_REF_TIME_PER_SECOND, IdentityFee, Weight},
@@ -244,4 +244,4 @@ pub const WITH_MILLAU_MESSAGES_PALLET_NAME: &str = "BridgeMillauMessages";
 /// Name of the transaction payment pallet at the Millau runtime.
 pub const TRANSACTION_PAYMENT_PALLET_NAME: &str = "TransactionPayment";
 
-decl_bridge_runtime_apis!(millau);
+decl_bridge_runtime_apis!(millau, grandpa);
diff --git a/bridges/primitives/chain-polkadot/src/lib.rs b/bridges/primitives/chain-polkadot/src/lib.rs
index 628634bb46f..fb87c364423 100644
--- a/bridges/primitives/chain-polkadot/src/lib.rs
+++ b/bridges/primitives/chain-polkadot/src/lib.rs
@@ -69,4 +69,4 @@ pub const WITH_POLKADOT_GRANDPA_PALLET_NAME: &str = "BridgePolkadotGrandpa";
 /// reserve.
 pub const MAX_NESTED_PARACHAIN_HEAD_DATA_SIZE: u32 = 128;
 
-decl_bridge_finality_runtime_apis!(polkadot);
+decl_bridge_finality_runtime_apis!(polkadot, grandpa);
diff --git a/bridges/primitives/chain-rialto/src/lib.rs b/bridges/primitives/chain-rialto/src/lib.rs
index d5be78516a2..1104e17bb03 100644
--- a/bridges/primitives/chain-rialto/src/lib.rs
+++ b/bridges/primitives/chain-rialto/src/lib.rs
@@ -22,7 +22,7 @@ use bp_header_chain::ChainWithGrandpa;
 use bp_messages::{
 	InboundMessageDetails, LaneId, MessageNonce, MessagePayload, OutboundMessageDetails,
 };
-use bp_runtime::{decl_bridge_runtime_apis, Chain};
+use bp_runtime::{decl_bridge_finality_runtime_apis, decl_bridge_runtime_apis, Chain};
 use frame_support::{
 	dispatch::DispatchClass,
 	weights::{constants::WEIGHT_REF_TIME_PER_SECOND, IdentityFee, Weight},
@@ -211,4 +211,4 @@ pub const PARAS_REGISTRAR_PALLET_NAME: &str = "Registrar";
 /// Name of the parachains pallet in the Rialto runtime.
 pub const PARAS_PALLET_NAME: &str = "Paras";
 
-decl_bridge_runtime_apis!(rialto);
+decl_bridge_runtime_apis!(rialto, grandpa);
diff --git a/bridges/primitives/chain-rococo/src/lib.rs b/bridges/primitives/chain-rococo/src/lib.rs
index a825c8b3978..a5aa46edde0 100644
--- a/bridges/primitives/chain-rococo/src/lib.rs
+++ b/bridges/primitives/chain-rococo/src/lib.rs
@@ -73,4 +73,4 @@ pub const WITH_ROCOCO_GRANDPA_PALLET_NAME: &str = "BridgeRococoGrandpa";
 /// reserve.
 pub const MAX_NESTED_PARACHAIN_HEAD_DATA_SIZE: u32 = 128;
 
-decl_bridge_finality_runtime_apis!(rococo);
+decl_bridge_finality_runtime_apis!(rococo, grandpa);
diff --git a/bridges/primitives/chain-westend/src/lib.rs b/bridges/primitives/chain-westend/src/lib.rs
index cdda46ba7b2..c1cab3198fb 100644
--- a/bridges/primitives/chain-westend/src/lib.rs
+++ b/bridges/primitives/chain-westend/src/lib.rs
@@ -19,6 +19,7 @@
 #![allow(clippy::too_many_arguments)]
 
 pub use bp_polkadot_core::*;
+use frame_support::sp_std::prelude::*;
 
 use bp_header_chain::ChainWithGrandpa;
 use bp_runtime::{decl_bridge_finality_runtime_apis, Chain, Parachain};
@@ -103,6 +104,6 @@ pub const MAX_NESTED_PARACHAIN_HEAD_DATA_SIZE: u32 = 128;
 /// Identifier of `AssetHubWestend` parachain at the Westend relay chain.
 pub const ASSET_HUB_WESTEND_PARACHAIN_ID: u32 = 1000;
 
-decl_bridge_finality_runtime_apis!(westend);
+decl_bridge_finality_runtime_apis!(westend, grandpa);
 
 decl_bridge_finality_runtime_apis!(AssetHubWestend);
diff --git a/bridges/primitives/chain-wococo/src/lib.rs b/bridges/primitives/chain-wococo/src/lib.rs
index fb63613427d..8009fde023a 100644
--- a/bridges/primitives/chain-wococo/src/lib.rs
+++ b/bridges/primitives/chain-wococo/src/lib.rs
@@ -62,4 +62,4 @@ impl ChainWithGrandpa for Wococo {
 /// Name of the With-Wococo GRANDPA pallet instance that is deployed at bridged chains.
 pub const WITH_WOCOCO_GRANDPA_PALLET_NAME: &str = "BridgeWococoGrandpa";
 
-decl_bridge_finality_runtime_apis!(wococo);
+decl_bridge_finality_runtime_apis!(wococo, grandpa);
diff --git a/bridges/primitives/header-chain/src/lib.rs b/bridges/primitives/header-chain/src/lib.rs
index 5268e7d5c5f..1f5102203ca 100644
--- a/bridges/primitives/header-chain/src/lib.rs
+++ b/bridges/primitives/header-chain/src/lib.rs
@@ -21,7 +21,7 @@
 
 use bp_runtime::{
 	BasicOperatingMode, Chain, HashOf, HasherOf, HeaderOf, RawStorageProof, StorageProofChecker,
-	StorageProofError,
+	StorageProofError, UnderlyingChainProvider,
 };
 use codec::{Codec, Decode, Encode, EncodeLike, MaxEncodedLen};
 use core::{clone::Clone, cmp::Eq, default::Default, fmt::Debug};
@@ -234,3 +234,17 @@ pub trait ChainWithGrandpa: Chain {
 	/// refund amount and doing calls which exceed the limit, may be costly to submitter.
 	const AVERAGE_HEADER_SIZE_IN_JUSTIFICATION: u32;
 }
+
+/// A trait that provides the type of the underlying `ChainWithGrandpa`.
+pub trait UnderlyingChainWithGrandpaProvider: UnderlyingChainProvider {
+	/// Underlying `ChainWithGrandpa` type.
+	type ChainWithGrandpa: ChainWithGrandpa;
+}
+
+impl<T> UnderlyingChainWithGrandpaProvider for T
+where
+	T: UnderlyingChainProvider,
+	T::Chain: ChainWithGrandpa,
+{
+	type ChainWithGrandpa = T::Chain;
+}
diff --git a/bridges/primitives/runtime/src/chain.rs b/bridges/primitives/runtime/src/chain.rs
index 8c47662a7c1..a5fb8a28809 100644
--- a/bridges/primitives/runtime/src/chain.rs
+++ b/bridges/primitives/runtime/src/chain.rs
@@ -279,10 +279,11 @@ pub type TransactionEraOf<C> = crate::TransactionEra<BlockNumberOf<C>, HashOf<C>
 ///     - `<ThisChain>FinalityApi`
 /// - constants that are stringified names of runtime API methods:
 ///     - `BEST_FINALIZED_<THIS_CHAIN>_HEADER_METHOD`
+///     - `<THIS_CHAIN>_ACCEPTED_<CONSENSUS>_FINALITY_PROOFS_METHOD`
 /// The name of the chain has to be specified in snake case (e.g. `rialto_parachain`).
 #[macro_export]
 macro_rules! decl_bridge_finality_runtime_apis {
-	($chain: ident) => {
+	($chain: ident $(, $consensus: ident => $justification_type: ty)?) => {
 		bp_runtime::paste::item! {
 			mod [<$chain _finality_api>] {
 				use super::*;
@@ -291,6 +292,13 @@ macro_rules! decl_bridge_finality_runtime_apis {
 				pub const [<BEST_FINALIZED_ $chain:upper _HEADER_METHOD>]: &str =
 					stringify!([<$chain:camel FinalityApi_best_finalized>]);
 
+				$(
+					/// Name of the `<ThisChain>FinalityApi::accepted_<consensus>_finality_proofs`
+					/// runtime method.
+					pub const [<$chain:upper _ACCEPTED_ $consensus:upper _FINALITY_PROOFS_METHOD>]: &str =
+						stringify!([<$chain:camel FinalityApi_accepted_ $consensus:lower _finality_proofs>]);
+				)?
+
 				sp_api::decl_runtime_apis! {
 					/// API for querying information about the finalized chain headers.
 					///
@@ -299,6 +307,12 @@ macro_rules! decl_bridge_finality_runtime_apis {
 					pub trait [<$chain:camel FinalityApi>] {
 						/// Returns number and hash of the best finalized header known to the bridge module.
 						fn best_finalized() -> Option<bp_runtime::HeaderId<Hash, BlockNumber>>;
+
+						$(
+							/// Returns the justifications accepted in the current block.
+							fn [<accepted_ $consensus:lower _finality_proofs>](
+							) -> Vec<$justification_type>;
+						)?
 					}
 				}
 			}
@@ -306,6 +320,9 @@ macro_rules! decl_bridge_finality_runtime_apis {
 			pub use [<$chain _finality_api>]::*;
 		}
 	};
+	($chain: ident, grandpa) => {
+		decl_bridge_finality_runtime_apis!($chain, grandpa => bp_header_chain::justification::GrandpaJustification<Header>);
+	};
 }
 
 /// Convenience macro that declares bridge messages runtime apis and related constants for a chain.
@@ -376,8 +393,8 @@ macro_rules! decl_bridge_messages_runtime_apis {
 /// The name of the chain has to be specified in snake case (e.g. `rialto_parachain`).
 #[macro_export]
 macro_rules! decl_bridge_runtime_apis {
-	($chain: ident) => {
-		bp_runtime::decl_bridge_finality_runtime_apis!($chain);
+	($chain: ident $(, $consensus: ident)?) => {
+		bp_runtime::decl_bridge_finality_runtime_apis!($chain $(, $consensus)?);
 		bp_runtime::decl_bridge_messages_runtime_apis!($chain);
 	};
 }
diff --git a/bridges/relays/client-kusama/src/lib.rs b/bridges/relays/client-kusama/src/lib.rs
index 3d53fe8f9f1..0f4172248f3 100644
--- a/bridges/relays/client-kusama/src/lib.rs
+++ b/bridges/relays/client-kusama/src/lib.rs
@@ -16,9 +16,11 @@
 
 //! Types used to connect to the Kusama chain.
 
-use bp_kusama::AccountInfoStorageMapKeyProvider;
+use bp_kusama::{AccountInfoStorageMapKeyProvider, KUSAMA_ACCEPTED_GRANDPA_FINALITY_PROOFS_METHOD};
 use bp_runtime::ChainId;
-use relay_substrate_client::{Chain, ChainWithBalances, RelayChain, UnderlyingChainProvider};
+use relay_substrate_client::{
+	Chain, ChainWithBalances, ChainWithGrandpa, RelayChain, UnderlyingChainProvider,
+};
 use sp_core::storage::StorageKey;
 use std::time::Duration;
 
@@ -47,6 +49,11 @@ impl Chain for Kusama {
 	type Call = ();
 }
 
+impl ChainWithGrandpa for Kusama {
+	const ACCEPTED_FINALITY_PROOFS_METHOD: &'static str =
+		KUSAMA_ACCEPTED_GRANDPA_FINALITY_PROOFS_METHOD;
+}
+
 impl ChainWithBalances for Kusama {
 	fn account_info_storage_key(account_id: &Self::AccountId) -> StorageKey {
 		AccountInfoStorageMapKeyProvider::final_key(account_id)
diff --git a/bridges/relays/client-millau/src/lib.rs b/bridges/relays/client-millau/src/lib.rs
index d6ce47d847d..1e899c7fdac 100644
--- a/bridges/relays/client-millau/src/lib.rs
+++ b/bridges/relays/client-millau/src/lib.rs
@@ -17,12 +17,13 @@
 //! Types used to connect to the Millau-Substrate chain.
 
 use bp_messages::MessageNonce;
+use bp_millau::MILLAU_ACCEPTED_GRANDPA_FINALITY_PROOFS_METHOD;
 use bp_runtime::ChainId;
 use codec::{Compact, Decode, Encode};
 use relay_substrate_client::{
-	BalanceOf, Chain, ChainWithBalances, ChainWithMessages, ChainWithTransactions,
-	ChainWithUtilityPallet, Error as SubstrateError, FullRuntimeUtilityPallet, NonceOf, SignParam,
-	UnderlyingChainProvider, UnsignedTransaction,
+	BalanceOf, Chain, ChainWithBalances, ChainWithGrandpa, ChainWithMessages,
+	ChainWithTransactions, ChainWithUtilityPallet, Error as SubstrateError,
+	FullRuntimeUtilityPallet, NonceOf, SignParam, UnderlyingChainProvider, UnsignedTransaction,
 };
 use sp_core::{storage::StorageKey, Pair};
 use sp_runtime::{generic::SignedPayload, traits::IdentifyAccount};
@@ -65,6 +66,11 @@ impl Chain for Millau {
 	type Call = millau_runtime::RuntimeCall;
 }
 
+impl ChainWithGrandpa for Millau {
+	const ACCEPTED_FINALITY_PROOFS_METHOD: &'static str =
+		MILLAU_ACCEPTED_GRANDPA_FINALITY_PROOFS_METHOD;
+}
+
 impl ChainWithBalances for Millau {
 	fn account_info_storage_key(account_id: &Self::AccountId) -> StorageKey {
 		use frame_support::storage::generator::StorageMap;
diff --git a/bridges/relays/client-polkadot/src/lib.rs b/bridges/relays/client-polkadot/src/lib.rs
index 96453ab9041..f65f06c7de4 100644
--- a/bridges/relays/client-polkadot/src/lib.rs
+++ b/bridges/relays/client-polkadot/src/lib.rs
@@ -16,9 +16,13 @@
 
 //! Types used to connect to the Polkadot chain.
 
-use bp_polkadot::AccountInfoStorageMapKeyProvider;
+use bp_polkadot::{
+	AccountInfoStorageMapKeyProvider, POLKADOT_ACCEPTED_GRANDPA_FINALITY_PROOFS_METHOD,
+};
 use bp_runtime::ChainId;
-use relay_substrate_client::{Chain, ChainWithBalances, RelayChain, UnderlyingChainProvider};
+use relay_substrate_client::{
+	Chain, ChainWithBalances, ChainWithGrandpa, RelayChain, UnderlyingChainProvider,
+};
 use sp_core::storage::StorageKey;
 use std::time::Duration;
 
@@ -47,6 +51,11 @@ impl Chain for Polkadot {
 	type Call = ();
 }
 
+impl ChainWithGrandpa for Polkadot {
+	const ACCEPTED_FINALITY_PROOFS_METHOD: &'static str =
+		POLKADOT_ACCEPTED_GRANDPA_FINALITY_PROOFS_METHOD;
+}
+
 impl ChainWithBalances for Polkadot {
 	fn account_info_storage_key(account_id: &Self::AccountId) -> StorageKey {
 		AccountInfoStorageMapKeyProvider::final_key(account_id)
diff --git a/bridges/relays/client-rialto/src/lib.rs b/bridges/relays/client-rialto/src/lib.rs
index 97b6c7ee802..00c98876e47 100644
--- a/bridges/relays/client-rialto/src/lib.rs
+++ b/bridges/relays/client-rialto/src/lib.rs
@@ -17,12 +17,13 @@
 //! Types used to connect to the Rialto-Substrate chain.
 
 use bp_messages::MessageNonce;
+use bp_rialto::RIALTO_ACCEPTED_GRANDPA_FINALITY_PROOFS_METHOD;
 use bp_runtime::ChainId;
 use codec::{Compact, Decode, Encode};
 use relay_substrate_client::{
-	BalanceOf, Chain, ChainWithBalances, ChainWithMessages, ChainWithTransactions,
-	Error as SubstrateError, NonceOf, RelayChain, SignParam, UnderlyingChainProvider,
-	UnsignedTransaction,
+	BalanceOf, Chain, ChainWithBalances, ChainWithGrandpa, ChainWithMessages,
+	ChainWithTransactions, Error as SubstrateError, NonceOf, RelayChain, SignParam,
+	UnderlyingChainProvider, UnsignedTransaction,
 };
 use sp_core::{storage::StorageKey, Pair};
 use sp_runtime::{generic::SignedPayload, traits::IdentifyAccount};
@@ -50,6 +51,11 @@ impl Chain for Rialto {
 	type Call = rialto_runtime::RuntimeCall;
 }
 
+impl ChainWithGrandpa for Rialto {
+	const ACCEPTED_FINALITY_PROOFS_METHOD: &'static str =
+		RIALTO_ACCEPTED_GRANDPA_FINALITY_PROOFS_METHOD;
+}
+
 impl RelayChain for Rialto {
 	const PARAS_PALLET_NAME: &'static str = bp_rialto::PARAS_PALLET_NAME;
 	const PARACHAINS_FINALITY_PALLET_NAME: &'static str =
diff --git a/bridges/relays/client-rococo/src/lib.rs b/bridges/relays/client-rococo/src/lib.rs
index ede1bf1ded4..5254b877ea8 100644
--- a/bridges/relays/client-rococo/src/lib.rs
+++ b/bridges/relays/client-rococo/src/lib.rs
@@ -16,8 +16,11 @@
 
 //! Types used to connect to the Rococo-Substrate chain.
 
+use bp_rococo::ROCOCO_ACCEPTED_GRANDPA_FINALITY_PROOFS_METHOD;
 use bp_runtime::ChainId;
-use relay_substrate_client::{Chain, ChainWithBalances, RelayChain, UnderlyingChainProvider};
+use relay_substrate_client::{
+	Chain, ChainWithBalances, ChainWithGrandpa, RelayChain, UnderlyingChainProvider,
+};
 use sp_core::storage::StorageKey;
 use std::time::Duration;
 
@@ -46,6 +49,11 @@ impl Chain for Rococo {
 	type Call = ();
 }
 
+impl ChainWithGrandpa for Rococo {
+	const ACCEPTED_FINALITY_PROOFS_METHOD: &'static str =
+		ROCOCO_ACCEPTED_GRANDPA_FINALITY_PROOFS_METHOD;
+}
+
 impl ChainWithBalances for Rococo {
 	fn account_info_storage_key(account_id: &Self::AccountId) -> StorageKey {
 		bp_rococo::AccountInfoStorageMapKeyProvider::final_key(account_id)
diff --git a/bridges/relays/client-substrate/src/chain.rs b/bridges/relays/client-substrate/src/chain.rs
index f733a10d06b..0d178da3db8 100644
--- a/bridges/relays/client-substrate/src/chain.rs
+++ b/bridges/relays/client-substrate/src/chain.rs
@@ -16,6 +16,7 @@
 
 use crate::calls::UtilityCall;
 
+use bp_header_chain::UnderlyingChainWithGrandpaProvider;
 use bp_messages::MessageNonce;
 use bp_runtime::{
 	Chain as ChainBase, ChainId, EncodedOrDecodedCall, HashOf, Parachain as ParachainBase,
@@ -77,22 +78,13 @@ pub trait RelayChain: Chain {
 ///
 /// Keep in mind that parachains are relying on relay chain GRANDPA, so they should not implement
 /// this trait.
-pub trait ChainWithGrandpa: Chain {
-	/// Name of the bridge GRANDPA pallet (used in `construct_runtime` macro call) that is deployed
-	/// at some other chain to bridge with this `ChainWithGrandpa`.
+pub trait ChainWithGrandpa: Chain + UnderlyingChainWithGrandpaProvider {
+	/// Name of the runtime API method that is returning the GRANDPA justifications accepted
+	/// by the `submit_finality_proofs` extrinsic in the queried block.
 	///
-	/// We assume that all chains that are bridging with this `ChainWithGrandpa` are using
-	/// the same name.
-	const WITH_CHAIN_GRANDPA_PALLET_NAME: &'static str;
-}
-
-impl<T> ChainWithGrandpa for T
-where
-	T: Chain + UnderlyingChainProvider,
-	T::Chain: bp_header_chain::ChainWithGrandpa,
-{
-	const WITH_CHAIN_GRANDPA_PALLET_NAME: &'static str =
-		<T::Chain as bp_header_chain::ChainWithGrandpa>::WITH_CHAIN_GRANDPA_PALLET_NAME;
+	/// Keep in mind that this method is normally provided by the other chain, which is
+	/// bridged with this chain.
+	const ACCEPTED_FINALITY_PROOFS_METHOD: &'static str;
 }
 
 /// Substrate-based parachain from minimal relay-client point of view.
diff --git a/bridges/relays/client-westend/src/lib.rs b/bridges/relays/client-westend/src/lib.rs
index 1251276fcfd..67f1f61c547 100644
--- a/bridges/relays/client-westend/src/lib.rs
+++ b/bridges/relays/client-westend/src/lib.rs
@@ -17,7 +17,10 @@
 //! Types used to connect to the Westend chain.
 
 use bp_runtime::ChainId;
-use relay_substrate_client::{Chain, ChainWithBalances, RelayChain, UnderlyingChainProvider};
+use bp_westend::WESTEND_ACCEPTED_GRANDPA_FINALITY_PROOFS_METHOD;
+use relay_substrate_client::{
+	Chain, ChainWithBalances, ChainWithGrandpa, RelayChain, UnderlyingChainProvider,
+};
 use sp_core::storage::StorageKey;
 use std::time::Duration;
 
@@ -46,6 +49,11 @@ impl Chain for Westend {
 	type Call = ();
 }
 
+impl ChainWithGrandpa for Westend {
+	const ACCEPTED_FINALITY_PROOFS_METHOD: &'static str =
+		WESTEND_ACCEPTED_GRANDPA_FINALITY_PROOFS_METHOD;
+}
+
 impl RelayChain for Westend {
 	const PARAS_PALLET_NAME: &'static str = bp_westend::PARAS_PALLET_NAME;
 	const PARACHAINS_FINALITY_PALLET_NAME: &'static str =
diff --git a/bridges/relays/client-wococo/src/lib.rs b/bridges/relays/client-wococo/src/lib.rs
index 2f0d6b22f92..acb41be50e6 100644
--- a/bridges/relays/client-wococo/src/lib.rs
+++ b/bridges/relays/client-wococo/src/lib.rs
@@ -17,7 +17,10 @@
 //! Types used to connect to the Wococo-Substrate chain.
 
 use bp_runtime::ChainId;
-use relay_substrate_client::{Chain, ChainWithBalances, RelayChain, UnderlyingChainProvider};
+use bp_wococo::WOCOCO_ACCEPTED_GRANDPA_FINALITY_PROOFS_METHOD;
+use relay_substrate_client::{
+	Chain, ChainWithBalances, ChainWithGrandpa, RelayChain, UnderlyingChainProvider,
+};
 use sp_core::storage::StorageKey;
 use std::time::Duration;
 
@@ -46,6 +49,11 @@ impl Chain for Wococo {
 	type Call = ();
 }
 
+impl ChainWithGrandpa for Wococo {
+	const ACCEPTED_FINALITY_PROOFS_METHOD: &'static str =
+		WOCOCO_ACCEPTED_GRANDPA_FINALITY_PROOFS_METHOD;
+}
+
 impl ChainWithBalances for Wococo {
 	fn account_info_storage_key(account_id: &Self::AccountId) -> StorageKey {
 		bp_wococo::AccountInfoStorageMapKeyProvider::final_key(account_id)
diff --git a/bridges/relays/lib-substrate-relay/src/finality/engine.rs b/bridges/relays/lib-substrate-relay/src/finality/engine.rs
index 3f7e3eecbaa..0092db96992 100644
--- a/bridges/relays/lib-substrate-relay/src/finality/engine.rs
+++ b/bridges/relays/lib-substrate-relay/src/finality/engine.rs
@@ -20,7 +20,8 @@ use crate::error::Error;
 use async_trait::async_trait;
 use bp_header_chain::{
 	justification::{verify_and_optimize_justification, GrandpaJustification},
-	ConsensusLogReader, FinalityProof, GrandpaConsensusLogReader,
+	ChainWithGrandpa as ChainWithGrandpaBase, ConsensusLogReader, FinalityProof,
+	GrandpaConsensusLogReader,
 };
 use bp_runtime::{BasicOperatingMode, HeaderIdProvider, OperatingMode};
 use codec::{Decode, Encode};
@@ -83,8 +84,10 @@ pub trait Engine<C: Chain>: Send {
 	}
 
 	/// A method to subscribe to encoded finality proofs, given source client.
-	async fn finality_proofs(client: &Client<C>) -> Result<Subscription<Bytes>, SubstrateError> {
-		client.subscribe_finality_justifications::<Self::FinalityClient>().await
+	async fn source_finality_proofs(
+		source_client: &Client<C>,
+	) -> Result<Subscription<Bytes>, SubstrateError> {
+		source_client.subscribe_finality_justifications::<Self::FinalityClient>().await
 	}
 
 	/// Optimize finality proof before sending it to the target node.
@@ -139,11 +142,15 @@ impl<C: ChainWithGrandpa> Engine<C> for Grandpa<C> {
 	type OperatingMode = BasicOperatingMode;
 
 	fn is_initialized_key() -> StorageKey {
-		bp_header_chain::storage_keys::best_finalized_key(C::WITH_CHAIN_GRANDPA_PALLET_NAME)
+		bp_header_chain::storage_keys::best_finalized_key(
+			C::ChainWithGrandpa::WITH_CHAIN_GRANDPA_PALLET_NAME,
+		)
 	}
 
 	fn pallet_operating_mode_key() -> StorageKey {
-		bp_header_chain::storage_keys::pallet_operating_mode_key(C::WITH_CHAIN_GRANDPA_PALLET_NAME)
+		bp_header_chain::storage_keys::pallet_operating_mode_key(
+			C::ChainWithGrandpa::WITH_CHAIN_GRANDPA_PALLET_NAME,
+		)
 	}
 
 	async fn optimize_proof<TargetChain: Chain>(
@@ -152,7 +159,7 @@ impl<C: ChainWithGrandpa> Engine<C> for Grandpa<C> {
 		proof: &mut Self::FinalityProof,
 	) -> Result<(), SubstrateError> {
 		let current_authority_set_key = bp_header_chain::storage_keys::current_authority_set_key(
-			C::WITH_CHAIN_GRANDPA_PALLET_NAME,
+			C::ChainWithGrandpa::WITH_CHAIN_GRANDPA_PALLET_NAME,
 		);
 		let (authority_set, authority_set_id): (
 			sp_consensus_grandpa::AuthorityList,
@@ -199,7 +206,7 @@ impl<C: ChainWithGrandpa> Engine<C> for Grandpa<C> {
 		// 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 = Self::finality_proofs(&source_client)
+		let justifications = Self::source_finality_proofs(&source_client)
 			.await
 			.map_err(|err| Error::Subscribe(C::NAME, err))?;
 		// Read next justification - the header that it finalizes will be used as initial header.
diff --git a/bridges/relays/lib-substrate-relay/src/finality/source.rs b/bridges/relays/lib-substrate-relay/src/finality/source.rs
index c8f11d99461..6227263902a 100644
--- a/bridges/relays/lib-substrate-relay/src/finality/source.rs
+++ b/bridges/relays/lib-substrate-relay/src/finality/source.rs
@@ -234,7 +234,7 @@ impl<P: SubstrateFinalitySyncPipeline> SourceClient<FinalitySyncPipelineAdapter<
 
 	async fn finality_proofs(&self) -> Result<Self::FinalityProofsStream, Error> {
 		Ok(unfold(
-			P::FinalityEngine::finality_proofs(&self.client).await?,
+			P::FinalityEngine::source_finality_proofs(&self.client).await?,
 			move |subscription| async move {
 				loop {
 					let log_error = |err| {
-- 
GitLab