Skip to content

Commit a42d670

Browse files
authored
Merge pull request #3811 from etan-status/lc-electra
Update light client specifications for Electra
2 parents 2331291 + 460d46d commit a42d670

File tree

17 files changed

+800
-89
lines changed

17 files changed

+800
-89
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ Features are researched and developed in parallel, and then consolidated into se
2626
### In-development Specifications
2727
| Code Name or Topic | Specs | Notes |
2828
| - | - | - |
29-
| Electra | <ul><li>Core</li><ul><li>[Beacon Chain changes](specs/electra/beacon-chain.md)</li><li>[EIP-6110 fork](specs/electra/fork.md)</li></ul><li>Additions</li><ul><li>[Honest validator guide changes](specs/electra/validator.md)</li></ul></ul> |
29+
| Electra | <ul><li>Core</li><ul><li>[Beacon Chain changes](specs/electra/beacon-chain.md)</li><li>[EIP-6110 fork](specs/electra/fork.md)</li></ul><li>Additions</li><ul><li>[Light client sync protocol changes](specs/electra/light-client/sync-protocol.md) ([fork](specs/electra/light-client/fork.md), [full node](specs/electra/light-client/full-node.md), [networking](specs/electra/light-client/p2p-interface.md))</li></ul><ul><li>[Honest validator guide changes](specs/electra/validator.md)</li></ul></ul> |
3030
| Sharding (outdated) | <ul><li>Core</li><ul><li>[Beacon Chain changes](specs/_features/sharding/beacon-chain.md)</li></ul><li>Additions</li><ul><li>[P2P networking](specs/_features/sharding/p2p-interface.md)</li></ul></ul> |
3131
| Custody Game (outdated) | <ul><li>Core</li><ul><li>[Beacon Chain changes](specs/_features/custody_game/beacon-chain.md)</li></ul><li>Additions</li><ul><li>[Honest validator guide changes](specs/_features/custody_game/validator.md)</li></ul></ul> | Dependent on sharding |
3232
| Data Availability Sampling (outdated) | <ul><li>Core</li><ul><li>[Core types and functions](specs/_features/das/das-core.md)</li><li>[Fork choice changes](specs/_features/das/fork-choice.md)</li></ul><li>Additions</li><ul><li>[P2P Networking](specs/_features/das/p2p-interface.md)</li><li>[Sampling process](specs/_features/das/sampling.md)</li></ul></ul> | <ul><li> Dependent on sharding</li><li>[Technical explainer](https://hackmd.io/@HWeNw8hNRimMm2m2GH56Cw/B1YJPGkpD)</li></ul> |

pysetup/spec_builders/electra.py

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,10 @@ def imports(cls, preset_name: str):
1212
from eth2spec.deneb import {preset_name} as deneb
1313
'''
1414

15-
## TODO: deal with changed gindices
16-
1715
@classmethod
1816
def hardcoded_ssz_dep_constants(cls) -> Dict[str, str]:
1917
return {
20-
'FINALIZED_ROOT_GINDEX': 'GeneralizedIndex(169)',
21-
'CURRENT_SYNC_COMMITTEE_GINDEX': 'GeneralizedIndex(86)',
22-
'NEXT_SYNC_COMMITTEE_GINDEX': 'GeneralizedIndex(87)',
18+
'FINALIZED_ROOT_GINDEX_ELECTRA': 'GeneralizedIndex(169)',
19+
'CURRENT_SYNC_COMMITTEE_GINDEX_ELECTRA': 'GeneralizedIndex(86)',
20+
'NEXT_SYNC_COMMITTEE_GINDEX_ELECTRA': 'GeneralizedIndex(87)',
2321
}

specs/altair/light-client/full-node.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ def create_light_client_bootstrap(state: BeaconState,
7676
header=block_to_light_client_header(block),
7777
current_sync_committee=state.current_sync_committee,
7878
current_sync_committee_branch=CurrentSyncCommitteeBranch(
79-
compute_merkle_proof(state, CURRENT_SYNC_COMMITTEE_GINDEX)),
79+
compute_merkle_proof(state, current_sync_committee_gindex_at_slot(state.slot))),
8080
)
8181
```
8282

@@ -124,7 +124,7 @@ def create_light_client_update(state: BeaconState,
124124
if update_attested_period == update_signature_period:
125125
update.next_sync_committee = attested_state.next_sync_committee
126126
update.next_sync_committee_branch = NextSyncCommitteeBranch(
127-
compute_merkle_proof(attested_state, NEXT_SYNC_COMMITTEE_GINDEX))
127+
compute_merkle_proof(attested_state, next_sync_committee_gindex_at_slot(attested_state.slot)))
128128

129129
# Indicate finality whenever possible
130130
if finalized_block is not None:
@@ -134,7 +134,7 @@ def create_light_client_update(state: BeaconState,
134134
else:
135135
assert attested_state.finalized_checkpoint.root == Bytes32()
136136
update.finality_branch = FinalityBranch(
137-
compute_merkle_proof(attested_state, FINALIZED_ROOT_GINDEX))
137+
compute_merkle_proof(attested_state, finalized_root_gindex_at_slot(attested_state.slot)))
138138

139139
update.sync_aggregate = block.message.body.sync_aggregate
140140
update.signature_slot = block.message.slot

specs/altair/light-client/sync-protocol.md

Lines changed: 50 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,17 @@
2121
- [`LightClientOptimisticUpdate`](#lightclientoptimisticupdate)
2222
- [`LightClientStore`](#lightclientstore)
2323
- [Helper functions](#helper-functions)
24+
- [`finalized_root_gindex_at_slot`](#finalized_root_gindex_at_slot)
25+
- [`current_sync_committee_gindex_at_slot`](#current_sync_committee_gindex_at_slot)
26+
- [`next_sync_committee_gindex_at_slot`](#next_sync_committee_gindex_at_slot)
2427
- [`is_valid_light_client_header`](#is_valid_light_client_header)
2528
- [`is_sync_committee_update`](#is_sync_committee_update)
2629
- [`is_finality_update`](#is_finality_update)
2730
- [`is_better_update`](#is_better_update)
2831
- [`is_next_sync_committee_known`](#is_next_sync_committee_known)
2932
- [`get_safety_threshold`](#get_safety_threshold)
3033
- [`get_subtree_index`](#get_subtree_index)
34+
- [`is_valid_normalized_merkle_branch`](#is_valid_normalized_merkle_branch)
3135
- [`compute_sync_committee_period_at_slot`](#compute_sync_committee_period_at_slot)
3236
- [Light client initialization](#light-client-initialization)
3337
- [`initialize_light_client_store`](#initialize_light_client_store)
@@ -171,6 +175,30 @@ class LightClientStore(object):
171175

172176
## Helper functions
173177

178+
### `finalized_root_gindex_at_slot`
179+
180+
```python
181+
def finalized_root_gindex_at_slot(slot: Slot) -> GeneralizedIndex:
182+
# pylint: disable=unused-argument
183+
return FINALIZED_ROOT_GINDEX
184+
```
185+
186+
### `current_sync_committee_gindex_at_slot`
187+
188+
```python
189+
def current_sync_committee_gindex_at_slot(slot: Slot) -> GeneralizedIndex:
190+
# pylint: disable=unused-argument
191+
return CURRENT_SYNC_COMMITTEE_GINDEX
192+
```
193+
194+
### `next_sync_committee_gindex_at_slot`
195+
196+
```python
197+
def next_sync_committee_gindex_at_slot(slot: Slot) -> GeneralizedIndex:
198+
# pylint: disable=unused-argument
199+
return NEXT_SYNC_COMMITTEE_GINDEX
200+
```
201+
174202
### `is_valid_light_client_header`
175203

176204
```python
@@ -273,6 +301,22 @@ def get_subtree_index(generalized_index: GeneralizedIndex) -> uint64:
273301
return uint64(generalized_index % 2**(floorlog2(generalized_index)))
274302
```
275303

304+
### `is_valid_normalized_merkle_branch`
305+
306+
```python
307+
def is_valid_normalized_merkle_branch(leaf: Bytes32,
308+
branch: Sequence[Bytes32],
309+
gindex: GeneralizedIndex,
310+
root: Root) -> bool:
311+
depth = floorlog2(gindex)
312+
index = get_subtree_index(gindex)
313+
num_extra = len(branch) - depth
314+
for i in range(num_extra):
315+
if branch[i] != Bytes32():
316+
return False
317+
return is_valid_merkle_branch(leaf, branch[num_extra:], depth, index, root)
318+
```
319+
276320
### `compute_sync_committee_period_at_slot`
277321

278322
```python
@@ -292,11 +336,10 @@ def initialize_light_client_store(trusted_block_root: Root,
292336
assert is_valid_light_client_header(bootstrap.header)
293337
assert hash_tree_root(bootstrap.header.beacon) == trusted_block_root
294338

295-
assert is_valid_merkle_branch(
339+
assert is_valid_normalized_merkle_branch(
296340
leaf=hash_tree_root(bootstrap.current_sync_committee),
297341
branch=bootstrap.current_sync_committee_branch,
298-
depth=floorlog2(CURRENT_SYNC_COMMITTEE_GINDEX),
299-
index=get_subtree_index(CURRENT_SYNC_COMMITTEE_GINDEX),
342+
gindex=current_sync_committee_gindex_at_slot(bootstrap.header.beacon.slot),
300343
root=bootstrap.header.beacon.state_root,
301344
)
302345

@@ -364,11 +407,10 @@ def validate_light_client_update(store: LightClientStore,
364407
else:
365408
assert is_valid_light_client_header(update.finalized_header)
366409
finalized_root = hash_tree_root(update.finalized_header.beacon)
367-
assert is_valid_merkle_branch(
410+
assert is_valid_normalized_merkle_branch(
368411
leaf=finalized_root,
369412
branch=update.finality_branch,
370-
depth=floorlog2(FINALIZED_ROOT_GINDEX),
371-
index=get_subtree_index(FINALIZED_ROOT_GINDEX),
413+
gindex=finalized_root_gindex_at_slot(update.attested_header.beacon.slot),
372414
root=update.attested_header.beacon.state_root,
373415
)
374416

@@ -379,11 +421,10 @@ def validate_light_client_update(store: LightClientStore,
379421
else:
380422
if update_attested_period == store_period and is_next_sync_committee_known(store):
381423
assert update.next_sync_committee == store.next_sync_committee
382-
assert is_valid_merkle_branch(
424+
assert is_valid_normalized_merkle_branch(
383425
leaf=hash_tree_root(update.next_sync_committee),
384426
branch=update.next_sync_committee_branch,
385-
depth=floorlog2(NEXT_SYNC_COMMITTEE_GINDEX),
386-
index=get_subtree_index(NEXT_SYNC_COMMITTEE_GINDEX),
427+
gindex=next_sync_committee_gindex_at_slot(update.attested_header.beacon.slot),
387428
root=update.attested_header.beacon.state_root,
388429
)
389430

specs/capella/light-client/fork.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@
77
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
88

99
- [Introduction](#introduction)
10-
- [Upgrading light client data](#upgrading-light-client-data)
11-
- [Upgrading the store](#upgrading-the-store)
10+
- [Upgrading light client data](#upgrading-light-client-data)
11+
- [Upgrading the store](#upgrading-the-store)
1212

1313
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
1414
<!-- /TOC -->
@@ -17,7 +17,7 @@
1717

1818
This document describes how to upgrade existing light client objects based on the [Altair specification](../../altair/light-client/sync-protocol.md) to Capella. This is necessary when processing pre-Capella data with a post-Capella `LightClientStore`. Note that the data being exchanged over the network protocols uses the original format.
1919

20-
### Upgrading light client data
20+
## Upgrading light client data
2121

2222
A Capella `LightClientStore` can still process earlier light client data. In order to do so, that pre-Capella data needs to be locally upgraded to Capella before processing.
2323

@@ -70,7 +70,7 @@ def upgrade_lc_optimistic_update_to_capella(pre: bellatrix.LightClientOptimistic
7070
)
7171
```
7272

73-
### Upgrading the store
73+
## Upgrading the store
7474

7575
Existing `LightClientStore` objects based on Altair MUST be upgraded to Capella before Capella based light client data can be processed. The `LightClientStore` upgrade MAY be performed before `CAPELLA_FORK_EPOCH`.
7676

specs/deneb/light-client/fork.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@
77
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
88

99
- [Introduction](#introduction)
10-
- [Upgrading light client data](#upgrading-light-client-data)
11-
- [Upgrading the store](#upgrading-the-store)
10+
- [Upgrading light client data](#upgrading-light-client-data)
11+
- [Upgrading the store](#upgrading-the-store)
1212

1313
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
1414
<!-- /TOC -->
@@ -17,7 +17,7 @@
1717

1818
This document describes how to upgrade existing light client objects based on the [Capella specification](../../capella/light-client/sync-protocol.md) to Deneb. This is necessary when processing pre-Deneb data with a post-Deneb `LightClientStore`. Note that the data being exchanged over the network protocols uses the original format.
1919

20-
### Upgrading light client data
20+
## Upgrading light client data
2121

2222
A Deneb `LightClientStore` can still process earlier light client data. In order to do so, that pre-Deneb data needs to be locally upgraded to Deneb before processing.
2323

@@ -90,7 +90,7 @@ def upgrade_lc_optimistic_update_to_deneb(pre: capella.LightClientOptimisticUpda
9090
)
9191
```
9292

93-
### Upgrading the store
93+
## Upgrading the store
9494

9595
Existing `LightClientStore` objects based on Capella MUST be upgraded to Deneb before Deneb based light client data can be processed. The `LightClientStore` upgrade MAY be performed before `DENEB_FORK_EPOCH`.
9696

specs/deneb/light-client/full-node.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717

1818
## Introduction
1919

20-
This upgrade adds information about the execution payload to light client data as part of the Deneb upgrade.
20+
Execution payload data is updated to account for the Deneb upgrade.
2121

2222
## Helper functions
2323

specs/electra/light-client/fork.md

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
# Electra Light Client -- Fork Logic
2+
3+
## Table of contents
4+
5+
<!-- TOC -->
6+
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
7+
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
8+
9+
- [Introduction](#introduction)
10+
- [Helper functions](#helper-functions)
11+
- [`normalize_merkle_branch`](#normalize_merkle_branch)
12+
- [Upgrading light client data](#upgrading-light-client-data)
13+
- [Upgrading the store](#upgrading-the-store)
14+
15+
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
16+
<!-- /TOC -->
17+
18+
## Introduction
19+
20+
This document describes how to upgrade existing light client objects based on the [Deneb specification](../../deneb/light-client/sync-protocol.md) to Electra. This is necessary when processing pre-Electra data with a post-Electra `LightClientStore`. Note that the data being exchanged over the network protocols uses the original format.
21+
22+
## Helper functions
23+
24+
### `normalize_merkle_branch`
25+
26+
```python
27+
def normalize_merkle_branch(branch: Sequence[Bytes32],
28+
gindex: GeneralizedIndex) -> Sequence[Bytes32]:
29+
depth = floorlog2(gindex)
30+
num_extra = depth - len(branch)
31+
return [Bytes32()] * num_extra + [*branch]
32+
```
33+
34+
## Upgrading light client data
35+
36+
A Electra `LightClientStore` can still process earlier light client data. In order to do so, that pre-Electra data needs to be locally upgraded to Electra before processing.
37+
38+
```python
39+
def upgrade_lc_header_to_electra(pre: deneb.LightClientHeader) -> LightClientHeader:
40+
return LightClientHeader(
41+
beacon=pre.beacon,
42+
execution=ExecutionPayloadHeader(
43+
parent_hash=pre.execution.parent_hash,
44+
fee_recipient=pre.execution.fee_recipient,
45+
state_root=pre.execution.state_root,
46+
receipts_root=pre.execution.receipts_root,
47+
logs_bloom=pre.execution.logs_bloom,
48+
prev_randao=pre.execution.prev_randao,
49+
block_number=pre.execution.block_number,
50+
gas_limit=pre.execution.gas_limit,
51+
gas_used=pre.execution.gas_used,
52+
timestamp=pre.execution.timestamp,
53+
extra_data=pre.execution.extra_data,
54+
base_fee_per_gas=pre.execution.base_fee_per_gas,
55+
block_hash=pre.execution.block_hash,
56+
transactions_root=pre.execution.transactions_root,
57+
withdrawals_root=pre.execution.withdrawals_root,
58+
blob_gas_used=pre.execution.blob_gas_used,
59+
excess_blob_gas=pre.execution.blob_gas_used,
60+
deposit_requests_root=Root(), # [New in Electra:EIP6110]
61+
withdrawal_requests_root=Root(), # [New in Electra:EIP7002:EIP7251]
62+
consolidation_requests_root=Root(), # [New in Electra:EIP7251]
63+
),
64+
execution_branch=pre.execution_branch,
65+
)
66+
```
67+
68+
```python
69+
def upgrade_lc_bootstrap_to_electra(pre: deneb.LightClientBootstrap) -> LightClientBootstrap:
70+
return LightClientBootstrap(
71+
header=upgrade_lc_header_to_electra(pre.header),
72+
current_sync_committee=pre.current_sync_committee,
73+
current_sync_committee_branch=normalize_merkle_branch(
74+
pre.current_sync_committee_branch, CURRENT_SYNC_COMMITTEE_GINDEX_ELECTRA),
75+
)
76+
```
77+
78+
```python
79+
def upgrade_lc_update_to_electra(pre: deneb.LightClientUpdate) -> LightClientUpdate:
80+
return LightClientUpdate(
81+
attested_header=upgrade_lc_header_to_electra(pre.attested_header),
82+
next_sync_committee=pre.next_sync_committee,
83+
next_sync_committee_branch=normalize_merkle_branch(
84+
pre.next_sync_committee_branch, NEXT_SYNC_COMMITTEE_GINDEX_ELECTRA),
85+
finalized_header=upgrade_lc_header_to_electra(pre.finalized_header),
86+
finality_branch=normalize_merkle_branch(
87+
pre.finality_branch, FINALIZED_ROOT_GINDEX_ELECTRA),
88+
sync_aggregate=pre.sync_aggregate,
89+
signature_slot=pre.signature_slot,
90+
)
91+
```
92+
93+
```python
94+
def upgrade_lc_finality_update_to_electra(pre: deneb.LightClientFinalityUpdate) -> LightClientFinalityUpdate:
95+
return LightClientFinalityUpdate(
96+
attested_header=upgrade_lc_header_to_electra(pre.attested_header),
97+
finalized_header=upgrade_lc_header_to_electra(pre.finalized_header),
98+
finality_branch=normalize_merkle_branch(
99+
pre.finality_branch, FINALIZED_ROOT_GINDEX_ELECTRA),
100+
sync_aggregate=pre.sync_aggregate,
101+
signature_slot=pre.signature_slot,
102+
)
103+
```
104+
105+
```python
106+
def upgrade_lc_optimistic_update_to_electra(pre: deneb.LightClientOptimisticUpdate) -> LightClientOptimisticUpdate:
107+
return LightClientOptimisticUpdate(
108+
attested_header=upgrade_lc_header_to_electra(pre.attested_header),
109+
sync_aggregate=pre.sync_aggregate,
110+
signature_slot=pre.signature_slot,
111+
)
112+
```
113+
114+
## Upgrading the store
115+
116+
Existing `LightClientStore` objects based on Deneb MUST be upgraded to Electra before Electra based light client data can be processed. The `LightClientStore` upgrade MAY be performed before `ELECTRA_FORK_EPOCH`.
117+
118+
```python
119+
def upgrade_lc_store_to_electra(pre: deneb.LightClientStore) -> LightClientStore:
120+
if pre.best_valid_update is None:
121+
best_valid_update = None
122+
else:
123+
best_valid_update = upgrade_lc_update_to_electra(pre.best_valid_update)
124+
return LightClientStore(
125+
finalized_header=upgrade_lc_header_to_electra(pre.finalized_header),
126+
current_sync_committee=pre.current_sync_committee,
127+
next_sync_committee=pre.next_sync_committee,
128+
best_valid_update=best_valid_update,
129+
optimistic_header=upgrade_lc_header_to_electra(pre.optimistic_header),
130+
previous_max_active_participants=pre.previous_max_active_participants,
131+
current_max_active_participants=pre.current_max_active_participants,
132+
)
133+
```

0 commit comments

Comments
 (0)