---
eip: 8365
title: BLS withdrawal credential retirement
description: Exit validators with 0x00 withdrawal credentials and stop creating new ones, keeping the credential change path open
author: NC (@ensi321)
discussions-to: https://ethereum-magicians.org/t/eip-8365-bls-withdrawal-credential-retirement/29284
status: Draft
type: Standards Track
category: Core
created: 2026-07-18
requires: 6110, 7251, 7732
---

## Abstract

This EIP retires the `BLS_WITHDRAWAL_PREFIX` (`0x00`) withdrawal credential type. A standing rule in epoch processing initiates the exit of every active validator whose withdrawal credentials carry the `0x00` prefix, and deposits that would create new validators with `0x00` credentials are no longer processed. The `BLSToExecutionChange` operation is unchanged: a retired validator's full balance remains recoverable at any time by rotating to `0x01` execution credentials, after which the standard withdrawal sweep pays it out.

This is the first stage of a staged deprecation. A companion EIP (balance sunset) gradually reduces retired `0x00` balances to zero ahead of the post-quantum transition, and a final-stage EIP at the post-quantum fork removes the remaining `0x00` machinery (`BLSToExecutionChange`, its gossip topic and operation pool, and the zero-balance registry entries) from the consensus layer entirely.

## Motivation

The `0x00` credential type is the original genesis-era withdrawal format: `0x00 || sha256(withdrawal_bls_pubkey)[1:]`, with withdrawal controlled by a BLS key and no execution address. Since Capella opened one-way conversion to `0x01`, the population has fallen from roughly 600,000 to 9,290 validators (mainnet, July 2026: 9,119 active plus 171 exited awaiting credential rotation), but the decline has stalled. Conversion inclusions have decayed to double digits per month, and of the 9,119 still-active `0x00` validators, 374 have not attested for over six months and 253 have never attested in a 14-month observation window. These are, with high likelihood, validators whose keys are lost.

The stalled tail creates costs that grow with time rather than shrink:

- **Un-removable validators.** No party can exit a `0x00` validator with a lost key. Voluntary exit requires the signing key, and execution-layer triggerable exits ([EIP-7002](./eip-7002.md)) require an execution address that `0x00` credentials do not have. At measured penalty rates (~0.55 ETH/year), natural ejection at `EJECTION_BALANCE` takes roughly 28 years. Offline rates confirm the asymmetry: 4.45% of active `0x00` validators have been offline for 30+ days, versus 0.10% for `0x01` and 0.05% for `0x02`. Being offline is a transient state for execution-credentialed validators, whose owners can always exit and recover funds, but a terminal state for `0x00` validators with lost keys.
- **Permanent protocol surface.** While any `0x00` validator exists, every fork must carry `process_bls_to_execution_change`, its gossip topic, its operation pool, and the `0x00` branch of every credential check.
- **Post-quantum transition burden.** BLS signatures are not post-quantum secure. The post-quantum roadmap has validators registering post-quantum keys ahead of a signature-switch fork, but validators that cannot act (lost keys) cannot register. `BLSToExecutionChange` itself becomes insecure once BLS is broken: the message reveals the withdrawal public key, allowing a quantum adversary to derive the key and race a competing change. Any plan that carries `0x00` validators into the post-quantum era must design and maintain hardened credential-change machinery indefinitely, solely for this population. Retiring the credential type before the transition removes a design question from any post-quantum key registry (how a validator with no execution address authorizes its registration), and lets the signature-switch fork start from a clean validator set.

This EIP alone stops duty participation and closes the inflow. It deliberately does not touch balances: retired validators are frozen (no rewards, no penalties) awaiting credential rotation. Without the companion balance sunset EIP, the frozen entries would persist in the registry indefinitely and the final-stage removal would have to delete entries with non-zero balances, which is a materially harder decision. The staged path (retire, drain, remove) is designed to be evaluated as a whole, while allowing the stages to activate in the same fork or in consecutive forks.

## Specification

### Constants

| Name                        | Value | Comment                                              |
| --------------------------- | ----- | ---------------------------------------------------- |
| `MAX_RETIREMENTS_PER_EPOCH` | TBD   | Maximum retirements initiated per epoch transition   |

### Consensus layer

#### Epoch processing

A new per-epoch step, `process_bls_credential_retirement`, is added to `process_epoch` after `process_registry_updates`:

