support EIP4844 LC data format (#4520)

Implements the proposed light client data format for EIP4844:
- https://github.com/ethereum/consensus-specs/pull/3151
This commit is contained in:
Etan Kissling 2023-01-19 23:53:37 +01:00 committed by GitHub
parent 819e007689
commit 65ca523482
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 620 additions and 69 deletions

View File

@ -2023,6 +2023,14 @@ OK: 1/1 Fail: 0/1 Skip: 0/1
+ Testing Withdrawal OK
```
OK: 48/48 Fail: 0/48 Skip: 0/48
## EF - EIP4844 - Unittests - Light client - Sync protocol [Preset: mainnet]
```diff
+ process_light_client_update_finality_updated OK
+ process_light_client_update_timeout OK
+ test_process_light_client_update_at_period_boundary OK
+ test_process_light_client_update_not_timeout OK
```
OK: 4/4 Fail: 0/4 Skip: 0/4
## EF - Phase 0 - Epoch Processing - Effective balance updates [Preset: mainnet]
```diff
+ Effective balance updates - effective_balance_hysteresis [Preset: mainnet] OK
@ -2588,4 +2596,4 @@ OK: 63/63 Fail: 0/63 Skip: 0/63
OK: 100/100 Fail: 0/100 Skip: 0/100
---TOTAL---
OK: 2289/2298 Fail: 0/2298 Skip: 9/2298
OK: 2293/2302 Fail: 0/2302 Skip: 9/2302

View File

@ -2187,6 +2187,14 @@ OK: 5/5 Fail: 0/5 Skip: 0/5
+ Testing Withdrawal OK
```
OK: 48/48 Fail: 0/48 Skip: 0/48
## EF - EIP4844 - Unittests - Light client - Sync protocol [Preset: minimal]
```diff
+ process_light_client_update_finality_updated OK
+ process_light_client_update_timeout OK
+ test_process_light_client_update_at_period_boundary OK
+ test_process_light_client_update_not_timeout OK
```
OK: 4/4 Fail: 0/4 Skip: 0/4
## EF - Phase 0 - Epoch Processing - Effective balance updates [Preset: minimal]
```diff
+ Effective balance updates - effective_balance_hysteresis [Preset: minimal] OK
@ -2755,4 +2763,4 @@ OK: 68/68 Fail: 0/68 Skip: 0/68
OK: 102/102 Fail: 0/102 Skip: 0/102
---TOTAL---
OK: 2440/2449 Fail: 0/2449 Skip: 9/2449
OK: 2444/2453 Fail: 0/2453 Skip: 9/2453

View File

@ -347,10 +347,6 @@ proc installMessageValidators*(
let forkDigests = lightClient.forkDigests
for stateFork in BeaconStateFork:
if stateFork >= BeaconStateFork.EIP4844:
# Format is still in development, do not use Gossip at this time.
continue
withLcDataFork(lcDataForkAtStateFork(stateFork)):
when lcDataFork > LightClientDataFork.None:
let
@ -420,9 +416,6 @@ proc updateGossipStatus*(
for gossipFork in oldGossipForks:
if gossipFork >= BeaconStateFork.Altair:
if gossipFork >= BeaconStateFork.EIP4844:
# Format is still in development, do not use Gossip at this time.
continue
let forkDigest = lightClient.forkDigests[].atStateFork(gossipFork)
lightClient.network.unsubscribe(
getLightClientFinalityUpdateTopic(forkDigest))
@ -431,9 +424,6 @@ proc updateGossipStatus*(
for gossipFork in newGossipForks:
if gossipFork >= BeaconStateFork.Altair:
if gossipFork >= BeaconStateFork.EIP4844:
# Format is still in development, do not use Gossip at this time.
continue
let forkDigest = lightClient.forkDigests[].atStateFork(gossipFork)
lightClient.network.subscribe(
getLightClientFinalityUpdateTopic(forkDigest),

View File

@ -1430,7 +1430,7 @@ proc installMessageValidators(node: BeaconNode) =
installPhase0Validators(forkDigests.altair)
installPhase0Validators(forkDigests.bellatrix)
installPhase0Validators(forkDigests.capella)
if node.dag.cfg.EIP4844_FORK_EPOCH != FAR_FUTURE_EPOCH:
if node.dag.cfg.EIP4844_FORK_EPOCH != FAR_FUTURE_EPOCH:
installPhase0Validators(forkDigests.eip4844)
node.network.addValidator(
@ -1466,8 +1466,14 @@ proc installMessageValidators(node: BeaconNode) =
if node.dag.cfg.EIP4844_FORK_EPOCH != FAR_FUTURE_EPOCH:
node.network.addValidator(
getBeaconBlockAndBlobsSidecarTopic(forkDigests.eip4844),
proc (signedBlock: eip4844.SignedBeaconBlockAndBlobsSidecar): ValidationResult =
# TODO: take into account node.shouldSyncOptimistically(node.currentSlot)
proc (
signedBlock: eip4844.SignedBeaconBlockAndBlobsSidecar
): ValidationResult =
if node.shouldSyncOptimistically(node.currentSlot):
toValidationResult(
node.optimisticProcessor.processSignedBeaconBlock(
signedBlock.beacon_block))
else:
toValidationResult(node.processor[].processSignedBeaconBlock(
MsgSource.gossip, signedBlock)))

View File

@ -13,7 +13,7 @@ import
./gossip_processing/optimistic_processor,
./networking/topic_params,
./spec/beaconstate,
./spec/datatypes/[phase0, altair, bellatrix, capella],
./spec/datatypes/[phase0, altair, bellatrix, capella, eip4844],
"."/[filepath, light_client, light_client_db, nimbus_binary_common, version]
from ./consensus_object_pools/consensus_manager import runForkchoiceUpdated
@ -156,6 +156,14 @@ programMain:
proc (signedBlock: capella.SignedBeaconBlock): ValidationResult =
toValidationResult(
optimisticProcessor.processSignedBeaconBlock(signedBlock)))
network.addValidator(
getBeaconBlockAndBlobsSidecarTopic(forkDigests.eip4844),
proc (
signedBlock: eip4844.SignedBeaconBlockAndBlobsSidecar
): ValidationResult =
toValidationResult(
optimisticProcessor.processSignedBeaconBlock(
signedBlock.beacon_block)))
lightClient.installMessageValidators()
waitFor network.startListening()
waitFor network.start()
@ -252,16 +260,10 @@ programMain:
oldGossipForks = currentGossipState - targetGossipState
for gossipFork in oldGossipForks:
if gossipFork >= BeaconStateFork.EIP4844:
# Format is still in development, do not use Gossip at this time.
continue
let forkDigest = forkDigests[].atStateFork(gossipFork)
network.unsubscribe(getBeaconBlocksTopic(forkDigest))
for gossipFork in newGossipForks:
if gossipFork >= BeaconStateFork.EIP4844:
# Format is still in development, do not use Gossip at this time.
continue
let forkDigest = forkDigests[].atStateFork(gossipFork)
network.subscribe(
getBeaconBlocksTopic(forkDigest), blocksTopicParams,

View File

@ -19,8 +19,10 @@ else:
{.push raises: [].}
import
stew/byteutils,
chronicles,
stew/[bitops2, byteutils],
json_serialization,
ssz_serialization/[merkleization, proofs],
ssz_serialization/types as sszTypes,
../digest,
"."/[base, phase0, altair, bellatrix, capella]
@ -108,6 +110,102 @@ type
ExecutePayload* = proc(
execution_payload: ExecutionPayload): bool {.gcsafe, raises: [Defect].}
# https://github.com/ethereum/consensus-specs/blob/v1.3.0-rc.1/specs/capella/light-client/sync-protocol.md#lightclientheader
LightClientHeader* = object
beacon*: BeaconBlockHeader
## Beacon block header
execution*: ExecutionPayloadHeader
## Execution payload header corresponding to `beacon.body_root` (from Capella onward)
execution_branch*: capella.ExecutionBranch
# https://github.com/ethereum/consensus-specs/blob/v1.3.0-rc.1/specs/altair/light-client/sync-protocol.md#lightclientbootstrap
LightClientBootstrap* = object
header*: LightClientHeader
## Header matching the requested beacon block root
current_sync_committee*: SyncCommittee
## Current sync committee corresponding to `header.beacon.state_root`
current_sync_committee_branch*: altair.CurrentSyncCommitteeBranch
# https://github.com/ethereum/consensus-specs/blob/v1.3.0-rc.1/specs/altair/light-client/sync-protocol.md#lightclientupdate
LightClientUpdate* = object
attested_header*: LightClientHeader
## Header attested to by the sync committee
next_sync_committee*: SyncCommittee
## Next sync committee corresponding to `attested_header.beacon.state_root`
next_sync_committee_branch*: altair.NextSyncCommitteeBranch
# Finalized header corresponding to `attested_header.beacon.state_root`
finalized_header*: LightClientHeader
finality_branch*: altair.FinalityBranch
sync_aggregate*: SyncAggregate
## Sync committee aggregate signature
signature_slot*: Slot
## Slot at which the aggregate signature was created (untrusted)
# https://github.com/ethereum/consensus-specs/blob/v1.3.0-rc.1/specs/altair/light-client/sync-protocol.md#lightclientfinalityupdate
LightClientFinalityUpdate* = object
# Header attested to by the sync committee
attested_header*: LightClientHeader
# Finalized header corresponding to `attested_header.beacon.state_root`
finalized_header*: LightClientHeader
finality_branch*: altair.FinalityBranch
# Sync committee aggregate signature
sync_aggregate*: SyncAggregate
# Slot at which the aggregate signature was created (untrusted)
signature_slot*: Slot
# https://github.com/ethereum/consensus-specs/blob/v1.3.0-rc.1/specs/altair/light-client/sync-protocol.md#lightclientoptimisticupdate
LightClientOptimisticUpdate* = object
# Header attested to by the sync committee
attested_header*: LightClientHeader
# Sync committee aggregate signature
sync_aggregate*: SyncAggregate
# Slot at which the aggregate signature was created (untrusted)
signature_slot*: Slot
SomeLightClientUpdateWithSyncCommittee* =
LightClientUpdate
SomeLightClientUpdateWithFinality* =
LightClientUpdate |
LightClientFinalityUpdate
SomeLightClientUpdate* =
LightClientUpdate |
LightClientFinalityUpdate |
LightClientOptimisticUpdate
SomeLightClientObject* =
LightClientBootstrap |
SomeLightClientUpdate
# https://github.com/ethereum/consensus-specs/blob/v1.3.0-rc.1/specs/altair/light-client/sync-protocol.md#lightclientstore
LightClientStore* = object
finalized_header*: LightClientHeader
## Header that is finalized
current_sync_committee*: SyncCommittee
## Sync committees corresponding to the finalized header
next_sync_committee*: SyncCommittee
best_valid_update*: Opt[LightClientUpdate]
## Best available header to switch finalized head to if we see nothing else
optimistic_header*: LightClientHeader
## Most recent available reasonably-safe header
previous_max_active_participants*: uint64
## Max number of active participants in a sync committee (used to compute
## safety threshold)
current_max_active_participants*: uint64
# https://github.com/ethereum/consensus-specs/blob/v1.3.0-alpha.1/specs/capella/beacon-chain.md#beaconstate
# changes indirectly via ExecutionPayloadHeader
BeaconState* = object
@ -403,6 +501,243 @@ func shortLog*(v: SomeSignedBeaconBlock): auto =
blck: shortLog(v.message),
signature: shortLog(v.signature)
)
# https://github.com/ethereum/consensus-specs/blob/v1.3.0-rc.1/specs/eip4844/light-client/sync-protocol.md#get_lc_execution_root
func get_lc_execution_root*(
header: LightClientHeader, cfg: RuntimeConfig): Eth2Digest =
let epoch = header.beacon.slot.epoch
if epoch >= cfg.EIP4844_FORK_EPOCH:
return hash_tree_root(header.execution)
if epoch >= cfg.CAPELLA_FORK_EPOCH:
let execution_header = capella.ExecutionPayloadHeader(
parent_hash: header.execution.parent_hash,
fee_recipient: header.execution.fee_recipient,
state_root: header.execution.state_root,
receipts_root: header.execution.receipts_root,
logs_bloom: header.execution.logs_bloom,
prev_randao: header.execution.prev_randao,
block_number: header.execution.block_number,
gas_limit: header.execution.gas_limit,
gas_used: header.execution.gas_used,
timestamp: header.execution.timestamp,
extra_data: header.execution.extra_data,
base_fee_per_gas: header.execution.base_fee_per_gas,
block_hash: header.execution.block_hash,
transactions_root: header.execution.transactions_root,
withdrawals_root: header.execution.withdrawals_root)
return hash_tree_root(execution_header)
ZERO_HASH
# https://github.com/ethereum/consensus-specs/blob/v1.3.0-rc.1/specs/eip4844/light-client/sync-protocol.md#is_valid_light_client_header
func is_valid_light_client_header*(
header: LightClientHeader, cfg: RuntimeConfig): bool =
let epoch = header.beacon.slot.epoch
if epoch < cfg.EIP4844_FORK_EPOCH:
if header.execution.excess_data_gas != 0.u256:
return false
if epoch < cfg.CAPELLA_FORK_EPOCH:
return
header.execution == default(ExecutionPayloadHeader) and
header.execution_branch == default(ExecutionBranch)
is_valid_merkle_branch(
get_lc_execution_root(header, cfg),
header.execution_branch,
log2trunc(EXECUTION_PAYLOAD_INDEX),
get_subtree_index(EXECUTION_PAYLOAD_INDEX),
header.beacon.body_root)
# https://github.com/ethereum/consensus-specs/blob/v1.3.0-rc.1/specs/eip4844/light-client/fork.md#upgrade_lc_header_to_eip4844
func upgrade_lc_header_to_eip4844*(
pre: capella.LightClientHeader): LightClientHeader =
LightClientHeader(
beacon: pre.beacon,
execution: ExecutionPayloadHeader(
parent_hash: pre.execution.parent_hash,
fee_recipient: pre.execution.fee_recipient,
state_root: pre.execution.state_root,
receipts_root: pre.execution.receipts_root,
logs_bloom: pre.execution.logs_bloom,
prev_randao: pre.execution.prev_randao,
block_number: pre.execution.block_number,
gas_limit: pre.execution.gas_limit,
gas_used: pre.execution.gas_used,
timestamp: pre.execution.timestamp,
extra_data: pre.execution.extra_data,
base_fee_per_gas: pre.execution.base_fee_per_gas,
block_hash: pre.execution.block_hash,
transactions_root: pre.execution.transactions_root,
withdrawals_root: pre.execution.withdrawals_root),
execution_branch: pre.execution_branch)
# https://github.com/ethereum/consensus-specs/blob/v1.3.0-rc.1/specs/eip4844/light-client/fork.md#upgrade_lc_bootstrap_to_eip4844
func upgrade_lc_bootstrap_to_eip4844*(
pre: capella.LightClientBootstrap): LightClientBootstrap =
LightClientBootstrap(
header: upgrade_lc_header_to_eip4844(pre.header),
current_sync_committee: pre.current_sync_committee,
current_sync_committee_branch: pre.current_sync_committee_branch)
# https://github.com/ethereum/consensus-specs/blob/v1.3.0-rc.1/specs/eip4844/light-client/fork.md#upgrade_lc_update_to_eip4844
func upgrade_lc_update_to_eip4844*(
pre: capella.LightClientUpdate): LightClientUpdate =
LightClientUpdate(
attested_header: upgrade_lc_header_to_eip4844(pre.attested_header),
next_sync_committee: pre.next_sync_committee,
next_sync_committee_branch: pre.next_sync_committee_branch,
finalized_header: upgrade_lc_header_to_eip4844(pre.finalized_header),
finality_branch: pre.finality_branch,
sync_aggregate: pre.sync_aggregate,
signature_slot: pre.signature_slot)
# https://github.com/ethereum/consensus-specs/blob/v1.3.0-rc.1/specs/eip4844/light-client/fork.md#upgrade_lc_finality_update_to_eip4844
func upgrade_lc_finality_update_to_eip4844*(
pre: capella.LightClientFinalityUpdate): LightClientFinalityUpdate =
LightClientFinalityUpdate(
attested_header: upgrade_lc_header_to_eip4844(pre.attested_header),
finalized_header: upgrade_lc_header_to_eip4844(pre.finalized_header),
finality_branch: pre.finality_branch,
sync_aggregate: pre.sync_aggregate,
signature_slot: pre.signature_slot)
# https://github.com/ethereum/consensus-specs/blob/v1.3.0-rc.1/specs/eip4844/light-client/fork.md#upgrade_lc_optimistic_update_to_eip4844
func upgrade_lc_optimistic_update_to_eip4844*(
pre: capella.LightClientOptimisticUpdate): LightClientOptimisticUpdate =
LightClientOptimisticUpdate(
attested_header: upgrade_lc_header_to_eip4844(pre.attested_header),
sync_aggregate: pre.sync_aggregate,
signature_slot: pre.signature_slot)
func shortLog*(v: LightClientHeader): auto =
(
beacon: shortLog(v.beacon),
execution: (
block_hash: v.execution.block_hash,
block_number: v.execution.block_number)
)
func shortLog*(v: LightClientBootstrap): auto =
(
header: shortLog(v.header)
)
func shortLog*(v: LightClientUpdate): auto =
(
attested: shortLog(v.attested_header),
has_next_sync_committee:
v.next_sync_committee != default(typeof(v.next_sync_committee)),
finalized: shortLog(v.finalized_header),
num_active_participants: v.sync_aggregate.num_active_participants,
signature_slot: v.signature_slot
)
func shortLog*(v: LightClientFinalityUpdate): auto =
(
attested: shortLog(v.attested_header),
finalized: shortLog(v.finalized_header),
num_active_participants: v.sync_aggregate.num_active_participants,
signature_slot: v.signature_slot
)
func shortLog*(v: LightClientOptimisticUpdate): auto =
(
attested: shortLog(v.attested_header),
num_active_participants: v.sync_aggregate.num_active_participants,
signature_slot: v.signature_slot,
)
chronicles.formatIt LightClientBootstrap: shortLog(it)
chronicles.formatIt LightClientUpdate: shortLog(it)
chronicles.formatIt LightClientFinalityUpdate: shortLog(it)
chronicles.formatIt LightClientOptimisticUpdate: shortLog(it)
template toFull*(
update: SomeLightClientUpdate): LightClientUpdate =
when update is LightClientUpdate:
update
elif update is SomeLightClientUpdateWithFinality:
LightClientUpdate(
attested_header: update.attested_header,
finalized_header: update.finalized_header,
finality_branch: update.finality_branch,
sync_aggregate: update.sync_aggregate,
signature_slot: update.signature_slot)
else:
LightClientUpdate(
attested_header: update.attested_header,
sync_aggregate: update.sync_aggregate,
signature_slot: update.signature_slot)
template toFinality*(
update: SomeLightClientUpdate): LightClientFinalityUpdate =
when update is LightClientFinalityUpdate:
update
elif update is SomeLightClientUpdateWithFinality:
LightClientFinalityUpdate(
attested_header: update.attested_header,
finalized_header: update.finalized_header,
finality_branch: update.finality_branch,
sync_aggregate: update.sync_aggregate,
signature_slot: update.signature_slot)
else:
LightClientFinalityUpdate(
attested_header: update.attested_header,
sync_aggregate: update.sync_aggregate,
signature_slot: update.signature_slot)
template toOptimistic*(
update: SomeLightClientUpdate): LightClientOptimisticUpdate =
when update is LightClientOptimisticUpdate:
update
else:
LightClientOptimisticUpdate(
attested_header: update.attested_header,
sync_aggregate: update.sync_aggregate,
signature_slot: update.signature_slot)
func matches*[A, B: SomeLightClientUpdate](a: A, b: B): bool =
if a.attested_header != b.attested_header:
return false
when a is SomeLightClientUpdateWithSyncCommittee and
b is SomeLightClientUpdateWithSyncCommittee:
if a.next_sync_committee != b.next_sync_committee:
return false
if a.next_sync_committee_branch != b.next_sync_committee_branch:
return false
when a is SomeLightClientUpdateWithFinality and
b is SomeLightClientUpdateWithFinality:
if a.finalized_header != b.finalized_header:
return false
if a.finality_branch != b.finality_branch:
return false
if a.sync_aggregate != b.sync_aggregate:
return false
if a.signature_slot != b.signature_slot:
return false
true
# https://github.com/ethereum/consensus-specs/blob/v1.3.0-rc.1/specs/eip4844/light-client/fork.md#upgrade_lc_store_to_eip4844
func upgrade_lc_store_to_eip4844*(
pre: capella.LightClientStore): LightClientStore =
let best_valid_update =
if pre.best_valid_update.isNone:
Opt.none(LightClientUpdate)
else:
Opt.some upgrade_lc_update_to_eip4844(pre.best_valid_update.get)
LightClientStore(
finalized_header: upgrade_lc_header_to_eip4844(pre.finalized_header),
current_sync_committee: pre.current_sync_committee,
next_sync_committee: pre.next_sync_committee,
best_valid_update: best_valid_update,
optimistic_header: upgrade_lc_header_to_eip4844(pre.optimistic_header),
previous_max_active_participants: pre.previous_max_active_participants,
current_max_active_participants: pre.current_max_active_participants)
template asSigned*(
x: SigVerifiedSignedBeaconBlock |
MsgTrustedSignedBeaconBlock |

View File

@ -927,8 +927,10 @@ func nextForkEpochAtEpoch*(cfg: RuntimeConfig, epoch: Epoch): Epoch =
of BeaconStateFork.Phase0: cfg.ALTAIR_FORK_EPOCH
func lcDataForkAtStateFork*(stateFork: BeaconStateFork): LightClientDataFork =
static: doAssert LightClientDataFork.high == LightClientDataFork.Capella
if stateFork >= BeaconStateFork.Capella:
static: doAssert LightClientDataFork.high == LightClientDataFork.EIP4844
if stateFork >= BeaconStateFork.EIP4844:
LightClientDataFork.EIP4844
elif stateFork >= BeaconStateFork.Capella:
LightClientDataFork.Capella
elif stateFork >= BeaconStateFork.Altair:
LightClientDataFork.Altair

View File

@ -18,27 +18,33 @@ type
LightClientDataFork* {.pure.} = enum # Append only, used in DB data!
None = 0, # only use non-0 in DB to detect accidentally uninitialized data
Altair = 1,
Capella = 2
Capella = 2,
EIP4844 = 3
ForkyLightClientHeader* =
altair.LightClientHeader |
capella.LightClientHeader
capella.LightClientHeader |
eip4844.LightClientHeader
ForkyLightClientBootstrap* =
altair.LightClientBootstrap |
capella.LightClientBootstrap
capella.LightClientBootstrap |
eip4844.LightClientBootstrap
ForkyLightClientUpdate* =
altair.LightClientUpdate |
capella.LightClientUpdate
capella.LightClientUpdate |
eip4844.LightClientUpdate
ForkyLightClientFinalityUpdate* =
altair.LightClientFinalityUpdate |
capella.LightClientFinalityUpdate
capella.LightClientFinalityUpdate |
eip4844.LightClientFinalityUpdate
ForkyLightClientOptimisticUpdate* =
altair.LightClientOptimisticUpdate |
capella.LightClientOptimisticUpdate
capella.LightClientOptimisticUpdate |
eip4844.LightClientOptimisticUpdate
SomeForkyLightClientUpdateWithSyncCommittee* =
ForkyLightClientUpdate
@ -58,7 +64,8 @@ type
ForkyLightClientStore* =
altair.LightClientStore |
capella.LightClientStore
capella.LightClientStore |
eip4844.LightClientStore
ForkedLightClientHeader* = object
case kind*: LightClientDataFork
@ -68,6 +75,8 @@ type
altairData*: altair.LightClientHeader
of LightClientDataFork.Capella:
capellaData*: capella.LightClientHeader
of LightClientDataFork.EIP4844:
eip4844Data*: eip4844.LightClientHeader
ForkedLightClientBootstrap* = object
case kind*: LightClientDataFork
@ -77,6 +86,8 @@ type
altairData*: altair.LightClientBootstrap
of LightClientDataFork.Capella:
capellaData*: capella.LightClientBootstrap
of LightClientDataFork.EIP4844:
eip4844Data*: eip4844.LightClientBootstrap
ForkedLightClientUpdate* = object
case kind*: LightClientDataFork
@ -86,6 +97,8 @@ type
altairData*: altair.LightClientUpdate
of LightClientDataFork.Capella:
capellaData*: capella.LightClientUpdate
of LightClientDataFork.EIP4844:
eip4844Data*: eip4844.LightClientUpdate
ForkedLightClientFinalityUpdate* = object
case kind*: LightClientDataFork
@ -95,6 +108,8 @@ type
altairData*: altair.LightClientFinalityUpdate
of LightClientDataFork.Capella:
capellaData*: capella.LightClientFinalityUpdate
of LightClientDataFork.EIP4844:
eip4844Data*: eip4844.LightClientFinalityUpdate
ForkedLightClientOptimisticUpdate* = object
case kind*: LightClientDataFork
@ -104,6 +119,8 @@ type
altairData*: altair.LightClientOptimisticUpdate
of LightClientDataFork.Capella:
capellaData*: capella.LightClientOptimisticUpdate
of LightClientDataFork.EIP4844:
eip4844Data*: eip4844.LightClientOptimisticUpdate
SomeForkedLightClientUpdateWithSyncCommittee* =
ForkedLightClientUpdate
@ -129,11 +146,15 @@ type
altairData*: altair.LightClientStore
of LightClientDataFork.Capella:
capellaData*: capella.LightClientStore
of LightClientDataFork.EIP4844:
eip4844Data*: eip4844.LightClientStore
func lcDataForkAtEpoch*(
cfg: RuntimeConfig, epoch: Epoch): LightClientDataFork =
static: doAssert LightClientDataFork.high == LightClientDataFork.Capella
if epoch >= cfg.CAPELLA_FORK_EPOCH:
static: doAssert LightClientDataFork.high == LightClientDataFork.EIP4844
if epoch >= cfg.EIP4844_FORK_EPOCH:
LightClientDataFork.EIP4844
elif epoch >= cfg.CAPELLA_FORK_EPOCH:
LightClientDataFork.Capella
elif epoch >= cfg.ALTAIR_FORK_EPOCH:
LightClientDataFork.Altair
@ -160,8 +181,20 @@ template kind*(
capella.LightClientStore]): LightClientDataFork =
LightClientDataFork.Capella
template kind*(
x: typedesc[ # `SomeLightClientObject` doesn't work here (Nim 1.6)
eip4844.LightClientHeader |
eip4844.LightClientBootstrap |
eip4844.LightClientUpdate |
eip4844.LightClientFinalityUpdate |
eip4844.LightClientOptimisticUpdate |
eip4844.LightClientStore]): LightClientDataFork =
LightClientDataFork.EIP4844
template LightClientHeader*(kind: static LightClientDataFork): auto =
when kind == LightClientDataFork.Capella:
when kind == LightClientDataFork.EIP4844:
typedesc[eip4844.LightClientHeader]
elif kind == LightClientDataFork.Capella:
typedesc[capella.LightClientHeader]
elif kind == LightClientDataFork.Altair:
typedesc[altair.LightClientHeader]
@ -169,7 +202,9 @@ template LightClientHeader*(kind: static LightClientDataFork): auto =
static: raiseAssert "Unreachable"
template LightClientBootstrap*(kind: static LightClientDataFork): auto =
when kind == LightClientDataFork.Capella:
when kind == LightClientDataFork.EIP4844:
typedesc[eip4844.LightClientBootstrap]
elif kind == LightClientDataFork.Capella:
typedesc[capella.LightClientBootstrap]
elif kind == LightClientDataFork.Altair:
typedesc[altair.LightClientBootstrap]
@ -177,7 +212,9 @@ template LightClientBootstrap*(kind: static LightClientDataFork): auto =
static: raiseAssert "Unreachable"
template LightClientUpdate*(kind: static LightClientDataFork): auto =
when kind == LightClientDataFork.Capella:
when kind == LightClientDataFork.EIP4844:
typedesc[eip4844.LightClientUpdate]
elif kind == LightClientDataFork.Capella:
typedesc[capella.LightClientUpdate]
elif kind == LightClientDataFork.Altair:
typedesc[altair.LightClientUpdate]
@ -185,7 +222,9 @@ template LightClientUpdate*(kind: static LightClientDataFork): auto =
static: raiseAssert "Unreachable"
template LightClientFinalityUpdate*(kind: static LightClientDataFork): auto =
when kind == LightClientDataFork.Capella:
when kind == LightClientDataFork.EIP4844:
typedesc[eip4844.LightClientFinalityUpdate]
elif kind == LightClientDataFork.Capella:
typedesc[capella.LightClientFinalityUpdate]
elif kind == LightClientDataFork.Altair:
typedesc[altair.LightClientFinalityUpdate]
@ -193,7 +232,9 @@ template LightClientFinalityUpdate*(kind: static LightClientDataFork): auto =
static: raiseAssert "Unreachable"
template LightClientOptimisticUpdate*(kind: static LightClientDataFork): auto =
when kind == LightClientDataFork.Capella:
when kind == LightClientDataFork.EIP4844:
typedesc[eip4844.LightClientOptimisticUpdate]
elif kind == LightClientDataFork.Capella:
typedesc[capella.LightClientOptimisticUpdate]
elif kind == LightClientDataFork.Altair:
typedesc[altair.LightClientOptimisticUpdate]
@ -201,7 +242,9 @@ template LightClientOptimisticUpdate*(kind: static LightClientDataFork): auto =
static: raiseAssert "Unreachable"
template LightClientStore*(kind: static LightClientDataFork): auto =
when kind == LightClientDataFork.Capella:
when kind == LightClientDataFork.EIP4844:
typedesc[eip4844.LightClientStore]
elif kind == LightClientDataFork.Capella:
typedesc[capella.LightClientStore]
elif kind == LightClientDataFork.Altair:
typedesc[altair.LightClientStore]
@ -258,7 +301,10 @@ template Forked*(x: typedesc[ForkyLightClientStore]): auto =
template withAll*(
x: typedesc[LightClientDataFork], body: untyped): untyped =
static: doAssert LightClientDataFork.high == LightClientDataFork.Capella
static: doAssert LightClientDataFork.high == LightClientDataFork.EIP4844
block:
const lcDataFork {.inject, used.} = LightClientDataFork.EIP4844
body
block:
const lcDataFork {.inject, used.} = LightClientDataFork.Capella
body
@ -272,6 +318,9 @@ template withAll*(
template withLcDataFork*(
x: LightClientDataFork, body: untyped): untyped =
case x
of LightClientDataFork.EIP4844:
const lcDataFork {.inject, used.} = LightClientDataFork.EIP4844
body
of LightClientDataFork.Capella:
const lcDataFork {.inject, used.} = LightClientDataFork.Capella
body
@ -285,6 +334,10 @@ template withLcDataFork*(
template withForkyHeader*(
x: ForkedLightClientHeader, body: untyped): untyped =
case x.kind
of LightClientDataFork.EIP4844:
const lcDataFork {.inject, used.} = LightClientDataFork.EIP4844
template forkyHeader: untyped {.inject, used.} = x.eip4844Data
body
of LightClientDataFork.Capella:
const lcDataFork {.inject, used.} = LightClientDataFork.Capella
template forkyHeader: untyped {.inject, used.} = x.capellaData
@ -300,6 +353,10 @@ template withForkyHeader*(
template withForkyBootstrap*(
x: ForkedLightClientBootstrap, body: untyped): untyped =
case x.kind
of LightClientDataFork.EIP4844:
const lcDataFork {.inject, used.} = LightClientDataFork.EIP4844
template forkyBootstrap: untyped {.inject, used.} = x.eip4844Data
body
of LightClientDataFork.Capella:
const lcDataFork {.inject, used.} = LightClientDataFork.Capella
template forkyBootstrap: untyped {.inject, used.} = x.capellaData
@ -315,6 +372,10 @@ template withForkyBootstrap*(
template withForkyUpdate*(
x: ForkedLightClientUpdate, body: untyped): untyped =
case x.kind
of LightClientDataFork.EIP4844:
const lcDataFork {.inject, used.} = LightClientDataFork.EIP4844
template forkyUpdate: untyped {.inject, used.} = x.eip4844Data
body
of LightClientDataFork.Capella:
const lcDataFork {.inject, used.} = LightClientDataFork.Capella
template forkyUpdate: untyped {.inject, used.} = x.capellaData
@ -330,6 +391,10 @@ template withForkyUpdate*(
template withForkyFinalityUpdate*(
x: ForkedLightClientFinalityUpdate, body: untyped): untyped =
case x.kind
of LightClientDataFork.EIP4844:
const lcDataFork {.inject, used.} = LightClientDataFork.EIP4844
template forkyFinalityUpdate: untyped {.inject, used.} = x.eip4844Data
body
of LightClientDataFork.Capella:
const lcDataFork {.inject, used.} = LightClientDataFork.Capella
template forkyFinalityUpdate: untyped {.inject, used.} = x.capellaData
@ -345,6 +410,10 @@ template withForkyFinalityUpdate*(
template withForkyOptimisticUpdate*(
x: ForkedLightClientOptimisticUpdate, body: untyped): untyped =
case x.kind
of LightClientDataFork.EIP4844:
const lcDataFork {.inject, used.} = LightClientDataFork.EIP4844
template forkyOptimisticUpdate: untyped {.inject, used.} = x.eip4844Data
body
of LightClientDataFork.Capella:
const lcDataFork {.inject, used.} = LightClientDataFork.Capella
template forkyOptimisticUpdate: untyped {.inject, used.} = x.capellaData
@ -360,6 +429,10 @@ template withForkyOptimisticUpdate*(
template withForkyObject*(
x: SomeForkedLightClientObject, body: untyped): untyped =
case x.kind
of LightClientDataFork.EIP4844:
const lcDataFork {.inject, used.} = LightClientDataFork.EIP4844
template forkyObject: untyped {.inject, used.} = x.eip4844Data
body
of LightClientDataFork.Capella:
const lcDataFork {.inject, used.} = LightClientDataFork.Capella
template forkyObject: untyped {.inject, used.} = x.capellaData
@ -375,6 +448,10 @@ template withForkyObject*(
template withForkyStore*(
x: ForkedLightClientStore, body: untyped): untyped =
case x.kind
of LightClientDataFork.EIP4844:
const lcDataFork {.inject, used.} = LightClientDataFork.EIP4844
template forkyStore: untyped {.inject, used.} = x.eip4844Data
body
of LightClientDataFork.Capella:
const lcDataFork {.inject, used.} = LightClientDataFork.Capella
template forkyStore: untyped {.inject, used.} = x.capellaData
@ -444,7 +521,9 @@ template forky*(
SomeForkedLightClientObject |
ForkedLightClientStore,
kind: static LightClientDataFork): untyped =
when kind == LightClientDataFork.Capella:
when kind == LightClientDataFork.EIP4844:
x.eip4844Data
elif kind == LightClientDataFork.Capella:
x.capellaData
elif kind == LightClientDataFork.Altair:
x.altairData
@ -475,7 +554,15 @@ func migrateToDataFork*(
capellaData: upgrade_lc_header_to_capella(
x.forky(LightClientDataFork.Altair)))
static: doAssert LightClientDataFork.high == LightClientDataFork.Capella
# Upgrade to EIP4844
when newKind >= LightClientDataFork.EIP4844:
if x.kind == LightClientDataFork.Capella:
x = ForkedLightClientHeader(
kind: LightClientDataFork.EIP4844,
eip4844Data: upgrade_lc_header_to_eip4844(
x.forky(LightClientDataFork.Capella)))
static: doAssert LightClientDataFork.high == LightClientDataFork.EIP4844
doAssert x.kind == newKind
func migrateToDataFork*(
@ -502,7 +589,15 @@ func migrateToDataFork*(
capellaData: upgrade_lc_bootstrap_to_capella(
x.forky(LightClientDataFork.Altair)))
static: doAssert LightClientDataFork.high == LightClientDataFork.Capella
# Upgrade to EIP4844
when newKind >= LightClientDataFork.EIP4844:
if x.kind == LightClientDataFork.Capella:
x = ForkedLightClientBootstrap(
kind: LightClientDataFork.EIP4844,
eip4844Data: upgrade_lc_bootstrap_to_eip4844(
x.forky(LightClientDataFork.Capella)))
static: doAssert LightClientDataFork.high == LightClientDataFork.EIP4844
doAssert x.kind == newKind
func migrateToDataFork*(
@ -529,7 +624,15 @@ func migrateToDataFork*(
capellaData: upgrade_lc_update_to_capella(
x.forky(LightClientDataFork.Altair)))
static: doAssert LightClientDataFork.high == LightClientDataFork.Capella
# Upgrade to EIP4844
when newKind >= LightClientDataFork.EIP4844:
if x.kind == LightClientDataFork.Capella:
x = ForkedLightClientUpdate(
kind: LightClientDataFork.EIP4844,
eip4844Data: upgrade_lc_update_to_eip4844(
x.forky(LightClientDataFork.Capella)))
static: doAssert LightClientDataFork.high == LightClientDataFork.EIP4844
doAssert x.kind == newKind
func migrateToDataFork*(
@ -556,7 +659,15 @@ func migrateToDataFork*(
capellaData: upgrade_lc_finality_update_to_capella(
x.forky(LightClientDataFork.Altair)))
static: doAssert LightClientDataFork.high == LightClientDataFork.Capella
# Upgrade to EIP4844
when newKind >= LightClientDataFork.EIP4844:
if x.kind == LightClientDataFork.Capella:
x = ForkedLightClientFinalityUpdate(
kind: LightClientDataFork.EIP4844,
eip4844Data: upgrade_lc_finality_update_to_eip4844(
x.forky(LightClientDataFork.Capella)))
static: doAssert LightClientDataFork.high == LightClientDataFork.EIP4844
doAssert x.kind == newKind
func migrateToDataFork*(
@ -583,7 +694,15 @@ func migrateToDataFork*(
capellaData: upgrade_lc_optimistic_update_to_capella(
x.forky(LightClientDataFork.Altair)))
static: doAssert LightClientDataFork.high == LightClientDataFork.Capella
# Upgrade to EIP4844
when newKind >= LightClientDataFork.EIP4844:
if x.kind == LightClientDataFork.Capella:
x = ForkedLightClientOptimisticUpdate(
kind: LightClientDataFork.EIP4844,
eip4844Data: upgrade_lc_optimistic_update_to_eip4844(
x.forky(LightClientDataFork.Capella)))
static: doAssert LightClientDataFork.high == LightClientDataFork.EIP4844
doAssert x.kind == newKind
func migrateToDataFork*(
@ -610,7 +729,15 @@ func migrateToDataFork*(
capellaData: upgrade_lc_store_to_capella(
x.forky(LightClientDataFork.Altair)))
static: doAssert LightClientDataFork.high == LightClientDataFork.Capella
# Upgrade to EIP4844
when newKind >= LightClientDataFork.EIP4844:
if x.kind == LightClientDataFork.Capella:
x = ForkedLightClientStore(
kind: LightClientDataFork.EIP4844,
eip4844Data: upgrade_lc_store_to_eip4844(
x.forky(LightClientDataFork.Capella)))
static: doAssert LightClientDataFork.high == LightClientDataFork.EIP4844
doAssert x.kind == newKind
func migratingToDataFork*[
@ -651,8 +778,7 @@ func toCapellaLightClientHeader(
func toCapellaLightClientHeader(
blck: # `SomeSignedBeaconBlock` doesn't work here (Nim 1.6)
capella.SignedBeaconBlock | capella.TrustedSignedBeaconBlock |
eip4844.SignedBeaconBlock | eip4844.TrustedSignedBeaconBlock
capella.SignedBeaconBlock | capella.TrustedSignedBeaconBlock
): capella.LightClientHeader =
template payload: untyped = blck.message.body.execution_payload
capella.LightClientHeader(
@ -676,6 +802,75 @@ func toCapellaLightClientHeader(
execution_branch: blck.message.body.build_proof(
capella.EXECUTION_PAYLOAD_INDEX).get)
# https://github.com/ethereum/consensus-specs/blob/v1.3.0-rc.1/specs/eip4844/light-client/full-node.md#block_to_light_client_header
func toEIP4844LightClientHeader(
blck: # `SomeSignedBeaconBlock` doesn't work here (Nim 1.6)
phase0.SignedBeaconBlock | phase0.TrustedSignedBeaconBlock |
altair.SignedBeaconBlock | altair.TrustedSignedBeaconBlock |
bellatrix.SignedBeaconBlock | bellatrix.TrustedSignedBeaconBlock
): eip4844.LightClientHeader =
# Note that during fork transitions, `finalized_header` may still
# point to earlier forks. While Bellatrix blocks also contain an
# `ExecutionPayload` (minus `withdrawals_root`), it was not included
# in the corresponding light client data. To ensure compatibility
# with legacy data going through `upgrade_lc_header_to_capella`,
# leave out execution data.
eip4844.LightClientHeader(
beacon: blck.message.toBeaconBlockHeader())
func toEIP4844LightClientHeader(
blck: # `SomeSignedBeaconBlock` doesn't work here (Nim 1.6)
capella.SignedBeaconBlock | capella.TrustedSignedBeaconBlock
): eip4844.LightClientHeader =
template payload: untyped = blck.message.body.execution_payload
eip4844.LightClientHeader(
beacon: blck.message.toBeaconBlockHeader(),
execution: eip4844.ExecutionPayloadHeader(
parent_hash: payload.parent_hash,
fee_recipient: payload.fee_recipient,
state_root: payload.state_root,
receipts_root: payload.receipts_root,
logs_bloom: payload.logs_bloom,
prev_randao: payload.prev_randao,
block_number: payload.block_number,
gas_limit: payload.gas_limit,
gas_used: payload.gas_used,
timestamp: payload.timestamp,
extra_data: payload.extra_data,
base_fee_per_gas: payload.base_fee_per_gas,
block_hash: payload.block_hash,
transactions_root: hash_tree_root(payload.transactions),
withdrawals_root: hash_tree_root(payload.withdrawals)),
execution_branch: blck.message.body.build_proof(
capella.EXECUTION_PAYLOAD_INDEX).get)
func toEIP4844LightClientHeader(
blck: # `SomeSignedBeaconBlock` doesn't work here (Nim 1.6)
eip4844.SignedBeaconBlock | eip4844.TrustedSignedBeaconBlock
): eip4844.LightClientHeader =
template payload: untyped = blck.message.body.execution_payload
eip4844.LightClientHeader(
beacon: blck.message.toBeaconBlockHeader(),
execution: eip4844.ExecutionPayloadHeader(
parent_hash: payload.parent_hash,
fee_recipient: payload.fee_recipient,
state_root: payload.state_root,
receipts_root: payload.receipts_root,
logs_bloom: payload.logs_bloom,
prev_randao: payload.prev_randao,
block_number: payload.block_number,
gas_limit: payload.gas_limit,
gas_used: payload.gas_used,
timestamp: payload.timestamp,
extra_data: payload.extra_data,
base_fee_per_gas: payload.base_fee_per_gas,
excess_data_gas: payload.excess_data_gas,
block_hash: payload.block_hash,
transactions_root: hash_tree_root(payload.transactions),
withdrawals_root: hash_tree_root(payload.withdrawals)),
execution_branch: blck.message.body.build_proof(
capella.EXECUTION_PAYLOAD_INDEX).get)
func toLightClientHeader*(
blck: # `SomeSignedBeaconBlock` doesn't work here (Nim 1.6)
phase0.SignedBeaconBlock | phase0.TrustedSignedBeaconBlock |
@ -684,7 +879,9 @@ func toLightClientHeader*(
capella.SignedBeaconBlock | capella.TrustedSignedBeaconBlock |
eip4844.SignedBeaconBlock | eip4844.TrustedSignedBeaconBlock,
kind: static LightClientDataFork): auto =
when kind == LightClientDataFork.Capella:
when kind == LightClientDataFork.EIP4844:
blck.toEIP4844LightClientHeader()
elif kind == LightClientDataFork.Capella:
blck.toCapellaLightClientHeader()
elif kind == LightClientDataFork.Altair:
blck.toAltairLightClientHeader()

View File

@ -126,15 +126,15 @@ suite "EF - EIP4844 - SSZ consensus objects " & preset():
of "HistoricalSummary": checkSSZ(HistoricalSummary, path, hash)
of "IndexedAttestation": checkSSZ(IndexedAttestation, path, hash)
of "LightClientBootstrap":
discard # checkSSZ(capella.LightClientBootstrap, path, hash)
discard # checkSSZ(eip4844.LightClientBootstrap, path, hash)
of "LightClientHeader":
discard # checkSSZ(capella.LightClientHeader, path, hash)
discard # checkSSZ(eip4844.LightClientHeader, path, hash)
of "LightClientUpdate":
discard # checkSSZ(capella.LightClientUpdate, path, hash)
discard # checkSSZ(eip4844.LightClientUpdate, path, hash)
of "LightClientFinalityUpdate":
discard # checkSSZ(capella.LightClientFinalityUpdate, path, hash)
discard # checkSSZ(eip4844.LightClientFinalityUpdate, path, hash)
of "LightClientOptimisticUpdate":
discard # checkSSZ(capella.LightClientOptimisticUpdate, path, hash)
discard # checkSSZ(eip4844.LightClientOptimisticUpdate, path, hash)
of "PendingAttestation": checkSSZ(PendingAttestation, path, hash)
of "PowBlock": checkSSZ(PowBlock, path, hash)
of "ProposerSlashing": checkSSZ(ProposerSlashing, path, hash)

View File

@ -151,13 +151,8 @@ suite "Light client processor" & preset():
applyPeriodWithSupermajority(period)
# Reduce stack size by making this a `proc`
proc applyPeriodWithoutSupermajority(period: SyncCommitteePeriod) =
let update = newClone(dag.getLightClientUpdateForPeriod(period))
check update[].kind > LightClientDataFork.None
withForkyUpdate(update[]):
when lcDataFork > LightClientDataFork.None:
setTimeToSlot(forkyUpdate.signature_slot)
proc applyPeriodWithoutSupermajority(
period: SyncCommitteePeriod, update: ref ForkedLightClientUpdate) =
for i in 0 ..< 2:
res = processor[].storeObject(
MsgSource.gossip, getBeaconTime(), update[])
@ -198,7 +193,8 @@ suite "Light client processor" & preset():
forkyStore.best_valid_update.isSome
not forkyStore.best_valid_update.get.matches(forkyUpdate)
proc applyDuplicate() = # Reduce stack size by making this a `proc`
# Reduce stack size by making this a `proc`
proc applyDuplicate(update: ref ForkedLightClientUpdate) =
res = processor[].storeObject(
MsgSource.gossip, getBeaconTime(), update[])
check update[].kind <= store[].kind
@ -226,10 +222,10 @@ suite "Light client processor" & preset():
forkyStore.best_valid_update.isSome
not forkyStore.best_valid_update.get.matches(forkyUpdate)
applyDuplicate()
applyDuplicate(update)
time += chronos.minutes(15)
for _ in 0 ..< 150:
applyDuplicate()
applyDuplicate(update)
time += chronos.seconds(5)
time += chronos.minutes(15)
@ -272,6 +268,16 @@ suite "Light client processor" & preset():
res.error == VerifierError.MissingParent
forkyStore.best_valid_update.isSome
not forkyStore.best_valid_update.get.matches(forkyUpdate)
for period in lastPeriodWithSupermajority + 1 .. highPeriod:
let update = newClone(dag.getLightClientUpdateForPeriod(period))
check update[].kind > LightClientDataFork.None
withForkyUpdate(update[]):
when lcDataFork > LightClientDataFork.None:
setTimeToSlot(forkyUpdate.signature_slot)
applyPeriodWithoutSupermajority(period, update)
if finalizationMode == LightClientFinalizationMode.Optimistic:
withForkyStore(store[]):
when lcDataFork > LightClientDataFork.None:
@ -287,9 +293,6 @@ suite "Light client processor" & preset():
template forkyUpdate: untyped = upgraded[].forky(lcDataFork)
check forkyStore.finalized_header != forkyUpdate.attested_header
for period in lastPeriodWithSupermajority + 1 .. highPeriod:
applyPeriodWithoutSupermajority(period)
var oldFinalized {.noinit.}: ForkedLightClientHeader
withForkyStore(store[]):
when lcDataFork > LightClientDataFork.None: