Skip to content

Commit

Permalink
feat(eth-lc): handle electra fork
Browse files Browse the repository at this point in the history
  • Loading branch information
hussein-aitlahcen committed Feb 26, 2025
1 parent 7e0cd6c commit 8be7bf4
Show file tree
Hide file tree
Showing 10 changed files with 91 additions and 58 deletions.
14 changes: 9 additions & 5 deletions lib/beacon-api-types/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ use std::{

use hex_literal::hex;
use typenum::{NonZero, Unsigned};
use unionlabs::primitives::FixedBytes;
use unionlabs::primitives::{FixedBytes, H256};

pub use crate::{
attestation::Attestation, attestation_data::AttestationData,
Expand Down Expand Up @@ -368,6 +368,10 @@ consts_traits![
mk_chain_spec!(Minimal is preset::MINIMAL);
mk_chain_spec!(Mainnet is preset::MAINNET);

pub type CurrentSyncCommitteeBranch = Vec<H256>;
pub type NextSyncCommitteeBranch = Vec<H256>;
pub type FinalityBranch = Vec<H256>;

/// Values that are constant across all configurations.
pub mod consts {
/// <https://github.com/ethereum/consensus-specs/blob/dev/specs/altair/light-client/sync-protocol.md#get_subtree_index>
Expand All @@ -389,13 +393,13 @@ pub mod consts {

// https://github.com/ethereum/consensus-specs/blob/dev/ssz/merkle-proofs.md
/// `get_generalized_index(BeaconState, "finalized_checkpoint", "root")`
pub const FINALIZED_ROOT_INDEX: u64 = 105;
pub const FINALIZED_ROOT_GINDEX: u64 = 105;
/// `get_generalized_index(BeaconState, "current_sync_committee")`
pub const CURRENT_SYNC_COMMITTEE_INDEX: u64 = 54;
pub const CURRENT_SYNC_COMMITTEE_GINDEX: u64 = 54;
/// `get_generalized_index(BeaconState, "next_sync_committee")`
pub const NEXT_SYNC_COMMITTEE_INDEX: u64 = 55;
pub const NEXT_SYNC_COMMITTEE_GINDEX: u64 = 55;
/// `get_generalized_index(BeaconBlockBody, "execution_payload")`
pub const EXECUTION_PAYLOAD_INDEX: u64 = 25;
pub const EXECUTION_PAYLOAD_GINDEX: u64 = 25;

// https://github.com/ethereum/consensus-specs/blob/dev/specs/electra/light-client/sync-protocol.md#new-constants
pub const FINALIZED_ROOT_GINDEX_ELECTRA: u64 = 169;
Expand Down
6 changes: 2 additions & 4 deletions lib/beacon-api-types/src/light_client_bootstrap.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
use unionlabs::primitives::H256;

use crate::{
consts::{floorlog2, CURRENT_SYNC_COMMITTEE_INDEX},
light_client_header::LightClientHeader,
sync_committee::SyncCommittee,
CurrentSyncCommitteeBranch,
};

#[derive(Debug, Clone, PartialEq)]
Expand All @@ -12,5 +10,5 @@ pub struct LightClientBootstrap {
pub header: LightClientHeader,
/// Current sync committee corresponding to `beacon_header.state_root`
pub current_sync_committee: SyncCommittee,
pub current_sync_committee_branch: [H256; floorlog2(CURRENT_SYNC_COMMITTEE_INDEX)],
pub current_sync_committee_branch: CurrentSyncCommitteeBranch,
}
10 changes: 2 additions & 8 deletions lib/beacon-api-types/src/light_client_finality_update.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,4 @@
use unionlabs::primitives::H256;

use crate::{
consts::{floorlog2, FINALIZED_ROOT_INDEX},
light_client_header::LightClientHeader,
Slot, SyncAggregate,
};
use crate::{light_client_header::LightClientHeader, FinalityBranch, Slot, SyncAggregate};

#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
Expand All @@ -13,7 +7,7 @@ pub struct LightClientFinalityUpdate {
pub attested_header: LightClientHeader,
/// Finalized header corresponding to `attested_header.state_root`
pub finalized_header: LightClientHeader,
pub finality_branch: [H256; floorlog2(FINALIZED_ROOT_INDEX)],
pub finality_branch: FinalityBranch,
/// Sync committee aggregate signature
pub sync_aggregate: SyncAggregate,
/// Slot at which the aggregate signature was created (untrusted)
Expand Down
6 changes: 3 additions & 3 deletions lib/beacon-api-types/src/light_client_header.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use unionlabs::primitives::H256;

use crate::{
beacon_block_header::BeaconBlockHeader,
consts::{floorlog2, EXECUTION_PAYLOAD_INDEX},
consts::{floorlog2, EXECUTION_PAYLOAD_GINDEX},
execution_payload_header::ExecutionPayloadHeader,
};

Expand All @@ -12,7 +12,7 @@ use crate::{
pub struct LightClientHeader {
pub beacon: BeaconBlockHeader,
pub execution: ExecutionPayloadHeader,
pub execution_branch: [H256; floorlog2(EXECUTION_PAYLOAD_INDEX)],
pub execution_branch: [H256; floorlog2(EXECUTION_PAYLOAD_GINDEX)],
}

#[cfg(feature = "ssz")]
Expand All @@ -25,5 +25,5 @@ pub struct LightClientHeader {
pub struct LightClientHeaderSsz<C: crate::BYTES_PER_LOGS_BLOOM + crate::MAX_EXTRA_DATA_BYTES> {
pub beacon: BeaconBlockHeader,
pub execution: crate::ExecutionPayloadHeaderSsz<C>,
pub execution_branch: [H256; floorlog2(EXECUTION_PAYLOAD_INDEX)],
pub execution_branch: [H256; floorlog2(EXECUTION_PAYLOAD_GINDEX)],
}
8 changes: 1 addition & 7 deletions lib/beacon-api-types/src/light_client_update.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,7 @@
use unionlabs::primitives::H256;

use crate::{
consts::{floorlog2, FINALIZED_ROOT_INDEX, NEXT_SYNC_COMMITTEE_INDEX},
LightClientHeader, Slot, SyncAggregate, SyncCommittee,
FinalityBranch, LightClientHeader, NextSyncCommitteeBranch, Slot, SyncAggregate, SyncCommittee,
};

pub type NextSyncCommitteeBranch = [H256; floorlog2(NEXT_SYNC_COMMITTEE_INDEX)];
pub type FinalityBranch = [H256; floorlog2(FINALIZED_ROOT_INDEX)];

#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct LightClientUpdate {
Expand Down
7 changes: 7 additions & 0 deletions lib/beacon-api/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@ pub struct Spec {
pub deneb_fork_version: Version,
#[serde(with = "::serde_utils::string")]
pub deneb_fork_epoch: u64,
pub electra_fork_version: Version,
#[serde(with = "::serde_utils::string")]
pub electra_fork_epoch: u64,
#[serde(with = "::serde_utils::string")]
pub seconds_per_slot: u64,
// SECONDS_PER_ETH1_BLOCK: 14,
Expand Down Expand Up @@ -184,6 +187,10 @@ impl Spec {
version: self.deneb_fork_version,
epoch: self.deneb_fork_epoch,
},
electra: Fork {
version: self.electra_fork_version,
epoch: self.electra_fork_epoch
},
}
}

Expand Down
2 changes: 1 addition & 1 deletion lib/ethereum-light-client-types/src/light_client_update.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use beacon_api_types::{light_client_update::NextSyncCommitteeBranch, SyncCommittee};
use beacon_api_types::{NextSyncCommitteeBranch, SyncCommittee};

use crate::LightClientUpdateData;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
use beacon_api_types::{
light_client_update::{FinalityBranch, NextSyncCommitteeBranch},
LightClientHeader, Slot, SyncAggregate, SyncCommittee,
FinalityBranch, LightClientHeader, NextSyncCommitteeBranch, Slot, SyncAggregate, SyncCommittee
};

/// Common data required for all light client updates.
Expand Down
70 changes: 53 additions & 17 deletions lib/ethereum-sync-protocol/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@ pub mod utils;

use beacon_api_types::{
consts::{
floorlog2, get_subtree_index, EXECUTION_PAYLOAD_INDEX, FINALIZED_ROOT_INDEX,
NEXT_SYNC_COMMITTEE_INDEX,
CURRENT_SYNC_COMMITTEE_GINDEX, CURRENT_SYNC_COMMITTEE_GINDEX_ELECTRA,
EXECUTION_PAYLOAD_GINDEX, FINALIZED_ROOT_GINDEX, FINALIZED_ROOT_GINDEX_ELECTRA,
NEXT_SYNC_COMMITTEE_GINDEX, NEXT_SYNC_COMMITTEE_GINDEX_ELECTRA,
},
light_client_update::LightClientUpdate,
ChainSpec, DomainType, ExecutionPayloadHeaderSsz, ForkParameters, LightClientHeader, Slot,
Expand Down Expand Up @@ -42,6 +43,42 @@ pub trait BlsVerify {
) -> Result<(), Error>;
}

// https://github.com/ethereum/consensus-specs/blob/dev/specs/altair/light-client/sync-protocol.md#finalized_root_gindex_at_slot
pub fn finalized_root_gindex_at_slot<C: ChainSpec>(
fork_parameters: &ForkParameters,
slot: Slot,
) -> u64 {
let epoch = compute_epoch_at_slot::<C>(slot);
if epoch >= fork_parameters.electra.epoch {
return FINALIZED_ROOT_GINDEX_ELECTRA;
}
FINALIZED_ROOT_GINDEX
}

// https://github.com/ethereum/consensus-specs/blob/dev/specs/altair/light-client/sync-protocol.md#current_sync_committee_gindex_at_slot
pub fn current_sync_committee_gindex_at_slot<C: ChainSpec>(
fork_parameters: &ForkParameters,
slot: Slot,
) -> u64 {
let epoch = compute_epoch_at_slot::<C>(slot);
if epoch >= fork_parameters.electra.epoch {
return CURRENT_SYNC_COMMITTEE_GINDEX_ELECTRA;
}
CURRENT_SYNC_COMMITTEE_GINDEX
}

// https://github.com/ethereum/consensus-specs/blob/dev/specs/altair/light-client/sync-protocol.md#next_sync_committee_gindex_at_slot
pub fn next_sync_committee_gindex_at_slot<C: ChainSpec>(
fork_parameters: &ForkParameters,
slot: Slot,
) -> u64 {
let epoch = compute_epoch_at_slot::<C>(slot);
if epoch >= fork_parameters.electra.epoch {
return NEXT_SYNC_COMMITTEE_GINDEX_ELECTRA;
}
NEXT_SYNC_COMMITTEE_GINDEX
}

/// Verifies if the light client `update` is valid.
///
/// * `update`: The light client update we want to verify.
Expand Down Expand Up @@ -169,8 +206,7 @@ pub fn validate_light_client_update<C: ChainSpec, V: BlsVerify>(
validate_merkle_branch(
&update.finalized_header.beacon.tree_hash_root(),
&update.finality_branch,
floorlog2(FINALIZED_ROOT_INDEX),
get_subtree_index(FINALIZED_ROOT_INDEX),
finalized_root_gindex_at_slot::<C>(fork_parameters, update_attested_slot),
&update.attested_header.beacon.state_root,
)?;

Expand All @@ -188,14 +224,17 @@ pub fn validate_light_client_update<C: ChainSpec, V: BlsVerify>(
},
)?;
}

// This validates the given next sync committee against the attested header's state root.
validate_merkle_branch(
&TryInto::<SyncCommitteeSsz<C>>::try_into(next_sync_committee.clone())
.unwrap()
.tree_hash_root(),
&update.next_sync_committee_branch.unwrap_or_default(),
floorlog2(NEXT_SYNC_COMMITTEE_INDEX),
get_subtree_index(NEXT_SYNC_COMMITTEE_INDEX),
&update
.next_sync_committee_branch
.clone()
.unwrap_or_default()[..],
next_sync_committee_gindex_at_slot::<C>(fork_parameters, update_attested_slot),
&update.attested_header.beacon.state_root,
)?;
}
Expand Down Expand Up @@ -245,19 +284,17 @@ pub fn get_lc_execution_root<C: ChainSpec>(
header: &LightClientHeader,
) -> H256 {
let epoch = compute_epoch_at_slot::<C>(header.beacon.slot);
// Now new field in electra
if epoch >= fork_parameters.electra.epoch {
return TryInto::<ExecutionPayloadHeaderSsz<C>>::try_into(header.execution.clone())
.unwrap()
.tree_hash_root();
}
if epoch >= fork_parameters.deneb.epoch {
return TryInto::<ExecutionPayloadHeaderSsz<C>>::try_into(header.execution.clone())
.unwrap()
.tree_hash_root();
}

// TODO: Figure out what to do here
// if epoch >= fork_parameters.capella.epoch {
// return CapellaExecutionPayloadHeader::from(header.execution.clone())
// .tree_hash_root()
// .into();
// }

H256::default()
}

Expand Down Expand Up @@ -285,8 +322,7 @@ pub fn is_valid_light_client_header<C: ChainSpec>(
validate_merkle_branch(
&get_lc_execution_root::<C>(fork_parameters, header),
&header.execution_branch,
floorlog2(EXECUTION_PAYLOAD_INDEX),
get_subtree_index(EXECUTION_PAYLOAD_INDEX),
EXECUTION_PAYLOAD_GINDEX,
&header.beacon.body_root,
)
}
Expand Down
23 changes: 12 additions & 11 deletions lib/ethereum-sync-protocol/src/utils.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use beacon_api_types::{
consts::{floorlog2, get_subtree_index},
Domain, DomainType, ForkData, ForkParameters, SigningData, Slot, Version,
EPOCHS_PER_SYNC_COMMITTEE_PERIOD, SECONDS_PER_SLOT, SLOTS_PER_EPOCH,
};
Expand Down Expand Up @@ -139,12 +140,12 @@ pub fn validate_signature_supermajority(sync_committee_bits: &[u8]) -> bool {
pub fn validate_merkle_branch<'a>(
leaf: &H256,
branch: impl IntoIterator<Item = &'a H256>,
depth: usize,
index: u64,
gindex: u64,
root: &H256,
) -> Result<(), Error> {
let depth = floorlog2(gindex);
let index = get_subtree_index(gindex);
let branch = branch.into_iter().cloned().collect::<Vec<_>>();

'block: {
let mut value = *leaf;

Expand Down Expand Up @@ -340,8 +341,8 @@ pub fn validate_merkle_branch<'a>(
// // validate_merkle_branch(
// // &valid_leaf,
// // &valid_branch,
// // floorlog2(EXECUTION_PAYLOAD_INDEX),
// // EXECUTION_PAYLOAD_INDEX,
// // floorlog2(EXECUTION_PAYLOAD_GINDEX),
// // EXECUTION_PAYLOAD_GINDEX,
// // &valid_root,
// // ),
// // Ok(())
Expand All @@ -351,8 +352,8 @@ pub fn validate_merkle_branch<'a>(
// // assert!(validate_merkle_branch(
// // &valid_leaf,
// // &valid_branch,
// // floorlog2(EXECUTION_PAYLOAD_INDEX),
// // EXECUTION_PAYLOAD_INDEX + 1,
// // floorlog2(EXECUTION_PAYLOAD_GINDEX),
// // EXECUTION_PAYLOAD_GINDEX + 1,
// // &valid_root,
// // )
// // .is_err());
Expand All @@ -367,8 +368,8 @@ pub fn validate_merkle_branch<'a>(
// // assert!(validate_merkle_branch(
// // &invalid_leaf,
// // &valid_branch,
// // floorlog2(EXECUTION_PAYLOAD_INDEX),
// // EXECUTION_PAYLOAD_INDEX,
// // floorlog2(EXECUTION_PAYLOAD_GINDEX),
// // EXECUTION_PAYLOAD_GINDEX,
// // &valid_root,
// // )
// // .is_err());
Expand All @@ -383,8 +384,8 @@ pub fn validate_merkle_branch<'a>(
// // assert!(validate_merkle_branch(
// // &valid_leaf,
// // &invalid_branch,
// // floorlog2(EXECUTION_PAYLOAD_INDEX),
// // EXECUTION_PAYLOAD_INDEX,
// // floorlog2(EXECUTION_PAYLOAD_GINDEX),
// // EXECUTION_PAYLOAD_GINDEX,
// // &valid_root,
// // )
// // .is_err());
Expand Down

0 comments on commit 8be7bf4

Please sign in to comment.