Skip to content

Commit

Permalink
Merge branch 'master' into oty-revert-tracks-iter
Browse files Browse the repository at this point in the history
  • Loading branch information
ggwpez authored Feb 21, 2025
2 parents 308cd32 + dd7562a commit 99b44f9
Show file tree
Hide file tree
Showing 22 changed files with 3,195 additions and 126 deletions.
26 changes: 19 additions & 7 deletions bridges/snowbridge/pallets/ethereum-client/src/benchmarking/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@ mod util;
use crate::Pallet as EthereumBeaconClient;
use frame_benchmarking::v2::*;
use frame_system::RawOrigin;

use snowbridge_pallet_ethereum_client_fixtures::*;

use hex_literal::hex;
use snowbridge_beacon_primitives::{
fast_aggregate_verify, prepare_aggregate_pubkey, prepare_aggregate_signature,
verify_merkle_branch,
fast_aggregate_verify,
merkle_proof::{generalized_index_length, subtree_index},
prepare_aggregate_pubkey, prepare_aggregate_signature, verify_merkle_branch, Fork,
};
use snowbridge_pallet_ethereum_client_fixtures::*;
use util::*;

#[benchmarks]
Expand Down Expand Up @@ -111,13 +111,25 @@ mod benchmarks {
let update = make_sync_committee_update();
let block_root: H256 = update.finalized_header.hash_tree_root().unwrap();

let fork_versions = ForkVersions {
genesis: Fork { version: hex!("00000000"), epoch: 0 },
altair: Fork { version: hex!("01000000"), epoch: 0 },
bellatrix: Fork { version: hex!("02000000"), epoch: 0 },
capella: Fork { version: hex!("03000000"), epoch: 0 },
deneb: Fork { version: hex!("04000000"), epoch: 0 },
electra: Fork { version: hex!("05000000"), epoch: 80000000000 },
};
let finalized_root_gindex = EthereumBeaconClient::<T>::finalized_root_gindex_at_slot(
update.attested_header.slot,
fork_versions,
);
#[block]
{
verify_merkle_branch(
block_root,
&update.finality_branch,
config::FINALIZED_ROOT_SUBTREE_INDEX,
config::FINALIZED_ROOT_DEPTH,
subtree_index(finalized_root_gindex),
generalized_index_length(finalized_root_gindex),
update.attested_header.state_root,
);
}
Expand Down
15 changes: 15 additions & 0 deletions bridges/snowbridge/pallets/ethereum-client/src/config/altair.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2023 Snowfork <[email protected]>

/// Generalized Indices
/// related to Merkle proofs
/// get_generalized_index(BeaconState, 'block_roots')
pub const BLOCK_ROOTS_INDEX: usize = 37;
/// get_generalized_index(BeaconState, 'finalized_checkpoint', 'root')
pub const FINALIZED_ROOT_INDEX: usize = 105;
/// get_generalized_index(BeaconState, 'current_sync_committee')
pub const CURRENT_SYNC_COMMITTEE_INDEX: usize = 54;
/// get_generalized_index(BeaconState, 'next_sync_committee')
pub const NEXT_SYNC_COMMITTEE_INDEX: usize = 55;
/// get_generalized_index(BeaconBlockBody, 'execution_payload')
pub const EXECUTION_HEADER_INDEX: usize = 25;
13 changes: 13 additions & 0 deletions bridges/snowbridge/pallets/ethereum-client/src/config/electra.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2023 Snowfork <[email protected]>

/// Generalized Indices
/// related to Merkle proofs
/// get_generalized_index(BeaconState, 'block_roots')
pub const BLOCK_ROOTS_INDEX: usize = 69;
/// get_generalized_index(BeaconState, 'finalized_checkpoint', 'root')
pub const FINALIZED_ROOT_INDEX: usize = 169;
/// get_generalized_index(BeaconState, 'current_sync_committee')
pub const CURRENT_SYNC_COMMITTEE_INDEX: usize = 86;
/// get_generalized_index(BeaconState, 'next_sync_committee')
pub const NEXT_SYNC_COMMITTEE_INDEX: usize = 87;
30 changes: 2 additions & 28 deletions bridges/snowbridge/pallets/ethereum-client/src/config/mod.rs
Original file line number Diff line number Diff line change
@@ -1,35 +1,9 @@
// SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2023 Snowfork <[email protected]>
use snowbridge_beacon_primitives::merkle_proof::{generalized_index_length, subtree_index};
use static_assertions::const_assert;

/// Generalized Indices
/// related to Merkle proofs
/// get_generalized_index(BeaconState, 'block_roots')
pub const BLOCK_ROOTS_INDEX: usize = 37;
pub const BLOCK_ROOTS_SUBTREE_INDEX: usize = subtree_index(BLOCK_ROOTS_INDEX);
pub const BLOCK_ROOTS_DEPTH: usize = generalized_index_length(BLOCK_ROOTS_INDEX);

/// get_generalized_index(BeaconState, 'finalized_checkpoint', 'root')
pub const FINALIZED_ROOT_INDEX: usize = 105;
pub const FINALIZED_ROOT_SUBTREE_INDEX: usize = subtree_index(FINALIZED_ROOT_INDEX);
pub const FINALIZED_ROOT_DEPTH: usize = generalized_index_length(FINALIZED_ROOT_INDEX);

/// get_generalized_index(BeaconState, 'current_sync_committee')
pub const CURRENT_SYNC_COMMITTEE_INDEX: usize = 54;
pub const CURRENT_SYNC_COMMITTEE_SUBTREE_INDEX: usize = subtree_index(CURRENT_SYNC_COMMITTEE_INDEX);
pub const CURRENT_SYNC_COMMITTEE_DEPTH: usize =
generalized_index_length(CURRENT_SYNC_COMMITTEE_INDEX);

/// get_generalized_index(BeaconState, 'next_sync_committee')
pub const NEXT_SYNC_COMMITTEE_INDEX: usize = 55;
pub const NEXT_SYNC_COMMITTEE_SUBTREE_INDEX: usize = subtree_index(NEXT_SYNC_COMMITTEE_INDEX);
pub const NEXT_SYNC_COMMITTEE_DEPTH: usize = generalized_index_length(NEXT_SYNC_COMMITTEE_INDEX);

/// get_generalized_index(BeaconBlockBody, 'execution_payload')
pub const EXECUTION_HEADER_INDEX: usize = 25;
pub const EXECUTION_HEADER_SUBTREE_INDEX: usize = subtree_index(EXECUTION_HEADER_INDEX);
pub const EXECUTION_HEADER_DEPTH: usize = generalized_index_length(EXECUTION_HEADER_INDEX);
pub mod altair;
pub mod electra;

/// Sizes related to SSZ encoding
pub const MAX_EXTRA_DATA_BYTES: usize = 32;
Expand Down
44 changes: 23 additions & 21 deletions bridges/snowbridge/pallets/ethereum-client/src/impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use super::*;
use frame_support::ensure;
use snowbridge_beacon_primitives::ExecutionProof;

use snowbridge_beacon_primitives::merkle_proof::{generalized_index_length, subtree_index};
use snowbridge_core::inbound::{
VerificationError::{self, *},
*,
Expand All @@ -13,8 +14,9 @@ use snowbridge_ethereum::Receipt;
impl<T: Config> Verifier for Pallet<T> {
/// Verify a message by verifying the existence of the corresponding
/// Ethereum log in a block. Returns the log if successful. The execution header containing
/// the log should be in the beacon client storage, meaning it has been verified and is an
/// ancestor of a finalized beacon block.
/// the log is sent with the message. The beacon header containing the execution header
/// is also sent with the message, to check if the header is an ancestor of a finalized
/// header.
fn verify(event_log: &Log, proof: &Proof) -> Result<(), VerificationError> {
Self::verify_execution_proof(&proof.execution_proof)
.map_err(|e| InvalidExecutionProof(e.into()))?;
Expand Down Expand Up @@ -80,25 +82,6 @@ impl<T: Config> Pallet<T> {
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()
Expand All @@ -125,6 +108,25 @@ impl<T: Config> Pallet<T> {
},
}

// 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)?;

let execution_header_gindex = Self::execution_header_gindex();
ensure!(
verify_merkle_branch(
execution_header_root,
&execution_proof.execution_branch,
subtree_index(execution_header_gindex),
generalized_index_length(execution_header_gindex),
execution_proof.header.body_root
),
Error::<T>::InvalidExecutionHeaderProof
);
Ok(())
}

Expand Down
102 changes: 90 additions & 12 deletions bridges/snowbridge/pallets/ethereum-client/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,15 @@ pub mod weights;
#[cfg(any(test, feature = "fuzzing"))]
pub mod mock;

#[cfg(test)]
pub mod mock_electra;

#[cfg(test)]
mod tests;

#[cfg(test)]
mod tests_electra;

#[cfg(feature = "runtime-benchmarks")]
mod benchmarking;

Expand All @@ -40,8 +46,10 @@ use frame_support::{
};
use frame_system::ensure_signed;
use snowbridge_beacon_primitives::{
fast_aggregate_verify, verify_merkle_branch, verify_receipt_proof, BeaconHeader, BlsError,
CompactBeaconState, ForkData, ForkVersion, ForkVersions, PublicKeyPrepared, SigningData,
fast_aggregate_verify,
merkle_proof::{generalized_index_length, subtree_index},
verify_merkle_branch, verify_receipt_proof, BeaconHeader, BlsError, CompactBeaconState,
ForkData, ForkVersion, ForkVersions, PublicKeyPrepared, SigningData,
};
use snowbridge_core::{BasicOperatingMode, RingBufferMap};
use sp_core::H256;
Expand Down Expand Up @@ -245,13 +253,18 @@ pub mod pallet {
.hash_tree_root()
.map_err(|_| Error::<T>::SyncCommitteeHashTreeRootFailed)?;

let fork_versions = T::ForkVersions::get();
let sync_committee_gindex = Self::current_sync_committee_gindex_at_slot(
update.header.slot,
fork_versions.clone(),
);
// Verifies the sync committee in the Beacon state.
ensure!(
verify_merkle_branch(
sync_committee_root,
&update.current_sync_committee_branch,
config::CURRENT_SYNC_COMMITTEE_SUBTREE_INDEX,
config::CURRENT_SYNC_COMMITTEE_DEPTH,
subtree_index(sync_committee_gindex),
generalized_index_length(sync_committee_gindex),
update.header.state_root
),
Error::<T>::InvalidSyncCommitteeMerkleProof
Expand All @@ -265,12 +278,14 @@ pub mod pallet {
// This is used for ancestry proofs in ExecutionHeader updates. This verifies the
// BeaconState: the beacon state root is the tree root; the `block_roots` hash is the
// tree leaf.
let block_roots_gindex =
Self::block_roots_gindex_at_slot(update.header.slot, fork_versions);
ensure!(
verify_merkle_branch(
update.block_roots_root,
&update.block_roots_branch,
config::BLOCK_ROOTS_SUBTREE_INDEX,
config::BLOCK_ROOTS_DEPTH,
subtree_index(block_roots_gindex),
generalized_index_length(block_roots_gindex),
update.header.state_root
),
Error::<T>::InvalidBlockRootsRootMerkleProof
Expand Down Expand Up @@ -348,6 +363,11 @@ pub mod pallet {
Error::<T>::InvalidFinalizedHeaderGap
);

let fork_versions = T::ForkVersions::get();
let finalized_root_gindex = Self::finalized_root_gindex_at_slot(
update.attested_header.slot,
fork_versions.clone(),
);
// Verify that the `finality_branch`, if present, confirms `finalized_header` to match
// the finalized checkpoint root saved in the state of `attested_header`.
let finalized_block_root: H256 = update
Expand All @@ -358,8 +378,8 @@ pub mod pallet {
verify_merkle_branch(
finalized_block_root,
&update.finality_branch,
config::FINALIZED_ROOT_SUBTREE_INDEX,
config::FINALIZED_ROOT_DEPTH,
subtree_index(finalized_root_gindex),
generalized_index_length(finalized_root_gindex),
update.attested_header.state_root
),
Error::<T>::InvalidHeaderMerkleProof
Expand All @@ -368,12 +388,16 @@ pub mod pallet {
// Though following check does not belong to ALC spec we verify block_roots_root to
// match the finalized checkpoint root saved in the state of `finalized_header` so to
// cache it for later use in `verify_ancestry_proof`.
let block_roots_gindex = Self::block_roots_gindex_at_slot(
update.finalized_header.slot,
fork_versions.clone(),
);
ensure!(
verify_merkle_branch(
update.block_roots_root,
&update.block_roots_branch,
config::BLOCK_ROOTS_SUBTREE_INDEX,
config::BLOCK_ROOTS_DEPTH,
subtree_index(block_roots_gindex),
generalized_index_length(block_roots_gindex),
update.finalized_header.state_root
),
Error::<T>::InvalidBlockRootsRootMerkleProof
Expand All @@ -393,12 +417,16 @@ pub mod pallet {
Error::<T>::InvalidSyncCommitteeUpdate
);
}
let next_sync_committee_gindex = Self::next_sync_committee_gindex_at_slot(
update.attested_header.slot,
fork_versions,
);
ensure!(
verify_merkle_branch(
sync_committee_root,
&next_sync_committee_update.next_sync_committee_branch,
config::NEXT_SYNC_COMMITTEE_SUBTREE_INDEX,
config::NEXT_SYNC_COMMITTEE_DEPTH,
subtree_index(next_sync_committee_gindex),
generalized_index_length(next_sync_committee_gindex),
update.attested_header.state_root
),
Error::<T>::InvalidSyncCommitteeMerkleProof
Expand Down Expand Up @@ -604,6 +632,9 @@ pub mod pallet {

/// Returns the fork version based on the current epoch.
pub(super) fn select_fork_version(fork_versions: &ForkVersions, epoch: u64) -> ForkVersion {
if epoch >= fork_versions.electra.epoch {
return fork_versions.electra.version
}
if epoch >= fork_versions.deneb.epoch {
return fork_versions.deneb.version
}
Expand Down Expand Up @@ -684,5 +715,52 @@ pub mod pallet {

Pays::Yes
}

pub fn finalized_root_gindex_at_slot(slot: u64, fork_versions: ForkVersions) -> usize {
let epoch = compute_epoch(slot, config::SLOTS_PER_EPOCH as u64);

if epoch >= fork_versions.electra.epoch {
return config::electra::FINALIZED_ROOT_INDEX;
}

config::altair::FINALIZED_ROOT_INDEX
}

pub fn current_sync_committee_gindex_at_slot(
slot: u64,
fork_versions: ForkVersions,
) -> usize {
let epoch = compute_epoch(slot, config::SLOTS_PER_EPOCH as u64);

if epoch >= fork_versions.electra.epoch {
return config::electra::CURRENT_SYNC_COMMITTEE_INDEX;
}

config::altair::CURRENT_SYNC_COMMITTEE_INDEX
}

pub fn next_sync_committee_gindex_at_slot(slot: u64, fork_versions: ForkVersions) -> usize {
let epoch = compute_epoch(slot, config::SLOTS_PER_EPOCH as u64);

if epoch >= fork_versions.electra.epoch {
return config::electra::NEXT_SYNC_COMMITTEE_INDEX;
}

config::altair::NEXT_SYNC_COMMITTEE_INDEX
}

pub fn block_roots_gindex_at_slot(slot: u64, fork_versions: ForkVersions) -> usize {
let epoch = compute_epoch(slot, config::SLOTS_PER_EPOCH as u64);

if epoch >= fork_versions.electra.epoch {
return config::electra::BLOCK_ROOTS_INDEX;
}

config::altair::BLOCK_ROOTS_INDEX
}

pub fn execution_header_gindex() -> usize {
config::altair::EXECUTION_HEADER_INDEX
}
}
}
6 changes: 5 additions & 1 deletion bridges/snowbridge/pallets/ethereum-client/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,8 +130,12 @@ parameter_types! {
epoch: 0,
},
deneb: Fork {
version: [4, 0, 0, 0], // 0x90000073
version: [4, 0, 0, 0], // 0x04000000
epoch: 0,
},
electra: Fork {
version: [5, 0, 0, 0], // 0x05000000
epoch: 80000000000,
}
};
}
Expand Down
Loading

0 comments on commit 99b44f9

Please sign in to comment.