EIP.tools

EIP.tools

⚠️ DraftStandards Track: Core

EIP-8440: Execution Chain Proofs

Proves valid execution of all payloads from the head beacon block to the proof's origin, and their binding to the beacon chain

Authors
Created2026-10-08
Discussion Linkhttps://ethereum-magicians.org/t/eip-8440-execution-chain-proofs/29930
Requires

Markdown

https://raw.githubusercontent.com/ethereum/EIPs/re...
Pull Request#12464PR open

EIP-GPT summary

Contents
AbstractMotivationSpecificationSpecification referencesTerminologyPublic inputGossiped proofRecursive guest programRationaleCommitting through beacon blocksReusing the envelope handlerProver-chosen originWeak subjectivity syncOne payload per stepBackwards CompatibilityTest CasesReference ImplementationSecurity ConsiderationsCopyright

Abstract

This EIP introduces execution chain proofs, which make execution-layer chain sync constant time. A node establishes valid execution of all payloads in the chain from the head beacon block to the proof's origin beacon block, and their binding to the beacon chain, by verifying a single execution chain proof. Execution chain proofs are recursive execution proofs: each proof verifies the proof of the previous full execution payload on its branch and then proves one more payload. The origin is the block at which the prover started the recursion. Execution chain proofs build on the execution proofs of EIP-8025.

Motivation

A node syncing from a weak subjectivity checkpoint establishes valid execution from the checkpoint to the head with one proof whose origin is at or before the checkpoint. It downloads and verifies that single chain proof instead of every full payload for re-execution, so its bandwidth and computation are constant and execution-layer chain sync takes constant time (see Weak subjectivity sync). Because each proof supersedes the ones before it on its branch, nodes need not store proof history, and provers do constant work per payload. Execution chain proofs also advance the roadmap for stateless clients, validity-only partially stateless (VOPS) nodes and light clients.

Specification

The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119 and RFC 8174.

Specification references

The normative specification is maintained in the consensus-specs repository. This section summarises it.

Terminology

  • Full and empty. A beacon block is full when the next block on its branch applies its execution payload, and empty otherwise, as in EIP-7732.
  • Step. One run of the recursive guest program. A step extends the parent proof's chain by one full payload, or starts a new chain with it.
  • Head. The beacon block whose payload a proof's last step proved.
  • Origin. The beacon block whose payload the first step of a recursion proved. The prover chooses it.

Public input

class PublicInput(ProgressiveContainer):
    ACTIVE_FIELDS = active_fields(width=4)

    origin_block_root: Root
    head_block_root: Root
    chain_id: Uint64
    schema_id: Uint16
  • head_block_root is the head, the binding commitment of the proof.
  • origin_block_root is the origin, carried unchanged through every step.
  • chain_id is the chain ID, and schema_id is the stateless input schema version.

Gossiped proof

The chain ID and schema are constants of the specification, so a proof carries only the two roots:

class ExecutionProof(Container):
    proof_data: ProofData
    proof_type: ProofType
    origin_block_root: Root
    head_block_root: Root


class SignedExecutionProof(Container):
    message: ExecutionProof
    validator_index: ValidatorIndex
    signature: BLSSignature

The proof engine verifies a proof against the public input built from its two roots, DEPOSIT_CHAIN_ID and STATELESS_INPUT_SCHEMA_ID. Signed proofs are gossiped on the execution_proof topic. The execution payload is not required for proof verification, and a valid proof does not imply that the head's payload is available or was applied. MAX_SIGNED_EXECUTION_PROOF_SIZE is 4194481.

Recursive guest program

The guest's private input is:

  • previous_proof: the parent proof, or none to start a new chain;
  • previous_state and state: the beacon state witness, the fields of the beacon states after the parent proof's head block and after the target block that the step reads, each authenticated against its block root;
  • signed_envelope: the target block's signed execution payload envelope; and
  • execution_witness: the execution witness of the target payload.

Both beacon states are taken immediately after their blocks, not advanced to a later slot. A step runs:

def verify_execution_transition(proof_engine, execution_engine, private_input) -> PublicInput:
    state = private_input.state
    envelope = private_input.signed_envelope.message

    previous_proof = private_input.previous_proof
    if previous_proof is None:
        assert private_input.previous_state is None
        origin_block_root = envelope.beacon_block_root
    else:
        # Verify the parent proof as consensus clients verify proofs
        assert proof_engine.verify_execution_proof(previous_proof)
        origin_block_root = previous_proof.origin_block_root

        # Authenticate the parent head's beacon state against its block root
        previous_state = private_input.previous_state
        previous_header = previous_state.latest_block_header.copy()
        previous_header.state_root = hash_tree_root(previous_state)
        assert hash_tree_root(previous_header) == previous_proof.head_block_root

        # Bind consecutive heads
        assert state.latest_block_hash == previous_state.latest_execution_payload_bid.block_hash

    # Per-payload limits that Gloas enforces only in envelope gossip. The gossip
    # helper raises GossipReject, which fails the proof like an assertion.
    verify_execution_requests_limits(envelope.execution_requests)
    assert len(envelope.payload.withdrawals) <= MAX_WITHDRAWALS_PER_PAYLOAD

    # Bind the payload to the target block and validate it statelessly
    verify_execution_payload_envelope(state, private_input.signed_envelope, execution_engine)

    return PublicInput(
        origin_block_root=origin_block_root,
        head_block_root=envelope.beacon_block_root,
        chain_id=DEPOSIT_CHAIN_ID,
        schema_id=STATELESS_INPUT_SCHEMA_ID,
    )

