diff --git a/bridges/relays/lib-substrate-relay/src/finality/mod.rs b/bridges/relays/lib-substrate-relay/src/finality/mod.rs index b8cf27ea78fde9704820a30373dc80e6d4e317d5..ea7c4e0362b8583204e508a80036bb9445eac538 100644 --- a/bridges/relays/lib-substrate-relay/src/finality/mod.rs +++ b/bridges/relays/lib-substrate-relay/src/finality/mod.rs @@ -24,7 +24,7 @@ use crate::{ }; use async_trait::async_trait; -use bp_header_chain::justification::GrandpaJustification; +use bp_header_chain::justification::{GrandpaJustification, JustificationVerificationContext}; use finality_relay::{FinalityPipeline, FinalitySyncPipeline}; use pallet_bridge_grandpa::{Call as BridgeGrandpaCall, Config as BridgeGrandpaConfig}; use relay_substrate_client::{ @@ -110,11 +110,12 @@ impl<P: SubstrateFinalitySyncPipeline> FinalitySyncPipeline for FinalitySyncPipe /// Different ways of building `submit_finality_proof` calls. pub trait SubmitFinalityProofCallBuilder<P: SubstrateFinalitySyncPipeline> { - /// Given source chain header and its finality proofs, build call of `submit_finality_proof` - /// function of bridge GRANDPA module at the target chain. + /// Given source chain header, its finality proof and the current authority set id, build call + /// of `submit_finality_proof` function of bridge GRANDPA module at the target chain. fn build_submit_finality_proof_call( header: SyncHeader<HeaderOf<P::SourceChain>>, proof: SubstrateFinalityProof<P>, + context: <<P as SubstrateFinalityPipeline>::FinalityEngine as Engine<P::SourceChain>>::FinalityVerificationContext, ) -> CallOf<P::TargetChain>; } @@ -132,12 +133,16 @@ where I: 'static, R::BridgedChain: bp_runtime::Chain<Header = HeaderOf<P::SourceChain>>, CallOf<P::TargetChain>: From<BridgeGrandpaCall<R, I>>, - P::FinalityEngine: - Engine<P::SourceChain, FinalityProof = GrandpaJustification<HeaderOf<P::SourceChain>>>, + P::FinalityEngine: Engine< + P::SourceChain, + FinalityProof = GrandpaJustification<HeaderOf<P::SourceChain>>, + FinalityVerificationContext = JustificationVerificationContext, + >, { fn build_submit_finality_proof_call( header: SyncHeader<HeaderOf<P::SourceChain>>, proof: GrandpaJustification<HeaderOf<P::SourceChain>>, + _context: JustificationVerificationContext, ) -> CallOf<P::TargetChain> { BridgeGrandpaCall::<R, I>::submit_finality_proof { finality_target: Box::new(header.into_inner()), @@ -171,6 +176,7 @@ macro_rules! generate_submit_finality_proof_call_builder { <$pipeline as $crate::finality_base::SubstrateFinalityPipeline>::SourceChain > >, + _context: bp_header_chain::justification::JustificationVerificationContext, ) -> relay_substrate_client::CallOf< <$pipeline as $crate::finality_base::SubstrateFinalityPipeline>::TargetChain > { diff --git a/bridges/relays/lib-substrate-relay/src/finality/target.rs b/bridges/relays/lib-substrate-relay/src/finality/target.rs index 930f0360311c37e08955b5cfece2b62e1a3f2f6b..18464d523f4f6cf4c9c165af82f6b7c2c2504070 100644 --- a/bridges/relays/lib-substrate-relay/src/finality/target.rs +++ b/bridges/relays/lib-substrate-relay/src/finality/target.rs @@ -108,13 +108,15 @@ impl<P: SubstrateFinalitySyncPipeline> TargetClient<FinalitySyncPipelineAdapter< header: SyncHeader<HeaderOf<P::SourceChain>>, mut proof: SubstrateFinalityProof<P>, ) -> Result<Self::TransactionTracker, Error> { - // runtime module at target chain may require optimized finality proof - P::FinalityEngine::optimize_proof(&self.client, &header, &mut proof).await?; + // verify and runtime module at target chain may require optimized finality proof + let context = + P::FinalityEngine::verify_and_optimize_proof(&self.client, &header, &mut proof).await?; // now we may submit optimized finality proof let mortality = self.transaction_params.mortality; - let call = - P::SubmitFinalityProofCallBuilder::build_submit_finality_proof_call(header, proof); + let call = P::SubmitFinalityProofCallBuilder::build_submit_finality_proof_call( + header, proof, context, + ); self.client .submit_and_watch_signed_extrinsic( &self.transaction_params.signer, diff --git a/bridges/relays/lib-substrate-relay/src/finality_base/engine.rs b/bridges/relays/lib-substrate-relay/src/finality_base/engine.rs index 831c1e7ad5b50009f167f49827f8418cd2ba8d3f..e517b0fd9b9abd50d6445e7222ef24ed946554bf 100644 --- a/bridges/relays/lib-substrate-relay/src/finality_base/engine.rs +++ b/bridges/relays/lib-substrate-relay/src/finality_base/engine.rs @@ -118,12 +118,15 @@ pub trait Engine<C: Chain>: Send { source_client.subscribe_finality_justifications::<Self::FinalityClient>().await } - /// Optimize finality proof before sending it to the target node. - async fn optimize_proof<TargetChain: Chain>( + /// Verify and optimize finality proof before sending it to the target node. + /// + /// Apart from optimization, we expect this method to perform all required checks + /// that the `header` and `proof` are valid at the current state of the target chain. + async fn verify_and_optimize_proof<TargetChain: Chain>( target_client: &Client<TargetChain>, header: &C::Header, proof: &mut Self::FinalityProof, - ) -> Result<(), SubstrateError>; + ) -> Result<Self::FinalityVerificationContext, SubstrateError>; /// Checks whether the given `header` and its finality `proof` fit the maximal expected /// call size limit. If result is `MaxExpectedCallSizeCheck::Exceeds { .. }`, this @@ -212,11 +215,11 @@ impl<C: ChainWithGrandpa> Engine<C> for Grandpa<C> { bp_header_chain::storage_keys::pallet_operating_mode_key(C::WITH_CHAIN_GRANDPA_PALLET_NAME) } - async fn optimize_proof<TargetChain: Chain>( + async fn verify_and_optimize_proof<TargetChain: Chain>( target_client: &Client<TargetChain>, header: &C::Header, proof: &mut Self::FinalityProof, - ) -> Result<(), SubstrateError> { + ) -> Result<Self::FinalityVerificationContext, SubstrateError> { let verification_context = Grandpa::<C>::finality_verification_context( target_client, target_client.best_header().await?.hash(), @@ -231,6 +234,7 @@ impl<C: ChainWithGrandpa> Engine<C> for Grandpa<C> { &verification_context, proof, ) + .map(|_| verification_context) .map_err(|e| { SubstrateError::Custom(format!( "Failed to optimize {} GRANDPA jutification for header {:?}: {:?}", diff --git a/bridges/relays/lib-substrate-relay/src/on_demand/headers.rs b/bridges/relays/lib-substrate-relay/src/on_demand/headers.rs index 0090dee3a03c8119a45fe2b1086303f02a08fc8b..8b58552d292c4c56c1c6fbd6fb0d9334bbcdeb3f 100644 --- a/bridges/relays/lib-substrate-relay/src/on_demand/headers.rs +++ b/bridges/relays/lib-substrate-relay/src/on_demand/headers.rs @@ -146,8 +146,13 @@ impl<P: SubstrateFinalitySyncPipeline> OnDemandRelay<P::SourceChain, P::TargetCh finality_source.prove_block_finality(current_required_header).await?; let header_id = header.id(); - // optimize justification before including it into the call - P::FinalityEngine::optimize_proof(&self.target_client, &header, &mut proof).await?; + // verify and optimize justification before including it into the call + let context = P::FinalityEngine::verify_and_optimize_proof( + &self.target_client, + &header, + &mut proof, + ) + .await?; // now we have the header and its proof, but we want to minimize our losses, so let's // check if we'll get the full refund for submitting this header @@ -185,8 +190,9 @@ impl<P: SubstrateFinalitySyncPipeline> OnDemandRelay<P::SourceChain, P::TargetCh ); // and then craft the submit-proof call - let call = - P::SubmitFinalityProofCallBuilder::build_submit_finality_proof_call(header, proof); + let call = P::SubmitFinalityProofCallBuilder::build_submit_finality_proof_call( + header, proof, context, + ); return Ok((header_id, vec![call])); }