Problem
We already know Lodestar should avoid persisting duplicate full execution payload bodies on the CL side and instead keep a blinded representation + reconstruct the missing EL-side body data on demand.
There is already a broad tracking issue for the storage dedup idea:
But we should keep a more specific pre-testnet reminder for the serve path:
if Lodestar stores the execution payload envelope / block in blinded form, it must still be able to serve peers correctly during sync (especially beacon_blocks_by_range / beacon_blocks_by_root style serving), reconstructing the missing execution payload body data from EL and restoring any Gloas-specific fields such as BAL before serving.
Terence warned that Prysm hit a late bug in this area: they were not unblinding / re-adding BAL correctly when serving to peers.
Why this needs a dedicated reminder
This can easily be missed if we only test:
- local import / processing
- proposer-side flows
- REST full-block reconstruction
The tricky part is the sync serving path:
- range sync serving works
- block/root serving works
- the served payload is reconstructed from EL correctly
- BAL / other body-only fields are restored correctly before serving
- peers can consume the served block/payload without blinded/full mismatch bugs
Prysm reference points
I could not cleanly pull the exact ethpandaops/prysm:glamsterdam-devnet-0 branch into the local checkout, but the current local Prysm repo already shows the relevant shape:
1. Store the envelope in blinded form
beacon-chain/db/kv/execution_payload_envelope.go
SaveExecutionPayloadEnvelope() replaces the full payload with its blockHash
- keeps metadata like
executionRequests, builderIndex, beaconBlockRoot, slot, stateRoot
- comment explicitly says the full payload can later be retrieved from EL via
engine_getPayloadBodiesByHash
2. Reconstruct full payload bodies from EL on demand
beacon-chain/execution/payload_body.go
reconstructBlindedBlockBatch()
requestBodiesByHash() using engine_getPayloadBodiesByHashV1
- fallback
requestBodiesByRange() using engine_getPayloadBodiesByRangeV1
fullPayloadFromPayloadBody() rebuilds the full execution payload from the blinded header + EL body data
3. Use reconstructed full blocks for serving/API paths
beacon-chain/rpc/eth/beacon/handlers.go
GetBlockV2() reconstructs the full block when the stored block is blinded:
ExecutionReconstructor.ReconstructFullBlock(ctx, blk)
Lodestar context
Lodestar already has the relevant TODO in:
packages/beacon-node/src/chain/blocks/writePayloadEnvelopeInputToDb.ts
// TODO GLOAS: Persist envelope metadata (stateRoot, executionRequests, builderIndex, etc.) without the full
// execution payload body — only keep the blockHash reference. The EL already stores the payload.
// See https://github.com/ChainSafe/lodestar/issues/5671
Lodestar also already has EL payload body fetch methods:
packages/beacon-node/src/execution/engine/http.ts
getPayloadBodiesByHash()
getPayloadBodiesByRange()
Requested work / acceptance criteria
Before testnets, we should make sure Lodestar either implements or explicitly tests the full serve path for blinded envelope storage:
Related
Problem
We already know Lodestar should avoid persisting duplicate full execution payload bodies on the CL side and instead keep a blinded representation + reconstruct the missing EL-side body data on demand.
There is already a broad tracking issue for the storage dedup idea:
De-duplicate payload from persisted beacon blocksBut we should keep a more specific pre-testnet reminder for the serve path:
Terence warned that Prysm hit a late bug in this area: they were not unblinding / re-adding BAL correctly when serving to peers.
Why this needs a dedicated reminder
This can easily be missed if we only test:
The tricky part is the sync serving path:
Prysm reference points
I could not cleanly pull the exact
ethpandaops/prysm:glamsterdam-devnet-0branch into the local checkout, but the current local Prysm repo already shows the relevant shape:1. Store the envelope in blinded form
beacon-chain/db/kv/execution_payload_envelope.goSaveExecutionPayloadEnvelope()replaces the full payload with itsblockHashexecutionRequests,builderIndex,beaconBlockRoot,slot,stateRootengine_getPayloadBodiesByHash2. Reconstruct full payload bodies from EL on demand
beacon-chain/execution/payload_body.goreconstructBlindedBlockBatch()requestBodiesByHash()usingengine_getPayloadBodiesByHashV1requestBodiesByRange()usingengine_getPayloadBodiesByRangeV1fullPayloadFromPayloadBody()rebuilds the full execution payload from the blinded header + EL body data3. Use reconstructed full blocks for serving/API paths
beacon-chain/rpc/eth/beacon/handlers.goGetBlockV2()reconstructs the full block when the stored block is blinded:ExecutionReconstructor.ReconstructFullBlock(ctx, blk)Lodestar context
Lodestar already has the relevant TODO in:
packages/beacon-node/src/chain/blocks/writePayloadEnvelopeInputToDb.tsLodestar also already has EL payload body fetch methods:
packages/beacon-node/src/execution/engine/http.tsgetPayloadBodiesByHash()getPayloadBodiesByRange()Requested work / acceptance criteria
Before testnets, we should make sure Lodestar either implements or explicitly tests the full serve path for blinded envelope storage:
beacon_blocks_by_rangeserving worksbeacon_blocks_by_rootserving worksRelated
De-duplicate payload from persisted beacon blocks