Discussion topic for EIP-8237
Update Log
- 2026-04-23: initial draft
External Reviews
None as of 2026-04-03.
Outstanding Issues
- The acccumulator should use previous withdrawals instead of current block withdrawals
Discussion topic for EIP-8237
None as of 2026-04-03.
a few questions
The consensus layer still eventually verifies all execution payloads; it simply defers this verification during range sync.
Does this imply the consensus layer downloads and validates the full chain of ExecutionPayloadEnvelopes after completing range sync? It would suffice to infer validity of the whole chain from one VALID response from the EL on newPayload/forkchoiceUpdated, wouldn’t it?
—
Separately, if the goal is to eventually download all payloads (we need to serve them to peers, don’t we?), doesn’t deferring the download introduce a sort of awkward state where you have blocks but not payloads, and can’t claim to be fully synced (you can’t service peer requests for payloads). As far as I know, the getPayloadBodies* methods don’t let you reconstruct full envelopes from the EL, there are fields missing (see Prune finalized gloas envelopes · Issue #9527 · sigp/lighthouse · GitHub for related discussion).
for reference, LH doesn’t have optimistic sync working for Gloas yet, but I don’t foresee any problems in our previous approach of calculating the RLP block hash CL-side (the thorniness is all in fork choice: Tests for Gloas optimistic sync · Issue #5635 · ethereum/consensus-specs · GitHub)
Is there also an issue in the definition of the accumulator? It doesn’t seem to accumulate on top of the previous value, so I think that discrepancies at past slots can be papered over by agreement at later slots. My LLM wrote up an example here (apologies for the slop): EIP-8327 accumulator bug · GitHub
yes, that’s what it’s meant by “verifying”. As soon as the Engine returns VALID, if the accumulators match up then we know that both chains are valid and they correspond to eachother. The whole point of the EIP is to never download any payload on sync.
Is there also an issue in the definition of the accumulator?
There may be one, I haven’t updated the accumulator because we deferred discussions to Svalbard, where people rejected the EIP so I didn’t care in updating it, but the accumulator itself is the trivial part needs to commit to the previous payload and every data in the payload that the CL cannot verify by itself.
Thanks for framing these core questions, @michaelsproul. They strike directly at the boundary between consensus state validation, the Engine API wire contract, and P2P data availability duties.
Below is an analysis of how these trade-offs balance out across client runtime architectures:
1. Verification Semantics: Transitive Validity vs. Redundant Re-Execution
“Does this imply the consensus layer downloads and validates the full chain of ExecutionPayloadEnvelopes after completing range sync? It would suffice to infer validity of the whole chain from one VALID response from the EL on newPayload/forkchoiceUpdated, wouldn’t it?”
From a state-transition perspective, forcing sequential newPayload calls over the Engine API during backfill is largely redundant:
The Transitive Proof: Once the EL reaches the sync head and returns VALID via forkchoiceUpdated (or the terminal newPayload), the canonical execution chain and intermediate state roots are transitively verified back to the common finalized ancestor. Forcing the CL to sequentially pump every historical block through newPayload creates massive IPC serialization overhead and re-verifies transactions the EL already validated via its own sync machinery (e.g., Snap sync).
Decoupling Validation from Integrity:
Execution Validity: Inherited transitively from the EL’s head validation.
Chain Consistency: The CL only needs to assert that the ExecutionPayloadHeader.block_hash inside its historical **BeaconBlock**s matches the canonical execution block hashes reported by the EL. This requires a lightweight hash-tree check, not full EVM payload re-execution.
2. The P2P Data Availability Boundary & Intermediate Sync States
“…doesn’t deferring the download introduce a sort of awkward state where you have blocks but not payloads, and can’t claim to be fully synced (you can’t service peer requests for payloads)?”
This intermediate state mirrors the operational paradigm of EL Snap sync (where nodes track the head before block bodies/receipts are fully backfilled), but consensus P2P networking requires explicit protocol ergonomics:
Separation of Consensus Duty from P2P Seeding: A node’s primary responsibility upon reaching the head is consensus participation (attesting/proposing). P2P archival serving is secondary.
Peer Scoring & Capability Signaling: If an unbackfilled node attempts to answer BeaconBlocksByRange requests without complete payload bodies, it risks peer-score penalties or broken RPC pipelines. The P2P spec should formalize this distinction—either by signaling partial backfill via Status / metadata bits or defining graceful ResourceUnavailable responses so peers route payload range queries to fully seeded nodes.
“As far as I know, the
getPayloadBodies*methods don’t reconstruct full envelopes from the EL, there are fields missing (see Prune finalized gloas envelopes · Issue #9527 · sigp/lighthouse)…”
This is the most critical implementation hurdle. The EL cannot be relied upon to retroactively hydrate CL **ExecutionPayloadEnvelope**s:
The Missing Metadata Problem: As highlighted in Lighthouse #9527, the EL’s persistence layer stores standard execution block bodies (transactions, withdrawals). It does not custody consensus-layer wrapper metadata (such as execution requests, blob commitments, or specific envelope formatting introduced in post-Dencun/Electra forks).
Architectural Trade-Off:
Option A: Expanding the Engine API (getPayloadBodiesV*). Forcing the EL to ingest, index, and return CL-specific envelope fields couples execution databases to consensus envelope schemas, violating clean layer separation.
**Option B: Independent CL-to-CL Envelope Backfill (Recommended).**The CL handles historical envelope backfill natively across the LibP2P consensus mesh. The EL syncs its own chain via Snap/execution sync, while the CL pulls full signed envelopes directly from consensus peers in the background.
This preserves the boundary: the EL remains purely an execution engine, while the CL retains custody of consensus envelope data without creating a leaky abstraction over the Engine API.
Hi @potuz @michaelsproul — I’ve written up an EIP inspired by this one. It aims to remove the need for the CL to see any execution payloads during range sync, leaving the CL to serve only payloads for unfinalized blocks.
EIP: Add EIP: Deferred Payload Verification by frisitano · Pull Request #12372 · ethereum/EIPs · GitHub
Consensus specs: Add deferred payload verification (EIP-9999) by frisitano · Pull Request #5674 · ethereum/consensus-specs · GitHub
Would welcome your thoughts.
I don’t understand why this would need a different EIP, this is literally what 8237 does and it was DFId
Agreed — it doesn’t need to be a separate EIP, as the intent is the same. I opened one mainly to get feedback on the binding pattern and the overall design, which seemed a cleaner first step than cutting across your work.
I’d put it as a hardening of 8237 rather than an alternative. The differences that I think matter:
ExecutionPayloadEnvelopesByRange. Lighthouse’s objection is that the envelopes have to be downloaded eventually anyway but only because ByRange provides the requirementIf you’re open to it I’d be glad to fold this into 8237 as a PR. If you think there’s no point then thats also fair.
We could constrain the CL req/resp protocol for execution payloads to the latest payload a node has attested to as full. Envelopes already arrive on the execution_payload gossip topic, so req/resp is only ever a recovery path — it covers the case where gossip failed and a peer sees an attestation for a payload it hasn’t received. Attesting full means holding it, since fork choice only offers a FULL node once the envelope is verified, and prior payloads can be fetched over EL p2p. Payloads would then never need to reach the CL database, and the head could be served straight out of fork choice (or an in-memory cache).
Doesn’t this remove the requirement to download payloads (and serve for the most part)?