This repository was archived by the owner on Aug 15, 2025. It is now read-only.
forked from paritytech/polkadot-sdk
-
Notifications
You must be signed in to change notification settings - Fork 2
Inline execution update into proof of inbound message & Remove execution header storage #125
Merged
Merged
Changes from all commits
Commits
Show all changes
22 commits
Select commit
Hold shift + click to select a range
c6636fb
Remove execution header storage & submit inbound message with executi…
yrong 0237a6d
Fix ci breaking
yrong 090ec70
More refactoring
yrong d6164f4
Update beacon test fixtures
yrong cae355a
Format code
yrong dafb253
Initialize storage with finalized checkpoint for benchmark
yrong 964c9a2
Update weights include verify the execution proof
yrong a53ed52
Fix breaking test
yrong 58d2338
Merge branch 'snowbridge' into ron/remove-execution-header-storage
yrong 9b39730
Remove fixture not in use
yrong 8e31fb9
Add detail for InvalidExecutionProof
yrong 1648248
Initialize checkpoint for tests on demand
yrong 2443c4b
Revert error as NotBootstrapped for submit_update_with_missing_bootstrap
yrong 789d3a0
Add verify_execution_header tests back
yrong 1d29ccd
Add error test back
yrong aadd6e9
Cleanup templates
yrong 1b2ca63
Update bridges/snowbridge/primitives/beacon/src/types.rs
yrong ecd013d
Narrowed inputs
yrong 4eb471c
Remove fields irrelevant from proof
yrong 5cb862d
Update bridges/snowbridge/primitives/core/src/inbound.rs
yrong fc9980a
Update bridges/snowbridge/pallets/ethereum-client/src/impls.rs
yrong f9789d8
Polish
yrong File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
274 changes: 180 additions & 94 deletions
274
bridges/snowbridge/pallets/ethereum-client/fixtures/src/lib.rs
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,6 +1,8 @@ | ||
| // SPDX-License-Identifier: Apache-2.0 | ||
| // SPDX-FileCopyrightText: 2023 Snowfork <[email protected]> | ||
| use super::*; | ||
| use frame_support::ensure; | ||
| use primitives::ExecutionProof; | ||
|
|
||
| use snowbridge_core::inbound::{ | ||
| VerificationError::{self, *}, | ||
|
|
@@ -14,32 +16,13 @@ impl<T: Config> Verifier for Pallet<T> { | |
| /// the log should be in the beacon client storage, meaning it has been verified and is an | ||
| /// ancestor of a finalized beacon block. | ||
| fn verify(event_log: &Log, proof: &Proof) -> Result<(), VerificationError> { | ||
| log::info!( | ||
| target: "ethereum-client", | ||
| "💫 Verifying message with block hash {}", | ||
| proof.block_hash, | ||
| ); | ||
| Self::verify_execution_proof(&proof.execution_proof) | ||
| .map_err(|e| InvalidExecutionProof(e.into()))?; | ||
|
|
||
| let header = <ExecutionHeaderBuffer<T>>::get(proof.block_hash).ok_or(HeaderNotFound)?; | ||
|
|
||
| let receipt = match Self::verify_receipt_inclusion(header.receipts_root, proof) { | ||
| Ok(receipt) => receipt, | ||
| Err(err) => { | ||
| log::error!( | ||
| target: "ethereum-client", | ||
| "💫 Verification of receipt inclusion failed for block {}: {:?}", | ||
| proof.block_hash, | ||
| err | ||
| ); | ||
| return Err(err) | ||
| }, | ||
| }; | ||
|
|
||
| log::trace!( | ||
| target: "ethereum-client", | ||
| "💫 Verified receipt inclusion for transaction at index {} in block {}", | ||
| proof.tx_index, proof.block_hash, | ||
| ); | ||
| let receipt = Self::verify_receipt_inclusion( | ||
| proof.execution_proof.execution_header.receipts_root(), | ||
| &proof.receipt_proof.1, | ||
| )?; | ||
|
|
||
| event_log.validate().map_err(|_| InvalidLog)?; | ||
|
|
||
|
|
@@ -53,18 +36,11 @@ impl<T: Config> Verifier for Pallet<T> { | |
| if !receipt.contains_log(&event_log) { | ||
| log::error!( | ||
| target: "ethereum-client", | ||
| "💫 Event log not found in receipt for transaction at index {} in block {}", | ||
| proof.tx_index, proof.block_hash, | ||
| "💫 Event log not found in receipt for transaction", | ||
| ); | ||
| return Err(LogNotFound) | ||
| } | ||
|
|
||
| log::info!( | ||
| target: "ethereum-client", | ||
| "💫 Receipt verification successful for {}", | ||
| proof.block_hash, | ||
| ); | ||
|
|
||
| Ok(()) | ||
| } | ||
| } | ||
|
|
@@ -74,9 +50,9 @@ impl<T: Config> Pallet<T> { | |
| /// `proof.block_hash`. | ||
| pub fn verify_receipt_inclusion( | ||
| receipts_root: H256, | ||
| proof: &Proof, | ||
| receipt_proof: &[Vec<u8>], | ||
| ) -> Result<Receipt, VerificationError> { | ||
| let result = verify_receipt_proof(receipts_root, &proof.data.1).ok_or(InvalidProof)?; | ||
| let result = verify_receipt_proof(receipts_root, receipt_proof).ok_or(InvalidProof)?; | ||
|
|
||
| match result { | ||
| Ok(receipt) => Ok(receipt), | ||
|
|
@@ -90,4 +66,96 @@ impl<T: Config> Pallet<T> { | |
| }, | ||
| } | ||
| } | ||
|
|
||
| /// Validates an execution header with ancestry_proof against a finalized checkpoint on | ||
| /// chain.The beacon header containing the execution header is sent, plus the execution header, | ||
| /// along with a proof that the execution header is rooted in the beacon header body. | ||
| pub(crate) fn verify_execution_proof(execution_proof: &ExecutionProof) -> DispatchResult { | ||
| let latest_finalized_state = | ||
| FinalizedBeaconState::<T>::get(LatestFinalizedBlockRoot::<T>::get()) | ||
| .ok_or(Error::<T>::NotBootstrapped)?; | ||
| // Checks that the header is an ancestor of a finalized header, using slot number. | ||
| ensure!( | ||
| execution_proof.header.slot <= latest_finalized_state.slot, | ||
| Error::<T>::HeaderNotFinalized | ||
| ); | ||
|
|
||
| // Gets the hash tree root of the execution header, in preparation for the execution | ||
| // header proof (used to check that the execution header is rooted in the beacon | ||
| // header body. | ||
| let execution_header_root: H256 = execution_proof | ||
| .execution_header | ||
| .hash_tree_root() | ||
| .map_err(|_| Error::<T>::BlockBodyHashTreeRootFailed)?; | ||
|
|
||
| ensure!( | ||
| verify_merkle_branch( | ||
| execution_header_root, | ||
| &execution_proof.execution_branch, | ||
| config::EXECUTION_HEADER_SUBTREE_INDEX, | ||
| config::EXECUTION_HEADER_DEPTH, | ||
| execution_proof.header.body_root | ||
| ), | ||
| Error::<T>::InvalidExecutionHeaderProof | ||
| ); | ||
|
|
||
| let beacon_block_root: H256 = execution_proof | ||
| .header | ||
| .hash_tree_root() | ||
| .map_err(|_| Error::<T>::HeaderHashTreeRootFailed)?; | ||
|
|
||
| match &execution_proof.ancestry_proof { | ||
| Some(proof) => { | ||
| Self::verify_ancestry_proof( | ||
| beacon_block_root, | ||
| execution_proof.header.slot, | ||
| &proof.header_branch, | ||
| proof.finalized_block_root, | ||
| )?; | ||
| }, | ||
| None => { | ||
| // If the ancestry proof is not provided, we expect this beacon header to be a | ||
| // finalized beacon header. We need to check that the header hash matches the | ||
| // finalized header root at the expected slot. | ||
| let state = <FinalizedBeaconState<T>>::get(beacon_block_root) | ||
| .ok_or(Error::<T>::ExpectedFinalizedHeaderNotStored)?; | ||
| if execution_proof.header.slot != state.slot { | ||
| return Err(Error::<T>::ExpectedFinalizedHeaderNotStored.into()) | ||
| } | ||
| }, | ||
| } | ||
|
|
||
| Ok(()) | ||
| } | ||
|
|
||
| /// Verify that `block_root` is an ancestor of `finalized_block_root` Used to prove that | ||
| /// an execution header is an ancestor of a finalized header (i.e. the blocks are | ||
| /// on the same chain). | ||
| fn verify_ancestry_proof( | ||
claravanstaden marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| block_root: H256, | ||
| block_slot: u64, | ||
| block_root_proof: &[H256], | ||
| finalized_block_root: H256, | ||
| ) -> DispatchResult { | ||
| let state = <FinalizedBeaconState<T>>::get(finalized_block_root) | ||
| .ok_or(Error::<T>::ExpectedFinalizedHeaderNotStored)?; | ||
|
|
||
| ensure!(block_slot < state.slot, Error::<T>::HeaderNotFinalized); | ||
|
|
||
| let index_in_array = block_slot % (SLOTS_PER_HISTORICAL_ROOT as u64); | ||
| let leaf_index = (SLOTS_PER_HISTORICAL_ROOT as u64) + index_in_array; | ||
|
|
||
| ensure!( | ||
| verify_merkle_branch( | ||
| block_root, | ||
| block_root_proof, | ||
| leaf_index as usize, | ||
| config::BLOCK_ROOT_AT_INDEX_DEPTH, | ||
| state.block_roots_root | ||
| ), | ||
| Error::<T>::InvalidAncestryMerkleProof | ||
| ); | ||
|
|
||
| Ok(()) | ||
| } | ||
| } | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.