Alert Source Discuss
⚠️ Draft Standards Track: Core

EIP-6465: SSZ Withdrawals Root

Migration of withdrawals MPT commitment to SSZ

Authors Etan Kissling (@etan-status), Mikhail Kalinin (@mkalinin)
Created 2023-02-08
Discussion Link
Requires EIP-4895


This EIP defines a migration process of the existing Merkle-Patricia Trie (MPT) commitment for withdrawals to Simple Serialize (SSZ).


While the consensus ExecutionPayloadHeader and the execution block header map to each other conceptually, they are encoded differently. This EIP aims to align the encoding of the withdrawals_root, taking advantage of the more modern SSZ format. This brings several advantages:

  1. Reducing complexity: The proposed design reduces the number of use cases that require support for Merkle-Patricia Trie (MPT).

  2. Reducing ambiguity: The name withdrawals_root is currently used to refer to different roots. The execution block header refers to a MPT root, the consensus ExecutionPayloadHeader refers to an SSZ root.


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
ValidatorIndex uint64
Gwei uint64
ExecutionAddress Bytes20
WithdrawalIndex uint64
Name Value

Withdrawal representation

The existing consensus Withdrawal SSZ container is used to represent withdrawals.

class Withdrawal(Container):
    index: WithdrawalIndex
    validator_index: ValidatorIndex
    address: ExecutionAddress
    amount: Gwei

Consensus ExecutionPayload building

When building a consensus ExecutionPayload, the withdrawals_root is now based on the Withdrawal SSZ container. Implementations that currently produce withdrawals in the EIP-4895 format can convert them using the normalize_withdrawal helper function.

Execution block header changes

The execution block header’s withdrawals-root is updated to match the consensus ExecutionPayloadHeader.withdrawals_root.

withdrawals = List[Withdrawal, MAX_WITHDRAWALS_PER_PAYLOAD](
    withdrawal_0, withdrawal_1, withdrawal_2, ...)

block_header.withdrawals_root == withdrawals.hash_tree_root()


The recover_encoded_withdrawal helper function recovers a withdrawal’s original representation for exchange through the devp2p Withdrawals message.


This change was originally a candidate for inclusion in Shanghai, but was postponed to accelerate the rollout of withdrawals.

Backwards Compatibility

Applications that solely rely on the Withdrawal RLP encoding but do not rely on the withdrawals_root in the block header can still be used through a re-encoding proxy.

Applications that rely on the replaced MPT withdrawals_root in the block header can no longer find that information. Analysis is required whether affected applications have a migration path available to use the SSZ withdrawals_root instead.

Withdrawals were only just recently introduced as part of EIP-4895 (Shanghai). It is not expected that major applications already rely on the Merkle-Patricia Trie commitment for withdrawals.

Test Cases


Reference Implementation


Security Considerations


Copyright and related rights waived via CC0.


Please cite this document as:

Etan Kissling (@etan-status), Mikhail Kalinin (@mkalinin), "EIP-6465: SSZ Withdrawals Root [DRAFT]," Ethereum Improvement Proposals, no. 6465, February 2023. [Online serial]. Available: