Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Snowbridge: Synchronize from Snowfork repository #3761

Merged
merged 47 commits into from
Apr 2, 2024
Merged
Show file tree
Hide file tree
Changes from 40 commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
2536e78
adds snowbridge
Feb 8, 2024
bc607a0
Test pallet order (#112)
claravanstaden Feb 16, 2024
4cede80
Fix coverage (#115)
claravanstaden Feb 22, 2024
7bbe297
Merge branch 'master' into snowbridge
Feb 23, 2024
78c6c9b
Extract Ethereum chain id in tests (#117)
claravanstaden Feb 28, 2024
66505a7
Ignore reward when funds unavailable (#118)
yrong Feb 28, 2024
628b251
Increase MaxExecutionHeadersToKeep (#120)
yrong Mar 5, 2024
e553417
Smoke Tests in CI (#113)
claravanstaden Mar 5, 2024
5bac4ee
Sync execution update on demand (#123)
yrong Mar 14, 2024
8be52c9
Adds finalized header gap check (#124)
claravanstaden Mar 18, 2024
4c850e8
Inline execution update into proof of inbound message & Remove execut…
yrong Mar 20, 2024
cbcc449
Fix Smoketests CI (#126)
claravanstaden Mar 20, 2024
ae80de0
cleanup branch
Mar 20, 2024
b6fee8b
merge
Mar 20, 2024
e353ec0
remove fmt file
Mar 20, 2024
20ca52e
Merge branch 'master' into beacon-client-improvements
claravanstaden Mar 20, 2024
98d8f2c
unused param
Mar 20, 2024
0892540
Merge remote-tracking branch 'origin/beacon-client-improvements' into…
Mar 20, 2024
0432944
prdoc
Mar 20, 2024
ad9c398
Merge branch 'master' into beacon-client-improvements
claravanstaden Mar 21, 2024
db1b4c1
remove rustdoc describing removed extrinsic
Mar 21, 2024
2730776
Merge branch 'master' into beacon-client-improvements
claravanstaden Mar 21, 2024
71443be
taplo
Mar 21, 2024
5f2e751
Merge remote-tracking branch 'origin/beacon-client-improvements' into…
Mar 21, 2024
5da7df7
Add a linear fee multiplier to ensure safety margins (#127)
vgeddes Mar 21, 2024
a43b54e
change bitwise or to logical or
Mar 22, 2024
0fbceec
Merge branch 'master' into beacon-client-improvements
claravanstaden Mar 22, 2024
75a33cf
Merge branch 'master' into beacon-client-improvements
Mar 25, 2024
e80219d
rustdoc
Mar 25, 2024
deec9eb
merge damage
Mar 25, 2024
9293295
Merge branch 'master' into snowbridge
Mar 25, 2024
5f5aef7
Merge branch 'master' into beacon-client-improvements
claravanstaden Mar 25, 2024
a0e7884
Merge branch 'snowbridge' into beacon-client-improvements
Mar 25, 2024
8c51118
Merge remote-tracking branch 'origin/beacon-client-improvements' into…
Mar 25, 2024
a0d5002
Fix typo in prdoc. Credit author yrong.
Mar 25, 2024
6e5e5c0
unused var
Mar 25, 2024
ae83b6c
Remove MaxExecutionHeadersToKeep (#129)
yrong Mar 26, 2024
35c74ce
Merge branch 'master' into beacon-client-improvements
Mar 28, 2024
2ae3cab
Merge branch 'master' into beacon-client-improvements
claravanstaden Mar 31, 2024
b81f262
Merge branch 'master' into beacon-client-improvements
claravanstaden Apr 2, 2024
fcd5f71
Update bridges/snowbridge/pallets/inbound-queue/src/lib.rs
claravanstaden Apr 2, 2024
7c0a097
Merge branch 'master' into beacon-client-improvements
claravanstaden Apr 2, 2024
ef97c0b
update prdoc
Apr 2, 2024
87de172
Merge remote-tracking branch 'origin/beacon-client-improvements' into…
Apr 2, 2024
3aad93a
Merge branch 'master' into beacon-client-improvements
claravanstaden Apr 2, 2024
304f890
fix prdoc
Apr 2, 2024
0cfd048
Merge remote-tracking branch 'origin/beacon-client-improvements' into…
Apr 2, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
272 changes: 179 additions & 93 deletions bridges/snowbridge/pallets/ethereum-client/fixtures/src/lib.rs

Large diffs are not rendered by default.

18 changes: 0 additions & 18 deletions bridges/snowbridge/pallets/ethereum-client/src/benchmarking/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,24 +65,6 @@ mod benchmarks {
Ok(())
}

#[benchmark]
fn submit_execution_header() -> Result<(), BenchmarkError> {
let caller: T::AccountId = whitelisted_caller();
let checkpoint_update = make_checkpoint();
let finalized_header_update = make_finalized_header_update();
let execution_header_update = make_execution_header_update();
let execution_header_hash = execution_header_update.execution_header.block_hash();
EthereumBeaconClient::<T>::process_checkpoint_update(&checkpoint_update)?;
EthereumBeaconClient::<T>::process_update(&finalized_header_update)?;

#[extrinsic_call]
_(RawOrigin::Signed(caller.clone()), Box::new(*execution_header_update));

assert!(<ExecutionHeaders<T>>::contains_key(execution_header_hash));

Ok(())
}

#[benchmark(extra)]
fn bls_fast_aggregate_verify_pre_aggregated() -> Result<(), BenchmarkError> {
EthereumBeaconClient::<T>::process_checkpoint_update(&make_checkpoint())?;
Expand Down
138 changes: 103 additions & 35 deletions bridges/snowbridge/pallets/ethereum-client/src/impls.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2023 Snowfork <hello@snowfork.com>
use super::*;
use frame_support::ensure;
use primitives::ExecutionProof;

use snowbridge_core::inbound::{
VerificationError::{self, *},
Expand All @@ -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)?;

Expand All @@ -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",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why did you remove log params? I think this log became pretty non-relevant and useless, because you also remove input log with block_hash Verifying message with block hash.
How will you investigate Event log not found in receipt for transaction without knowing block_hash or tx?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The reasoning behind this is on the original PR, over here: Snowfork#125 (comment)

A side-note, we don't generally have access to the parachain logs either, so we try and solve issues without having to look at the logs.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok, got it, and what about adding there some "identifier" from proof.execution_proof or proof.execution_proof.execution_header, does it make sense?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know if it would be useful. We have the same info in the relayer and that is more accessible to us.

);
return Err(LogNotFound)
}

log::info!(
target: "ethereum-client",
"💫 Receipt verification successful for {}",
proof.block_hash,
);

Ok(())
}
}
Expand All @@ -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),
Expand All @@ -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(
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(())
}
}
Loading
Loading