---
eip: 6466
title: SSZ receipts
description: Migration of RLP receipts to SSZ
author: Etan Kissling (@etan-status), Gajinder Singh (@g11tech), Vitalik Buterin (@vbuterin)
discussions-to: https://ethereum-magicians.org/t/eip-6466-ssz-receipts/12884
status: Draft
type: Standards Track
category: Core
created: 2023-02-08
requires: 658, 2718, 6404, 7495, 7668, 7702, 7916, 8016, 8116
---

## Abstract

This EIP defines a migration process of [EIP-2718](./eip-2718.md) Recursive-Length Prefix (RLP) receipts to [Simple Serialize (SSZ)](https://github.com/ethereum/consensus-specs/blob/b3e83f6691c61e5b35136000146015653b22ed38/ssz/simple-serialize.md)

## Motivation

RLP receipts have a number of shortcomings:

1. **Limited proving support:** Due to receipt data being linearly hashed as part of the `receipts_root` Merkle-Patricia Trie (MPT), it is not possible to efficiently proof individual parts of receipts, such as logs. Requiring the full receipt data to be present can be prohibitive for smart contract based applications such as L2 fraud proofs or client applications verifying log data.

2. **Incomplete data:** JSON-RPC provides `from`, `gasUsed`, and `contractAddress` fields for receipts, but the on-chain receipt does not contain the required information to verify them.

This EIP defines a universal receipt format based on SSZ to address these concerns.

## 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`](https://github.com/ethereum/consensus-specs/blob/b3e83f6691c61e5b35136000146015653b22ed38/specs/phase0/beacon-chain.md#custom-types) | `Bytes32` |
| [`ExecutionAddress`](https://github.com/ethereum/consensus-specs/blob/b3e83f6691c61e5b35136000146015653b22ed38/specs/bellatrix/beacon-chain.md#custom-types) | `Bytes20` |
| [`GasAmount`](./eip-6404.md#normalized-transactions) | `uint64` |

### Logs

Logs are represented as an SSZ `Container`.

| Name | Value | Description |
| - | - | - |
| `MAX_TOPICS_PER_LOG` | `4` | `LOG0` through `LOG4` opcodes allow 0-4 topics per log |

```python
class Log(Container):
    address: ExecutionAddress
    topics: List[Bytes32, MAX_TOPICS_PER_LOG]
    data: ProgressiveByteList
```

### Receipts

New receipts use a normalized SSZ representation.

```python
class Receipt(CompatibleUnion({
    0x01: BasicReceipt,
    0x02: CreateReceipt,
    0x03: SetCodeReceipt,
})):
    pass
```

#### Basic receipts

This receipt is emitted for these transactions:

- [`RlpLegacyReplayableBasicTransaction`](./eip-6404.md#normalized-transactions)
- [`RlpLegacyBasicTransaction`](./eip-6404.md#normalized-transactions)
- [`RlpAccessListBasicTransaction`](./eip-6404.md#normalized-transactions)
- [`RlpBasicTransaction`](./eip-6404.md#normalized-transactions)
- [`RlpBlobTransaction`](./eip-6404.md#normalized-transactions)

```python
class BasicReceipt(
    ProgressiveContainer(active_fields=[1, 1, 0, 1, 1])
):
    from_: ExecutionAddress
    gas_used: GasAmount
    logs: ProgressiveList[Log]
    status: boolean
```

#### Create receipts

This receipt is emitted for these transactions:

- [`RlpLegacyReplayableCreateTransaction`](./eip-6404.md#normalized-transactions)
- [`RlpLegacyCreateTransaction`](./eip-6404.md#normalized-transactions)
- [`RlpAccessListCreateTransaction`](./eip-6404.md#normalized-transactions)
- [`RlpCreateTransaction`](./eip-6404.md#normalized-transactions)

```python
class CreateReceipt(
    ProgressiveContainer(active_fields=[1, 1, 1, 1, 1])
):
    from_: ExecutionAddress
    gas_used: GasAmount
    contract_address: ExecutionAddress
    logs: ProgressiveList[Log]
    status: boolean
```

#### EIP-7702 set code receipts

This receipt is emitted for these transactions:

- [`RlpSetCodeTransaction`](./eip-6404.md#normalized-transactions)

```python
class SetCodeReceipt(
    ProgressiveContainer(active_fields=[1, 1, 0, 1, 1, 1])
):
    from_: ExecutionAddress
    gas_used: GasAmount
    logs: ProgressiveList[Log]
    status: boolean
    authorities: ProgressiveList[ExecutionAddress]
```

### `Receipt` construction

Receipts are constructed as follows.

| Field | Description |
| - | - |
| `from` | The transaction sender's address |
| `gas_used` | How much gas this individual transaction used |
| `contract_address` | For transactions deploying a contract, the new contract address. Present only in `CreateReceipt` |
| `logs` | Logs emitted during transaction execution |
| `status` | [EIP-658](./eip-658.md) transaction status code |
| `authorities` | For transactions with an authorization list, the list of [EIP-7702](./eip-7702.md) `authority` addresses. Non-successful authorizations are represented with an all-zero address |

The `logs_bloom`, intermediate state `root` (Homestead scheme), and `cumulative_gas_used` (pre [EIP-8116](./eip-8116.md)) fields are not present in SSZ receipts.

### Execution block header changes

The [execution block header's `receipts-root`](https://github.com/ethereum/devp2p/blob/bc76b9809a30e6dc5c8dcda996273f0f9bcf7108/caps/eth.md#block-encoding-and-validity) is transitioned from MPT to SSZ.

```python
receipts = ProgressiveList[Receipt](
    receipt_0, receipt_1, receipt_2, ...)

block_header.receipts_root = receipts.hash_tree_root()
```

### JSON-RPC API

Transaction receipt objects in the context of the JSON-RPC API are extended to include:

- `authorities`: `Array of DATA|null` - Array of `DATA` entries each containing 20 Bytes, corresponding to the receipt's `authorities` field

The `logsBloom` field is no longer returned for new receipts. It continues to be returned for historical receipts conforming to earlier schemes.

`from`, `gasUsed`, and `contractAddress` are already provided via JSON-RPC and are left unchanged. For `BasicReceipt` and `SetCodeReceipt`, `contractAddress` will be `null` as these receipt types do not contain the `contract_address` field. `logIndex` indicates the log index position in the individual receipt (rather than the entire block), as defined in [EIP-8116](./eip-8116.md).

### Consensus `ExecutionPayload` changes

When building a consensus `ExecutionPayload`, the [`receipts_root`](https://github.com/ethereum/consensus-specs/blob/b3e83f6691c61e5b35136000146015653b22ed38/specs/deneb/beacon-chain.md#executionpayload) is now based on the `Receipt` type, changing the type of `receipts_root` from an MPT [`Hash32`](https://github.com/ethereum/consensus-specs/blob/b3e83f6691c61e5b35136000146015653b22ed38/specs/phase0/beacon-chain.md#custom-types) to an SSZ [`Root`](https://github.com/ethereum/consensus-specs/blob/b3e83f6691c61e5b35136000146015653b22ed38/specs/phase0/beacon-chain.md#custom-types).

```python
class ExecutionPayload(...):
    ...
    receipts_root: Root
    ...

class ExecutionPayloadHeader(...):
    ...
    receipts_root: Root
    ...
```

```python
payload_header.receipts_root = payload.receipts_root
```

## Rationale

### Forward compatibility

All receipts share the same Merkle tree shape with a stable [generalized index (gindex)](https://github.com/ethereum/consensus-specs/blob/b5c3b619887c7850a8c1d3540b471092be73ad84/ssz/merkle-proofs.md#generalized-merkle-tree-index) assigned to each field. Future transaction features can introduce additional receipt fields or drop existing fields without breaking verifiers.

### Verifier improvements

Committing to `from`, `contract_address` and `authorities` in the receipt allows efficient verification without the expensive `ecrecover` mechanism. This allows future EIPs to change how these addresses are computed without breaking verifiers, e.g., when future signature schemes are introduced.

### Execution client improvements

Execution Layer implementations no longer need access to the transaction and additional indices when serving receipts based on SSZ.

## Backwards Compatibility

Applications that rely on the replaced MPT `receipts_root` in the block header require migration to the SSZ `receipts_root`.

RLP and SSZ receipts may clash when encoded. It is essential to use only a single format within one channel. When requesting receipts by hash over the network, the block header corresponding to the containing receipts root can be consulted to identify the underlying fork.

## Security Considerations

None

## Copyright

Copyright and related rights waived via [CC0](../LICENSE.md).