```python
def process_bls_credential_retirement(state: BeaconState) -> None:
    current_epoch = get_current_epoch(state)
    retirements = 0
    for index, validator in enumerate(state.validators):
        if retirements >= MAX_RETIREMENTS_PER_EPOCH:
            break
        if (
            is_active_validator(validator, current_epoch)
            and validator.withdrawal_credentials[:1] == BLS_WITHDRAWAL_PREFIX
            and validator.exit_epoch == FAR_FUTURE_EPOCH
        ):
            initiate_validator_exit(state, ValidatorIndex(index))
            retirements += 1
```

This is a standing rule, not a one-time transition: it enforces the invariant that `0x00` is not a valid credential for an active validator after the fork. Starting from the first epoch after activation, up to `MAX_RETIREMENTS_PER_EPOCH` retirements are initiated per epoch transition, in validator index order, until the active `0x00` population is exhausted. Any validator that subsequently surfaces from the activation queue with `0x00` credentials is retired by the same rule.

Exits flow through the standard exit churn via `initiate_validator_exit`.

#### Deposit processing

`apply_pending_deposit` is modified so that deposits which would create a new validator with `0x00` withdrawal credentials are not applied:

```python
def apply_pending_deposit(state: BeaconState, deposit: PendingDeposit) -> None:
    validator_pubkeys = [v.pubkey for v in state.validators]
    if deposit.pubkey not in validator_pubkeys:
        # [New in this EIP] Do not create validators with BLS withdrawal credentials
        if deposit.withdrawal_credentials[:1] == BLS_WITHDRAWAL_PREFIX:
            return
        # Verify the deposit signature (proof of possession)
        if is_valid_deposit_signature(
            deposit.pubkey,
            deposit.withdrawal_credentials,
            deposit.amount,
            deposit.signature,
        ):
            add_validator_to_registry(
                state,
                deposit.pubkey,
                deposit.withdrawal_credentials,
                deposit.amount,
            )
    else:
        # Top-ups are unaffected
        index = ValidatorIndex(validator_pubkeys.index(deposit.pubkey))
        increase_balance(state, index, deposit.amount)
```

Rejected deposits receive the same treatment as deposits with invalid signatures today: they are silently skipped and the deposited ETH is not recoverable. Top-up deposits to existing validators, including retired `0x00` validators, are processed normally.

Where builder credential routing applies (`0x03`, [EIP-7732](./eip-7732.md)), the `0x00` check precedes it.

#### Unchanged operations

`process_bls_to_execution_change` is unchanged and remains available. A retired (exited) `0x00` validator that rotates to `0x01` credentials becomes fully withdrawable once its `withdrawable_epoch` has passed, and the withdrawal sweep transfers its entire remaining balance to the execution address in the change message.

`process_voluntary_exit` is unchanged. Voluntary exits of `0x00` validators before the fork have the same effect as retirement.

## Rationale

### Exit as the retirement mechanism

Exiting a validator natively removes it from all duty selection (proposer, attester, sync committee and any future committees) and ends both reward accrual and penalty exposure. No new exclusion machinery is required, and the frozen state ("no rewards, no penalties, balance intact") is exactly the intended holding pattern while awaiting credential rotation.

### A standing rule rather than a one-time sweep

A one-shot mass exit at the fork transition misses validators still in the deposit and activation pipeline, which can surface weeks later, and would require a second special-case event to catch them. A per-epoch rule expresses the actual invariant, drains the existing population and catches stragglers with the same code path, and requires no transition-specific logic.

### Capped initiation rate

Initiating all ~9,000 exits in a single epoch would assign the entire population staggered exit epochs immediately, backing up the exit queue by roughly five days at current churn, and any ordinary validator submitting a voluntary exit during that window would wait behind the full backlog. Capping initiation with `MAX_RETIREMENTS_PER_EPOCH` spreads the load so that the retirement stream consumes a bounded share of the per-epoch exit churn and other validators' exit times are essentially unaffected. Capped per-epoch processing is an established pattern in epoch processing (pending deposits, pending consolidations).

The constant's value trades drain time against churn share, and is left TBD. Indicative values for the current population of ~9,100: a value of `8` matches the exit churn throughput exactly (`MAX_PER_EPOCH_ACTIVATION_EXIT_CHURN_LIMIT` / `MIN_ACTIVATION_BALANCE` = 256 ETH / 32 ETH), completing retirement in about five days while never exceeding the queue's drain rate, and a value of `1` consumes 12.5% of churn capacity and completes in about six weeks. The total time for the population to pass through the exit queue cannot go below the churn-imposed five days regardless of the value.

### Notice and the conversion path

