Skip to content

Commit 41de505

Browse files
feat(eth-lc): handle electra fork
1 parent 7e0cd6c commit 41de505

File tree

9 files changed

+84
-58
lines changed

9 files changed

+84
-58
lines changed

lib/beacon-api-types/src/lib.rs

+9-5
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ use std::{
6363

6464
use hex_literal::hex;
6565
use typenum::{NonZero, Unsigned};
66-
use unionlabs::primitives::FixedBytes;
66+
use unionlabs::primitives::{FixedBytes, H256};
6767

6868
pub use crate::{
6969
attestation::Attestation, attestation_data::AttestationData,
@@ -368,6 +368,10 @@ consts_traits![
368368
mk_chain_spec!(Minimal is preset::MINIMAL);
369369
mk_chain_spec!(Mainnet is preset::MAINNET);
370370

371+
pub type CurrentSyncCommitteeBranch = Vec<H256>;
372+
pub type NextSyncCommitteeBranch = Vec<H256>;
373+
pub type FinalityBranch = Vec<H256>;
374+
371375
/// Values that are constant across all configurations.
372376
pub mod consts {
373377
/// <https://github.com/ethereum/consensus-specs/blob/dev/specs/altair/light-client/sync-protocol.md#get_subtree_index>
@@ -389,13 +393,13 @@ pub mod consts {
389393

390394
// https://github.com/ethereum/consensus-specs/blob/dev/ssz/merkle-proofs.md
391395
/// `get_generalized_index(BeaconState, "finalized_checkpoint", "root")`
392-
pub const FINALIZED_ROOT_INDEX: u64 = 105;
396+
pub const FINALIZED_ROOT_GINDEX: u64 = 105;
393397
/// `get_generalized_index(BeaconState, "current_sync_committee")`
394-
pub const CURRENT_SYNC_COMMITTEE_INDEX: u64 = 54;
398+
pub const CURRENT_SYNC_COMMITTEE_GINDEX: u64 = 54;
395399
/// `get_generalized_index(BeaconState, "next_sync_committee")`
396-
pub const NEXT_SYNC_COMMITTEE_INDEX: u64 = 55;
400+
pub const NEXT_SYNC_COMMITTEE_GINDEX: u64 = 55;
397401
/// `get_generalized_index(BeaconBlockBody, "execution_payload")`
398-
pub const EXECUTION_PAYLOAD_INDEX: u64 = 25;
402+
pub const EXECUTION_PAYLOAD_GINDEX: u64 = 25;
399403

400404
// https://github.com/ethereum/consensus-specs/blob/dev/specs/electra/light-client/sync-protocol.md#new-constants
401405
pub const FINALIZED_ROOT_GINDEX_ELECTRA: u64 = 169;
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
1-
use unionlabs::primitives::H256;
2-
31
use crate::{
4-
consts::{floorlog2, CURRENT_SYNC_COMMITTEE_INDEX},
52
light_client_header::LightClientHeader,
63
sync_committee::SyncCommittee,
4+
CurrentSyncCommitteeBranch,
75
};
86

97
#[derive(Debug, Clone, PartialEq)]
@@ -12,5 +10,5 @@ pub struct LightClientBootstrap {
1210
pub header: LightClientHeader,
1311
/// Current sync committee corresponding to `beacon_header.state_root`
1412
pub current_sync_committee: SyncCommittee,
15-
pub current_sync_committee_branch: [H256; floorlog2(CURRENT_SYNC_COMMITTEE_INDEX)],
13+
pub current_sync_committee_branch: CurrentSyncCommitteeBranch,
1614
}

lib/beacon-api-types/src/light_client_finality_update.rs

+2-8
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,4 @@
1-
use unionlabs::primitives::H256;
2-
3-
use crate::{
4-
consts::{floorlog2, FINALIZED_ROOT_INDEX},
5-
light_client_header::LightClientHeader,
6-
Slot, SyncAggregate,
7-
};
1+
use crate::{light_client_header::LightClientHeader, FinalityBranch, Slot, SyncAggregate};
82

93
#[derive(Debug, Clone, PartialEq)]
104
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
@@ -13,7 +7,7 @@ pub struct LightClientFinalityUpdate {
137
pub attested_header: LightClientHeader,
148
/// Finalized header corresponding to `attested_header.state_root`
159
pub finalized_header: LightClientHeader,
16-
pub finality_branch: [H256; floorlog2(FINALIZED_ROOT_INDEX)],
10+
pub finality_branch: FinalityBranch,
1711
/// Sync committee aggregate signature
1812
pub sync_aggregate: SyncAggregate,
1913
/// Slot at which the aggregate signature was created (untrusted)

lib/beacon-api-types/src/light_client_header.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use unionlabs::primitives::H256;
22

33
use crate::{
44
beacon_block_header::BeaconBlockHeader,
5-
consts::{floorlog2, EXECUTION_PAYLOAD_INDEX},
5+
consts::{floorlog2, EXECUTION_PAYLOAD_GINDEX},
66
execution_payload_header::ExecutionPayloadHeader,
77
};
88

@@ -12,7 +12,7 @@ use crate::{
1212
pub struct LightClientHeader {
1313
pub beacon: BeaconBlockHeader,
1414
pub execution: ExecutionPayloadHeader,
15-
pub execution_branch: [H256; floorlog2(EXECUTION_PAYLOAD_INDEX)],
15+
pub execution_branch: [H256; floorlog2(EXECUTION_PAYLOAD_GINDEX)],
1616
}
1717

1818
#[cfg(feature = "ssz")]
@@ -25,5 +25,5 @@ pub struct LightClientHeader {
2525
pub struct LightClientHeaderSsz<C: crate::BYTES_PER_LOGS_BLOOM + crate::MAX_EXTRA_DATA_BYTES> {
2626
pub beacon: BeaconBlockHeader,
2727
pub execution: crate::ExecutionPayloadHeaderSsz<C>,
28-
pub execution_branch: [H256; floorlog2(EXECUTION_PAYLOAD_INDEX)],
28+
pub execution_branch: [H256; floorlog2(EXECUTION_PAYLOAD_GINDEX)],
2929
}

lib/beacon-api-types/src/light_client_update.rs

+1-7
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,7 @@
1-
use unionlabs::primitives::H256;
2-
31
use crate::{
4-
consts::{floorlog2, FINALIZED_ROOT_INDEX, NEXT_SYNC_COMMITTEE_INDEX},
5-
LightClientHeader, Slot, SyncAggregate, SyncCommittee,
2+
FinalityBranch, LightClientHeader, NextSyncCommitteeBranch, Slot, SyncAggregate, SyncCommittee,
63
};
74

8-
pub type NextSyncCommitteeBranch = [H256; floorlog2(NEXT_SYNC_COMMITTEE_INDEX)];
9-
pub type FinalityBranch = [H256; floorlog2(FINALIZED_ROOT_INDEX)];
10-
115
#[derive(Debug, Clone, PartialEq)]
126
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
137
pub struct LightClientUpdate {

lib/ethereum-light-client-types/src/light_client_update.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use beacon_api_types::{light_client_update::NextSyncCommitteeBranch, SyncCommittee};
1+
use beacon_api_types::{NextSyncCommitteeBranch, SyncCommittee};
22

33
use crate::LightClientUpdateData;
44

lib/ethereum-light-client-types/src/light_client_update_data.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
use beacon_api_types::{
2-
light_client_update::{FinalityBranch, NextSyncCommitteeBranch},
3-
LightClientHeader, Slot, SyncAggregate, SyncCommittee,
2+
FinalityBranch, LightClientHeader, NextSyncCommitteeBranch, Slot, SyncAggregate, SyncCommittee
43
};
54

65
/// Common data required for all light client updates.

lib/ethereum-sync-protocol/src/lib.rs

+53-17
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,9 @@ pub mod utils;
77

88
use beacon_api_types::{
99
consts::{
10-
floorlog2, get_subtree_index, EXECUTION_PAYLOAD_INDEX, FINALIZED_ROOT_INDEX,
11-
NEXT_SYNC_COMMITTEE_INDEX,
10+
CURRENT_SYNC_COMMITTEE_GINDEX, CURRENT_SYNC_COMMITTEE_GINDEX_ELECTRA,
11+
EXECUTION_PAYLOAD_GINDEX, FINALIZED_ROOT_GINDEX, FINALIZED_ROOT_GINDEX_ELECTRA,
12+
NEXT_SYNC_COMMITTEE_GINDEX, NEXT_SYNC_COMMITTEE_GINDEX_ELECTRA,
1213
},
1314
light_client_update::LightClientUpdate,
1415
ChainSpec, DomainType, ExecutionPayloadHeaderSsz, ForkParameters, LightClientHeader, Slot,
@@ -42,6 +43,42 @@ pub trait BlsVerify {
4243
) -> Result<(), Error>;
4344
}
4445

46+
// https://github.com/ethereum/consensus-specs/blob/dev/specs/altair/light-client/sync-protocol.md#finalized_root_gindex_at_slot
47+
pub fn finalized_root_gindex_at_slot<C: ChainSpec>(
48+
fork_parameters: &ForkParameters,
49+
slot: Slot,
50+
) -> u64 {
51+
let epoch = compute_epoch_at_slot::<C>(slot);
52+
if epoch >= fork_parameters.electra.epoch {
53+
return FINALIZED_ROOT_GINDEX_ELECTRA;
54+
}
55+
FINALIZED_ROOT_GINDEX
56+
}
57+
58+
// https://github.com/ethereum/consensus-specs/blob/dev/specs/altair/light-client/sync-protocol.md#current_sync_committee_gindex_at_slot
59+
pub fn current_sync_committee_gindex_at_slot<C: ChainSpec>(
60+
fork_parameters: &ForkParameters,
61+
slot: Slot,
62+
) -> u64 {
63+
let epoch = compute_epoch_at_slot::<C>(slot);
64+
if epoch >= fork_parameters.electra.epoch {
65+
return CURRENT_SYNC_COMMITTEE_GINDEX_ELECTRA;
66+
}
67+
CURRENT_SYNC_COMMITTEE_GINDEX
68+
}
69+
70+
// https://github.com/ethereum/consensus-specs/blob/dev/specs/altair/light-client/sync-protocol.md#next_sync_committee_gindex_at_slot
71+
pub fn next_sync_committee_gindex_at_slot<C: ChainSpec>(
72+
fork_parameters: &ForkParameters,
73+
slot: Slot,
74+
) -> u64 {
75+
let epoch = compute_epoch_at_slot::<C>(slot);
76+
if epoch >= fork_parameters.electra.epoch {
77+
return NEXT_SYNC_COMMITTEE_GINDEX_ELECTRA;
78+
}
79+
NEXT_SYNC_COMMITTEE_GINDEX
80+
}
81+
4582
/// Verifies if the light client `update` is valid.
4683
///
4784
/// * `update`: The light client update we want to verify.
@@ -169,8 +206,7 @@ pub fn validate_light_client_update<C: ChainSpec, V: BlsVerify>(
169206
validate_merkle_branch(
170207
&update.finalized_header.beacon.tree_hash_root(),
171208
&update.finality_branch,
172-
floorlog2(FINALIZED_ROOT_INDEX),
173-
get_subtree_index(FINALIZED_ROOT_INDEX),
209+
finalized_root_gindex_at_slot::<C>(fork_parameters, update_attested_slot),
174210
&update.attested_header.beacon.state_root,
175211
)?;
176212

@@ -188,14 +224,17 @@ pub fn validate_light_client_update<C: ChainSpec, V: BlsVerify>(
188224
},
189225
)?;
190226
}
227+
191228
// This validates the given next sync committee against the attested header's state root.
192229
validate_merkle_branch(
193230
&TryInto::<SyncCommitteeSsz<C>>::try_into(next_sync_committee.clone())
194231
.unwrap()
195232
.tree_hash_root(),
196-
&update.next_sync_committee_branch.unwrap_or_default(),
197-
floorlog2(NEXT_SYNC_COMMITTEE_INDEX),
198-
get_subtree_index(NEXT_SYNC_COMMITTEE_INDEX),
233+
&update
234+
.next_sync_committee_branch
235+
.clone()
236+
.unwrap_or_default()[..],
237+
next_sync_committee_gindex_at_slot::<C>(fork_parameters, update_attested_slot),
199238
&update.attested_header.beacon.state_root,
200239
)?;
201240
}
@@ -245,19 +284,17 @@ pub fn get_lc_execution_root<C: ChainSpec>(
245284
header: &LightClientHeader,
246285
) -> H256 {
247286
let epoch = compute_epoch_at_slot::<C>(header.beacon.slot);
287+
// Now new field in electra
288+
if epoch >= fork_parameters.electra.epoch {
289+
return TryInto::<ExecutionPayloadHeaderSsz<C>>::try_into(header.execution.clone())
290+
.unwrap()
291+
.tree_hash_root();
292+
}
248293
if epoch >= fork_parameters.deneb.epoch {
249294
return TryInto::<ExecutionPayloadHeaderSsz<C>>::try_into(header.execution.clone())
250295
.unwrap()
251296
.tree_hash_root();
252297
}
253-
254-
// TODO: Figure out what to do here
255-
// if epoch >= fork_parameters.capella.epoch {
256-
// return CapellaExecutionPayloadHeader::from(header.execution.clone())
257-
// .tree_hash_root()
258-
// .into();
259-
// }
260-
261298
H256::default()
262299
}
263300

@@ -285,8 +322,7 @@ pub fn is_valid_light_client_header<C: ChainSpec>(
285322
validate_merkle_branch(
286323
&get_lc_execution_root::<C>(fork_parameters, header),
287324
&header.execution_branch,
288-
floorlog2(EXECUTION_PAYLOAD_INDEX),
289-
get_subtree_index(EXECUTION_PAYLOAD_INDEX),
325+
EXECUTION_PAYLOAD_GINDEX,
290326
&header.beacon.body_root,
291327
)
292328
}

lib/ethereum-sync-protocol/src/utils.rs

+12-11
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use beacon_api_types::{
2+
consts::{floorlog2, get_subtree_index},
23
Domain, DomainType, ForkData, ForkParameters, SigningData, Slot, Version,
34
EPOCHS_PER_SYNC_COMMITTEE_PERIOD, SECONDS_PER_SLOT, SLOTS_PER_EPOCH,
45
};
@@ -139,12 +140,12 @@ pub fn validate_signature_supermajority(sync_committee_bits: &[u8]) -> bool {
139140
pub fn validate_merkle_branch<'a>(
140141
leaf: &H256,
141142
branch: impl IntoIterator<Item = &'a H256>,
142-
depth: usize,
143-
index: u64,
143+
gindex: u64,
144144
root: &H256,
145145
) -> Result<(), Error> {
146+
let depth = floorlog2(gindex);
147+
let index = get_subtree_index(gindex);
146148
let branch = branch.into_iter().cloned().collect::<Vec<_>>();
147-
148149
'block: {
149150
let mut value = *leaf;
150151

@@ -340,8 +341,8 @@ pub fn validate_merkle_branch<'a>(
340341
// // validate_merkle_branch(
341342
// // &valid_leaf,
342343
// // &valid_branch,
343-
// // floorlog2(EXECUTION_PAYLOAD_INDEX),
344-
// // EXECUTION_PAYLOAD_INDEX,
344+
// // floorlog2(EXECUTION_PAYLOAD_GINDEX),
345+
// // EXECUTION_PAYLOAD_GINDEX,
345346
// // &valid_root,
346347
// // ),
347348
// // Ok(())
@@ -351,8 +352,8 @@ pub fn validate_merkle_branch<'a>(
351352
// // assert!(validate_merkle_branch(
352353
// // &valid_leaf,
353354
// // &valid_branch,
354-
// // floorlog2(EXECUTION_PAYLOAD_INDEX),
355-
// // EXECUTION_PAYLOAD_INDEX + 1,
355+
// // floorlog2(EXECUTION_PAYLOAD_GINDEX),
356+
// // EXECUTION_PAYLOAD_GINDEX + 1,
356357
// // &valid_root,
357358
// // )
358359
// // .is_err());
@@ -367,8 +368,8 @@ pub fn validate_merkle_branch<'a>(
367368
// // assert!(validate_merkle_branch(
368369
// // &invalid_leaf,
369370
// // &valid_branch,
370-
// // floorlog2(EXECUTION_PAYLOAD_INDEX),
371-
// // EXECUTION_PAYLOAD_INDEX,
371+
// // floorlog2(EXECUTION_PAYLOAD_GINDEX),
372+
// // EXECUTION_PAYLOAD_GINDEX,
372373
// // &valid_root,
373374
// // )
374375
// // .is_err());
@@ -383,8 +384,8 @@ pub fn validate_merkle_branch<'a>(
383384
// // assert!(validate_merkle_branch(
384385
// // &valid_leaf,
385386
// // &invalid_branch,
386-
// // floorlog2(EXECUTION_PAYLOAD_INDEX),
387-
// // EXECUTION_PAYLOAD_INDEX,
387+
// // floorlog2(EXECUTION_PAYLOAD_GINDEX),
388+
// // EXECUTION_PAYLOAD_GINDEX,
388389
// // &valid_root,
389390
// // )
390391
// // .is_err());

0 commit comments

Comments
 (0)