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

feat(eth-lc): electra fork #3878

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
19 changes: 14 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 {
use hex_literal::hex;
Expand All @@ -394,13 +398,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;
Comment on lines +401 to +407
Copy link
Contributor

Choose a reason for hiding this comment

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

rename the old ones to deneb?


pub const fn default_epoch() -> u64 {
u64::MAX
Expand All @@ -412,6 +416,11 @@ pub mod consts {
epoch: default_epoch(),
}
}

// 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;
pub const CURRENT_SYNC_COMMITTEE_GINDEX_ELECTRA: u64 = 86;
pub const NEXT_SYNC_COMMITTEE_GINDEX_ELECTRA: u64 = 87;
}

pub mod preset {
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
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
}

Comment on lines +46 to +81
Copy link
Contributor

Choose a reason for hiding this comment

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

small nit but make the links doc comments: /// <link>

/// 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();
}
Comment on lines +287 to 297
Copy link
Contributor

Choose a reason for hiding this comment

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

these branches are the same?


// 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
27 changes: 15 additions & 12 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 All @@ -17,7 +18,9 @@ use crate::{
///
/// [See in consensus-spec](https://github.com/ethereum/consensus-specs/blob/dev/specs/capella/fork.md#modified-compute_fork_version)
pub fn compute_fork_version(fork_parameters: &ForkParameters, epoch: u64) -> Version {
if epoch >= fork_parameters.deneb.epoch {
if epoch >= fork_parameters.electra.epoch {
fork_parameters.electra.version
} else if epoch >= fork_parameters.deneb.epoch {
fork_parameters.deneb.version
} else if epoch >= fork_parameters.capella.epoch {
fork_parameters.capella.version
Expand Down Expand Up @@ -137,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 @@ -338,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 @@ -349,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 @@ -365,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 @@ -381,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