The grace period runs from the publication of this EIP to fork activation, roughly six months on current fork cadence. A `0x00` validator that rotates credentials before activation keeps validating uninterrupted. One that rotates after activation recovers its full balance via the sweep and may re-enter as a new `0x01`/`0x02` validator. No balance is reduced by this EIP at any point.

Voluntary exit requires the signing key while credential rotation requires the withdrawal key, so a holder of only the signing key can exit but not rotate. Such validators are in the same position as the 171 `0x00` validators already exited and awaiting rotation on mainnet today, all of which this EIP leaves untouched (they are already exited) and the companion EIP covers.

### Deposit rejection semantics

Silently skipping the deposit while the ETH remains in the deposit contract is the established treatment of invalid deposits ([EIP-6110](./eip-6110.md) invalid-signature deposits), and [EIP-8205](./eip-8205.md) adopts the same permanent-rejection semantics for credential-mismatched deposits by deliberate design. No new deposit ought to carry `0x00` credentials (every deposit tool has defaulted to execution credentials since Capella), so this branch exists to close the inflow, not to adjudicate marginal cases.

### Staged deprecation precedent

The `SELFDESTRUCT` deprecation followed the same arc across multiple EIPs and forks: [EIP-6049](./eip-6049.md) (deprecation notice), [EIP-6780](./eip-6780.md) (behavioral restriction), and [EIP-4758](./eip-4758.md) (full deactivation). Retire, drain, remove is the same pattern applied to a credential type, with the same motivation: maintaining legacy functionality indefinitely carries a cost for every subsequent upgrade, and a clear deprecation schedule serves both the network and the remaining users better than an open-ended wait.

### Credible neutrality

Rescue proposals for `0x00` validators with lost keys have been rejected in the past on credible-neutrality grounds: a rescue adjudicates off-chain ownership claims and selects beneficiaries. This EIP is the opposite shape: a uniform rule over a class defined by an objective on-chain property, announced well in advance, with a permissionless compliance path (`BLSToExecutionChange`) open to every member throughout. It takes no position on any ownership claim. Rule-based deprecations with forward notice that disadvantage specific users are an established and accepted category: opcode repricings ([EIP-2929](./eip-2929.md)), `SELFDESTRUCT` neutering ([EIP-6780](./eip-6780.md)), and the inactivity leak all share this shape.

### Interaction with the post-quantum key registry

Every post-quantum key registry design under discussion requires a per-validator registration action, and validators that never register cannot remain active past the signature switch, whichever design is chosen. Force-exiting non-registrants is clean for execution-credentialed validators (funds sweep to their execution address) but strands `0x00` balances on the consensus layer. This EIP resolves that asymmetry ahead of time, independently of which registry design is adopted: by the time a registry fork activates, no active validator carries `0x00` credentials, and the registry does not need to consider them.

## Backwards Compatibility

This EIP introduces backward-incompatible changes to consensus-layer state transition and must be scheduled with a hard fork. No execution-layer changes are required. Existing deposit tooling is unaffected unless it attempts to create new `0x00`-credentialed validators, which no maintained tooling does.

## Test Cases

TBD. Reference tests will be provided with the consensus-specs implementation, covering the retirement rule (per-epoch cap respected, index-order draining, activation-queue stragglers), the deposit guard (new `0x00` deposit skipped, top-up applied), and credential rotation after retirement.

## Security Considerations

### Validator set reduction

Retiring the full current population removes at most ~297,000 ETH of effective balance (~1% of total stake at time of writing, and shrinking as conversions occur) from the active set. This is well within normal validator-set churn and does not meaningfully affect finality safety margins or weak-subjectivity periods.

### No change to fund ownership

This EIP moves no balances. Every retired validator's balance remains in the beacon state, recoverable in full at any time through the unchanged `BLSToExecutionChange` path. The population unable to use that path (lost withdrawal keys) is unable to use it today, and this EIP does not change their position.

### Deposit contract griefing

The deposit guard burns deposits that create `0x00` validators. A third party cannot grief anyone with this: constructing such a deposit requires a valid proof-of-possession signature over the `0x00` credentials from the depositing key, so only the key holder can burn their own deposit. This matches the existing invalid-signature deposit semantics.

### Exit queue impact

Retirement initiation is capped at `MAX_RETIREMENTS_PER_EPOCH`, bounding the retirement stream's churn consumption per epoch. With the cap at or below the churn-matched value, no backlog accumulates from retirement and the exit time of ordinary voluntary exits is essentially unaffected throughout the drain window. Ordinary exits initiated during the window share churn with the retirement stream, so combined demand can transiently exceed throughput, but the worst case is mild queueing comparable to any busy exit period, not a multi-day wall.

## Copyright

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