zkEVMs allow validators to verify the correctness of an execution payload using a proof, without downloading or executing the payload itself. However, removing the requirement to download the execution payload, also removes the implicit data availability (DA) guarantee; a block producer can publish a valid proof and withhold the execution-payload data since attesters no longer need them for consensus.
This EIP introduces Block-in-Blobs (BiB), a mechanism that requires the execution-payload data (transactions and BALs) to be published in blob data, in the same beacon block that carries the corresponding execution payload's header. This ensures that execution payloads and their associated data are always published even when validators no longer require them to verify the state transition function (STF).
In short, BiB works by having the block producer encode the execution-payload data into blobs as part of the execution layer's STF, requiring the beacon block’s blob KZG commitments to commit to those payload-blobs.
Validation via re-execution
Today, validators verify execution payloads by:
Implicitly this guarantees execution payload availability because the payload cannot be verified unless the node downloads it.
Validation with zkEVMs
With zkEVMs, validators instead:
In this model, validators no longer require access to the full execution payload data itself in order to verify its correctness.
The DA problem
Removing the re-execution requirement in consensus removes the implicit requirement that consensus clients download the execution payload.
A malicious or rational builder could:
Builders: Since builders will always need to re-execute in order to build blocks, a malicious builder would not publish the execution payload ensuring that they are the only ones that can build on top of the current chain.
RPC and indexers: Many nodes such as RPC providers and indexers cannot solely rely on execution proofs and must re-execute the execution payload.
BiB addresses this by making the execution payload available via blobs.
Type-3 transaction: Refers to EIP-4844 blob-carrying transactions (transaction type 0x03). These transactions include blob versioned hashes that commit to blobs carrying user data.
BiB ensures the proven payload is published:
Payload availability invariant: A valid block implies there exists an ordered list of blobs whose bytes decode to the canonical execution-payload data, and the KZG commitments for these blobs match the first payload_blob_count blob commitments referenced by the block. The existing DAS mechanism will ensure that those blobs are available.
These parameters are defined in EIP-4844 and related specs:
| Name | Value | Source |
|---|---|---|
FIELD_ELEMENTS_PER_BLOB | 4096 | EIP-4844 |
BYTES_PER_FIELD_ELEMENT | 32 | EIP-4844 |
GAS_PER_BLOB | 2**17 | EIP-4844 |
MAX_BLOBS_PER_BLOCK | Network-specific | EIP-7892 |
Note on MAX_BLOBS_PER_BLOCK: This constant represents the maximum number of blobs (both payload-blobs and type-3 transaction blobs) that can be included in a block. Per EIP-7892, the execution layer's blobSchedule.max MUST equal the consensus layer's MAX_BLOBS_PER_BLOCK configuration value at any given time. This value may change across forks (e.g., initially 6 in EIP-4844, potentially increased in subsequent blob throughput increase proposals).
| Name | Value | Description |
|---|---|---|
USABLE_BYTES_PER_FIELD_ELEMENT | BYTES_PER_FIELD_ELEMENT - 1 (31) | Usable bytes per field element (final byte must be zero to stay under BLS modulus) |
USABLE_BYTES_PER_BLOB | FIELD_ELEMENTS_PER_BLOB * USABLE_BYTES_PER_FIELD_ELEMENT | Total usable bytes per blob |
Summary: The execution layer is modified in the following ways:
payload_blob_count field to track how many blobs are used for the execution payload data, enabling verification of the correct number of payload-blobs at the Engine API boundary.engine_getPayload computes the payload-blobs when building a block, sets payload_blob_count in the ExecutionPayloadHeader, and returns the payload blobs (with their commitments and proofs) alongside type-3 transaction blobs in the response.engine_newPayload takes the ExecutionPayload and before passing it to the EL STF, it computes the payload-blobs, checks that the amount of blobs needed is equal to the payload_blob_count value in the ExecutionPayloadHeader and verifies that the expected version hashes match.The execution layer uses methods and classes defined in the corresponding consensus 4844/7594 specs.
Specifically, we use the following methods from polynomial-commitments.md:
And the following methods from polynomial-commitments-sampling.md:
And the following methods from beacon-chain.md:
This method will be used to implement the modified logic in engine_getPayload.
Invertibility invariant: execution_payload_data_to_blobs and blobs_to_execution_payload_data are mutual inverses on valid execution-payload data.
Execution-payload data refers to the subset of the ExecutionPayload that must be made available via blobs. This includes:
bals (Block Access List added in EIP-7928)transactionsSee What is included in execution-payload data? in the Rationale for details.
Note: This is not an SSZ Container - fields are RLP-encoded as described in the encoding functions. The MAX_TRANSACTIONS_PER_PAYLOAD bound is inherited from the ExecutionPayload field limit defined in the consensus specification.
This EIP adds a new field to the ExecutionPayloadHeader:
Semantics:
blob_kzg_commitments be the ordered list of kzg commitments referenced by the beacon blockpayload_blob_count entries of blob_kzg_commitments are the payload-blob commitments (i.e. commitments to the blobs that correspond to the payload data)For the zkEVM-optimized variant of engine_getPayload, this EIP extends BlobsBundle with an additional field:
payload_kzg_proofs: List[KZGProof]Semantics:
verify_blob_kzg_proof_batchpayload_blob_countThis section specifies two equivalent formulations of new_payload. Implementers choose one based on their execution context:
blob_to_kzg_commitment directly. Suitable for pre mandatory proofs implementations.verify_blob_kzg_proof_batch. Avoids the multiscalar multiplication (MSM) which is expensive to prove in a zkEVM circuit.Both variants enforce identical validity conditions. A block valid under one is valid under the other.
The builder must compute the payload blob count when constructing the block:
Note: The builder must account for payload blob usage when selecting type-3 transactions to ensure the total blob count does not exceed MAX_BLOBS_PER_BLOCK.
For the zkEVM-optimized variant, the builder must additionally compute random point KZG proofs for the payload blobs, which will be used as private inputs in the zkEVM circuit for payload consistency verification.
This variant extends BlobsBundle with an additional payload_kzg_proofs field containing random point KZG proofs for payload blobs.
Note for implementors:
payload_kzg_proofs field contains KZG opening proofs for payload blobs only. It is used for payload consistency verification via verify_blob_kzg_proof_batch.payload_blob_count commitments from all_commitments (i.e., all_commitments[:payload_blob_count]). This corresponds to the payload_kzg_commitments parameter in the zkEVM variant of engine_newPayload.Note: Once zkEVM proofs are required for consensus, newPayload will be executed inside a zkEVM to generate a proof, rather than being executed natively by validators. This variant is designed to be cheaper in that context.
This variant replaces the MSM in blob_to_kzg_commitment with polynomial opening proofs, which are cheaper to verify inside a zkEVM. The payload, commitments and KZG proofs are private inputs to the zkEVM circuit, while the corresponding versioned hashes (and payload header) are public inputs.
The consensus layer does not introduce new blob specific validation rules for payload-blobs beyond what we have for EIP-4844/EIP-7594.
The Consensus Layer relies on payload_blob_count in the ExecutionPayloadHeader to interpret the ordering of blob commitments, but otherwise treats payload blobs identically to other blobs for availability and networking.
This EIP deprecates the ExecutionPayloadEnvelope from EIP-7732. Transactions and BAL are published in blobs; all other payload fields move to ExecutionPayloadBid:
BiB reuses the existing blob networking mechanism. Nodes reconstruct the execution payload from the bid (header fields) and blobs (transactions, BAL).
Unlike most type-3 blob transactions, payload-blobs will not have been propagated before block building, which may imply higher bandwidth requirements from builders.
BiB introduces protocol mandated blob usage, rather than user initiated via type-3 transactions. Fee accounting for payload-blobs differ in nature from transaction blob fees as a result.
This EIP does not mandate that payload-blobs pay a per-blob fee like transaction blobs.
Instead payload-blobs are treated as a protocol-accepted cost when constructing the block. In particular:
Because payload blobs consume blob gas, they directly influence blob congestion and the blob base fee.
A potential concern is whether a malicious builder could create artificially large execution payloads to inflate blob gas usage.
This attack is economically constrained: to increase the size of the execution payload, a builder must include additional transactions with calldata. Since calldata costs execution gas, the builder would need to pay for this additional data through the normal gas mechanism. The cost of including extra calldata makes it economically unfavorable to artificially inflate payload size solely to manipulate blob fees.
Execution-payload data includes bals (Block Access Lists from EIP-7928) and transactions.
Why transactions? Transaction data is the only component of the execution payload that cannot be derived from other components and is not provided by the consensus layer.
Why BALs? While BALs are technically the output of executing transactions and could be recomputed, once zkEVM proofs become mandatory for consensus, validators no longer execute payloads. A malicious builder could publish a valid proof and withhold both the execution payload data and the BALs. This would prevent other builders from constructing subsequent blocks and prevent RPC providers from serving the full state. Including BALs in payload-blobs ensures they remain available.
Why not withdrawals? Withdrawals can be derived on the consensus layer.
Why not execution requests? Execution requests can be recomputed from transactions and do not suffer from the same withholding attack as BALs because they are required by the consensus layer for validation.
Why not the header? The header cannot be put into blobs because it contains payload_blob_count, which depends on the number of blobs; causing a circular dependency.
Encoding optimization: The encoding includes an 8-byte header: [4 bytes BAL length][4 bytes transaction length]. This allows extracting just the BAL data without parsing transactions.
TODO: We could also put the number of blobs that the BAL occupies in the execution payload header.
k blobsThis EIP specifies that the block builder choose payload_blob_count, subject to the constraint imposed by MAX_BLOBS_PER_BLOCK.
An alternative would have been to always reserve k blobs, where k corresponds to the worst case execution payload size. While this provides better predictability, it reduces flexibility under blob congestion.
Doing it in the EL STF would require payload-blob commitments or versioned hashes to be made visible inside the core execution logic, rather than being handled at the Engine API boundary.
The execution payload grows linearly with the gas limit. Requiring attesters to download the payload for DA would create an increasing bandwidth burden as the gas limit grows.
Compression can be used on the serialized execution-payload data. This (in theory) should allow the usage of less payload-blobs, depending on the compression ratio. The tradeoffs being:
Whether we should use a compression algorithm and which one requires more investigation, in particular we need to investigate:
For now we recommend using no compression algorithm and operating on uncompressed data.
Serialization of the execution-payload data uses RLP. Since transactions in the ExecutionPayload are already RLP-encoded, we simply RLP-encode the list of transaction bytes without any additional transformation.
While a more zk-friendly serialization algorithm could be beneficial in the future, this EIP uses RLP for simplicity. Once EIP-7807 (SSZ execution blocks) is implemented, the encoding can be updated to SSZ-serialize the list of SSZ-encoded transaction bytes.
This requires changes to the execution payload header and the EL STF; so requires a fork. Nodes that do not implement BiB will not be able to validate blocks after activation.
TODO
TODO
Interaction with blob congestion and denial-of-service
Payload-blobs consume blob gas and therefore are subject to the same congestion control mechanisms and blob limits as transaction blobs.
As a byproduct, this ensures that a malicious block producer cannot make arbitrarily large execution payloads without accounting for blob gas limits. While a block producer could theoretically drive up the blob base fee by creating large payloads, this attack is economically constrained by calldata costs (see Fee Accounting for details).
Data withholding
An attacker cannot withhold execution payload data without also withholding blob data, which would violate existing DAS guarantees and cause the block to be rejected by the consensus layer.
Copyright and related rights waived via CC0.