EIP-7807 - SSZ execution blocks

Created 2024-10-28
Status Draft
Category Core
Type Standards Track
Authors
Requires

Abstract

This EIP migrates the execution block to Simple Serialize (SSZ), including the block hash, request hash, and the per-block tries. Notably, individual transaction, receipt, and withdrawal list elements as well as the state trie are not affected by this EIP.

Motivation

The execution block and its per-block tries use Merkle-Patricia and RLP encoding, separate from the SSZ representation used by the Consensus Layer. Migrating the block to SSZ unifies the block representation across both layers and enables:

  1. Normalized block hash: The Consensus Layer can autonomously check the execution block hash against the builder's commitment, enabling early consistency checks that otherwise require asynchronous communication with the Execution Layer.

  2. Optimized engine API: With all exchanged data supporting SSZ, the engine API can be changed from the textual JSON encoding to binary SSZ encoding, reducing exchanged data size by ~50% and significantly improving encoding/parsing efficiency.

  3. Proving support: With SSZ, individual fields of the execution block become provable without requiring the full block to be present. With EIP-7495 ProgressiveContainer and EIP-7916 ProgressiveList, proofs are forward compatible as long as underlying semantics of individual fields are unchanged, reducing maintenance requirements for smart contracts and verifying client applications.

  4. Cleanup opportunity: The conversion to SSZ allows dropping historical fields from the PoW era and the inefficient logs bloom mechanism.

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.

Existing definitions

Definitions from existing specifications that are used throughout this document are replicated here for reference.

Name SSZ equivalent
Root Bytes32
ExecutionAddress Bytes20

Gas amounts

The different kinds of gas amounts and fees are combined into a single structure.

Name SSZ equivalent Description
GasAmount uint64 Amount in units of gas
FeePerGas uint256 Fee per unit of gas
class GasAmounts(ProgressiveContainer(active_fields=[1] * 2)):
    regular: GasAmount
    blob: GasAmount

class BlobFeesPerGas(ProgressiveContainer(active_fields=[1] * 2)):
    regular: FeePerGas
    blob: FeePerGas

Execution block

New execution blocks use a normalized SSZ representation.

class ExecutionPayload(ProgressiveContainer(active_fields=[1] * 18)):
    parent_hash: Root
    miner: ExecutionAddress
    state_root: Bytes32
    transactions: ProgressiveList[ProgressiveByteList]
    receipts_root: Root
    number: uint64
    gas_limits: GasAmounts
    gas_used: GasAmounts
    timestamp: uint64
    extra_data: ByteList[MAX_EXTRA_DATA_BYTES]
    mix_hash: Bytes32
    base_fees_per_gas: BlobFeesPerGas
    withdrawals: ProgressiveList[ProgressiveByteList]
    excess_gas: GasAmounts
    parent_beacon_block_root: Root
    requests_hash: Root
    block_access_list: ProgressiveByteList
    slot_number: uint64

An execution block header can be derived as an SSZ summary of ExecutionPayload that replaces the transactions, withdrawals, and block_access_list fields with their corresponding hash_tree_root.

Consensus ExecutionPayload changes

The ExecutionPayload definition replaces the Consensus Layer ExecutionPayload, carried by the ExecutionPayloadEnvelope.

Execution block hash computation

The execution block hash is computed as ExecutionPayload.hash_tree_root() in all contexts, including (1) the BLOCKHASH opcode, (2) JSON-RPC API interactions (blockHash field), (3) devp2p networking, and (4) Consensus Layer references in BeaconState.latest_block_hash / ExecutionPayloadBid.block_hash.

JSON-RPC

JSON-RPC block responses MUST set the logsBloom field to all 1 bits (256 bytes of 0xff).

Rationale

Forward compatibility

ExecutionPayload uses ProgressiveContainer and ProgressiveList: generalized indices remain stable as the block definition evolves, and the lists can grow without a hardcoded limit.

Logs bloom

Using an all 1 bits value forces consumers to fall back to inspecting every receipt; all 0 bits would signal a definite absence and may cause missed logs.

Engine API

The shared SSZ block hash lets the engine API drop the redundant block_hash field and adopt binary ForkDigest-context encoding. This reduces encoding overhead and simplifies sharing data structures in combined Consensus Layer / Execution Layer implementations.

Backwards Compatibility

This breaks compatibility of smart contracts that depend on the previous block header binary format, including for "generic" implementations that assume a common prefix and run the entire data through a linear keccak256 hash.

JSON-RPC consumers that read logsBloom observe an all-1 value for SSZ blocks, which is backwards compatible. The receipt logsBloom is unaffected by this EIP.

Security Considerations

The SSZ block hash is based on SHA256 and shares the namespace with existing keccak256 based block hashes. As these hash algorithms are fundamentally different, no significant collision risk is expected.

Copyright

Copyright and related rights waived via CC0.