Any failed assertion or raised exception fails the proof.

verify_execution_payload_envelope is the EIP-7732 function that consensus clients run on a received payload envelope. Given the target beacon state, it authenticates that state against the envelope's block root and checks:

  • the builder's envelope signature;
  • the envelope against the block's committed bid;
  • the payload's slot, timestamp, parent hash and withdrawals against the state; and
  • the payload itself, through verify_and_notify_new_payload, the call behind engine_newPayload.

The guest thus proves both sides of the Engine API: the consensus client's binding of the payload to its block, and the execution engine's validation of it. This lets the public input commit to the execution chain through beacon block roots.

Implementations SHOULD supply the beacon state witness as partial SSZ trees whose roots are the full state roots and in which only the fields the step reads are expanded. Reading a field that is not expanded MUST fail the proof.

Rationale

Committing through beacon blocks

The public input names beacon block roots rather than execution block hashes. A node checks a proof against beacon blocks it already holds, and the proof's statement is about the chain ending at its head block, which is what a node following that chain needs.

Reusing the envelope handler

The guest calls the function consensus clients run on payload envelopes rather than restating its checks. When a later fork changes that function, the guest follows, and the binding between a block and its payload cannot drift between the guest and consensus clients. The request and withdrawal count limits are the exception: EIP-7732 enforces them only in envelope gossip, so the guest checks them explicitly.

Prover-chosen origin

The prover may start a recursion at any full block. A proof that starts at its own head proves one payload, and recursion extends it from there. No origin is configured into clients, so proving can begin at any time and restart after an interruption. A consumer reads the origin from the proof to see how far back a proof reaches.

Weak subjectivity sync

A node syncing from a weak subjectivity checkpoint must establish valid execution of the NN full payloads between the checkpoint and the head. With execution costs eie_i and sizes bib_i, and a proof of size π\pi and verification cost vv, an execution chain proof whose origin is at or before the checkpoint reduces bandwidth and computation from

$$ B = \sum_{i=1}^{N} b_i, \qquad C = \sum_{i=1}^{N} e_i $$

to

$$ B = \pi, \qquad C = v. $$

Both are constant in NN, as is the cost of state sync to the head, so execution-layer chain sync takes constant time. Data availability is established separately (see Security Considerations).

As an estimate: under current mainnet churn parameters the weak subjectivity bound is about 3,532 epochs, roughly 15.7 days (EIP-8383). Etherscan's 30-day averages to 8 October 2026 are about 7,170 blocks per day, 183 KB and 30.3 million gas per block. Syncing across one bound therefore means re-executing N≈1.1×105N \approx 1.1 \times 10^5 payloads, about 21 GB and 3.4×10123.4 \times 10^{12} gas, whereas a proof within the Ethereum Foundation's 300 KiB real-time proving target is about 7×1047 \times 10^4 times smaller and is verified once.

One payload per step

Each step proves exactly one full payload, so the step's work is bounded by one payload and the binding is a single equality. A step spans any number of empty blocks without extra witnesses.

Backwards Compatibility

Execution chain proofs use a different public input and gossip message from EIP-8025, so nodes implementing each cannot share the execution_proof topic.

Test Cases

Consensus-layer tests for the guest program and proof handling are in the consensus specifications. They cover base and recursive steps, steps across empty blocks and missed slots, skipped and unapplied payloads, a parent extended to its own head, mismatched parent states, invalid parent proofs and payloads, signed proofs and proofs keyed by their head, envelopes inconsistent with the state, and the request and withdrawal limits.

Reference Implementation

The executable consensus specification is the reference implementation of the guest step.

Security Considerations

Separation of consensus and execution. An execution chain proof covers only the execution state transition: each payload's execution and its binding to the beacon block that committed to it. The verifying node executes the beacon state transition natively, including for the blocks between consecutive proof heads. Verifying a proof does not change fork choice or payload status.

Reorgs. A recursion follows one branch. When the chain reorganises, proofs whose heads lie only on the abandoned branch cannot be extended onto the new branch, because the new branch's blocks record a different last applied payload. Recursion on the new branch continues from the last proof whose head payload both branches applied, or restarts with a new origin. Until then, nodes on the new branch have no execution chain proof for its head.

Origin depth. A proof says nothing about payloads before its origin. Nodes MUST check that a proof's origin is at or before the point from which they need execution validity, such as the checkpoint block they synced from. Nodes SHOULD place an older origin using the checkpoint state's block_roots or historical_summaries; how they obtain the required data is out of scope.

Program and fork upgrades. A guest program MUST accept parent proofs only of its own proof type and, to continue recursion across an upgrade, of its predecessor proof types.

Chain binding. The guest MUST NOT take the chain ID or fork schedule from its private input.

Fork activation. The guest's execution engine MUST reject payloads outside the fork it implements; otherwise a payload could be proven under the wrong fork rules.

Data availability. The guest does not prove blob data availability. Nodes MUST continue to establish availability by the means EIP-7732 and its successors define.

Copyright and related rights waived via CC0.

EIP.tools

EIP.tools

Search, read, and map Ethereum improvement proposals, ERCs, RIPs, and CAIPs from one focused interface.

Farcaster
by @apoorveth