Alert Source Discuss
⚠️ Draft Standards Track: Core

EIP-8061: Increase exit and consolidation churn

Increase the exit and consolidation churn, let exits use consolidation churn and create a separate consolidation churn limit parameter.

Authors Francesco D'Amato (@fradamt), Anders Elowsson (@anderselowsson)
Created 2025-10-17
Discussion Link https://ethereum-magicians.org/t/eip-8061-increase-churn-limits/25991
Requires EIP-7521

Abstract

This EIP roughly doubles the consolidation churn, as well as quadrupling the exit churn and restoring its proportionality to total stake (though maintaining the existing cap on activations). Moreover, it routes exits through the consolidation queue when it is shorter than the exit queue (but not viceversa!), increasing the maximum exit throughput by another 75%. The choice of parameters balances maintaining a sufficiently long weak subjectivity period (~7 days, roughly halving the current period) with achieving two goals: allowing for faster consolidation of the validator set, in turn accelerating the timeline to faster finality, and relieving exit queue congestion, improving staking liquidity.

Motivation

EIP-7514 introduced an activation cap of 8 validators per epoch (now 256 ETH per epoch) to prevent overly rapid validator set growth. EIP-7251 extended this cap to exits, to make room for the newly introduced consolidation operations, without increasing the weak subjectivity period. However, the fixed cap prevents the exit churn limit from being proportional to total stake, which, all else being equal, leads to longer queues as stake grows. Moreover, the CHURN_LIMIT_QUOTIENT is set quite conservatively in the first place, requiring more than 3 months for 1/3 of the validator set to exit, a time which is now be more than doubled due to the cap. Recent episodes have stressed for more headroom to improve liquidity and staking user experience, as the exit queue has stretched beyond forty days as a consequence of the mass exit of Kiln validators. Long queues degrade user experience, and slow operator response to market or operational events. They also reduce the network’s ability to reconfigure stake more quickly after adverse events, for example to regain finality by having a large amount of stake exit (a double-edged sword, as preventing double finality is the reason these queues exist in the first place, as discussed in the security section). Finally, solo stakers are arguably the participants that suffer the most from a lack of liquidity today, as they do not have the ability to issue a liquid staking token or maintain liquidity reserves.

The conservative setting of the CHURN_LIMIT_QUOTIENT affects consolidations as well. Increasing the consolidation churn limit can shorten the path to a smaller validator set and, in turn, the path to a protocol with much faster finality. Under today’s parameters, even the best-case timelines are long: using only activations and exits, fully saturated around the clock, shrinking the roughly 32M ETH of 0x01 stake would take on the order of ~1.5 years; a fully saturated consolidation queue would still take ~1.3 years. Moreover, deposit capacity is also needed for new stake and is thus far from guaranteed to be available for consolidations, as evidenced by the recent inflow of > 1M ETH, fully occupying the queue for ~20 days.

The EIP proposes to address these issues by:

  • removing the cap on exits, restoring the proportionality of exit churn limit to total stake
  • increasing the churn limit on exits
  • introducing a separate consolidation churn limit, since there is no more “excess churn” from having an exit cap, and increase it compared to the current (implicitly defined) one. This also lets us more independently adjust it in the future, for example to increase it if we want to allow for faster consolidation of the validator set or decrease it when this process has already run its course.
  • allowing exits to use the consolidation queue whenever earliest_consolidation_epoch < earliest_exit_epoch, so that the consolidation churn is not wasted even when consolidations are not much in use. This lets us use the allocated churn more efficiently, greatly increasing the maximum exit throughput, while not harming the cause of shrinking the validator set size, since exits do that too. Moreover, it is already possible to route exits through the consolidation queue, due to a a loophole in the consolidation logic, which EIP-8071 proposes to fix. Democratizing this feature is useful and arguably even simpler than EIP-8071.

The EIP does not propose to lift the cap on the deposit churn, as part of the motivation for introducing it in EIP-7514 still holds today: though active validator set growth is mostly solved by EIP-7251, the validator array in the BeaconState (including inactive validators) is very large and still growing, and too rapid stake growth continues to be a concern as well.

Specification

The CHURN_LIMIT_QUOTIENT is halved, from 2**16 to 2**15, and fully dedicated to activations and exits. However, the cap on activations introduced in EIP-7514 is maintained via MAX_PER_EPOCH_ACTIVATION_CHURN_LIMIT, while exits are freed from this cap. Consolidations now have their own dedicated churn, determined by CONSOLIDATION_CHURN_LIMIT_QUOTIENT. This is set here to 2**16, so that consolidations are allocated half as much churn as activations and exits combined, and a third of the total churn. Finally, compute_weak_subjectivity_period is adjusted to account for the asymmetry between exit and activation churn: a unit of exit churn has twice the weak subjectivity effect ($\frac{4}{3}$) of a unit of activation churn $\frac{2}{3}$, and a unit of consolidation churn has an effect equivalent to the sum of the other two ($2$).

Configuration

MAX_PER_EPOCH_ACTIVATION_CHURN_LIMIT replaces the existing MAX_PER_EPOCH_ACTIVATION_EXIT_CHURN_LIMIT, also 256, as the cap now only applies to activations. We introduce the new CONSOLIDATION_CHURN_LIMIT_QUOTIENT and update the CHURN_LIMIT_QUOTIENT.

Name Value
CHURN_LIMIT_QUOTIENT_GLOAS uint64(2**15) (= 32,768)
CONSOLIDATION_CHURN_LIMIT_QUOTIENT uint64(2**16) (= 65,536)
MAX_PER_EPOCH_ACTIVATION_CHURN_LIMIT uint64(2**8) (=256)

Churn computations

Due to the intended asymmetry in activation and exit churn, we replace get_activation_exit_churn_limit with get_activation_churn_limit, capped at MAX_PER_EPOCH_ACTIVATION_CHURN_LIMIT, and get_exit_churn_limit, uncapped. get_consolidation_churn_limit uses the new CONSOLIDATION_CHURN_LIMIT_QUOTIENT, without either a minimum or a maximum value.

def get_activation_churn_limit(state: BeaconState) -> Gwei:
    """
    Per-epoch churn limit for activations, rounded to EFFECTIVE_BALANCE_INCREMENT.
    """
    churn = max(
        MIN_PER_EPOCH_CHURN_LIMIT_ELECTRA,
        get_total_active_balance(state) // CHURN_LIMIT_QUOTIENT_GLOAS
    )
    churn = churn - churn % EFFECTIVE_BALANCE_INCREMENT
    return min(MAX_PER_EPOCH_ACTIVATION_CHURN_LIMIT, churn)

def get_exit_churn_limit(state: BeaconState) -> Gwei:
    """
    Per-epoch churn limit for activations, rounded to EFFECTIVE_BALANCE_INCREMENT.
    """
    churn = max(
        MIN_PER_EPOCH_CHURN_LIMIT_ELECTRA,
        get_total_active_balance(state) // CHURN_LIMIT_QUOTIENT_GLOAS
    )
    return churn - churn % EFFECTIVE_BALANCE_INCREMENT

def get_consolidation_churn_limit(state: BeaconState) -> Gwei:
    """
    Per-epoch churn limit for consolidations (EIP-7521), rounded to
    EFFECTIVE_BALANCE_INCREMENT. Can also be used by exits.
    """
    churn = get_total_active_balance(state) // CONSOLIDATION_CHURN_LIMIT_QUOTIENT
    return churn - churn % EFFECTIVE_BALANCE_INCREMENT

In compute_weak_subjectivity_period we only replace delta = get_balance_churn_limit(state) with an explicit calculation taking into account the different weak subjectivity effect of each type of operation.

def compute_weak_subjectivity_period(state: BeaconState) -> uint64:
    """
    Returns the weak subjectivity period for the current ``state``.
    This computation takes into account the effect of validator set churn, 
    bounded by the three churn_limit functions used below.
    """
    t = get_total_active_balance(state)
    delta = (
        2 * get_activation_exit_churn_limit(state) // 3 # effect of exit churn
        + get_activation_churn_limit(state) // 3 # effect of activation churn
        + get_consolidation_churn_limit(state) # effect of consolidation churn
    )
    epochs_for_validator_set_churn = SAFETY_DECAY * t // (2 * delta * 100)
    return MIN_VALIDATOR_WITHDRAWABILITY_DELAY + epochs_for_validator_set_churn

Deposit processing

The only modification is replacing get_activation_exit_churn_limit with get_activation_churn_limit, maintaing the current cap on deposit churn respects, while removing the cap from exits. This reverts to the pre-Electra status quo, when activations were capped but exits were not.

def process_pending_deposits(state: BeaconState) -> None:
    next_epoch = Epoch(get_current_epoch(state) + 1)
    # [Modified in Gloas:EIP-8061]
    available_for_processing = state.deposit_balance_to_consume + get_activation_churn_limit(
        state
    )
    processed_amount = 0
    next_deposit_index = 0
    deposits_to_postpone = []
    is_churn_limit_reached = False
    finalized_slot = compute_start_slot_at_epoch(state.finalized_checkpoint.epoch)
    for deposit in state.pending_deposits:
        # Do not process deposit requests if Eth1 bridge deposits are not yet applied.
        if (
            # Is deposit request
            deposit.slot > GENESIS_SLOT
            and
            # There are pending Eth1 bridge deposits
            state.eth1_deposit_index < state.deposit_requests_start_index
        ):
            break
        # Check if deposit has been finalized, otherwise, stop processing.
        if deposit.slot > finalized_slot:
            break
        # Check if number of processed deposits has not reached the limit, otherwise, stop processing.
        if next_deposit_index >= MAX_PENDING_DEPOSITS_PER_EPOCH:
            break
        # Read validator state
        is_validator_exited = False
        is_validator_withdrawn = False
        validator_pubkeys = [v.pubkey for v in state.validators]
        if deposit.pubkey in validator_pubkeys:
            validator = state.validators[ValidatorIndex(validator_pubkeys.index(deposit.pubkey))]
            is_validator_exited = validator.exit_epoch < FAR_FUTURE_EPOCH
            is_validator_withdrawn = validator.withdrawable_epoch < next_epoch
        if is_validator_withdrawn:
            # Deposited balance will never become active. Increase balance but do not consume churn
            apply_pending_deposit(state, deposit)
        elif is_validator_exited:
            # Validator is exiting, postpone the deposit until after withdrawable epoch
            deposits_to_postpone.append(deposit)
        else:
            # Check if deposit fits in the churn, otherwise, do no more deposit processing in this epoch.
            is_churn_limit_reached = processed_amount + deposit.amount > available_for_processing
            if is_churn_limit_reached:
                break
            # Consume churn and apply deposit.
            processed_amount += deposit.amount
            apply_pending_deposit(state, deposit)
        # Regardless of how the deposit was handled, we move on in the queue.
        next_deposit_index += 1
    state.pending_deposits = state.pending_deposits[next_deposit_index:] + deposits_to_postpone
    # Accumulate churn only if the churn limit has been hit.
    if is_churn_limit_reached:
        state.deposit_balance_to_consume = available_for_processing - processed_amount
    else:
        state.deposit_balance_to_consume = Gwei(0)

Exit processing

We replace get_activation_exit_churn_limit with get_exit_churn_limit. Moreover, we route exits through the consolidation queue whenever state.earliest_exit_epoch > state.earliest_consolidation_epoch, by using compute_consolidation_epoch_and_update_churn. Note that the exit_balance passed to the latter is 2 * exit_balance // 3, because each unit of exit churn corresponds to 2/3 units of consolidation churn from a weak subjectivity perspective. This way, we keep the weak subjectivity impact of the consolidation queue the same regardless of whether it is used by consolidations or by exits.

def compute_exit_epoch_and_update_churn(state: BeaconState, exit_balance: Gwei) -> Epoch:
    if state.earliest_exit_epoch > state.earliest_consolidation_epoch:
        return compute_consolidation_epoch_and_update_churn(state, 2 * exit_balance // 3)

    earliest_exit_epoch = max(
        state.earliest_exit_epoch,
        compute_activation_exit_epoch(get_current_epoch(state))
    )
    per_epoch_churn = get_exit_churn_limit(state)
    # New epoch for exits.
    if state.earliest_exit_epoch < earliest_exit_epoch:
        exit_balance_to_consume = per_epoch_churn
    else:
        exit_balance_to_consume = state.exit_balance_to_consume

    # Exit doesn't fit in the current earliest epoch.
    if exit_balance > exit_balance_to_consume:
        balance_to_process = exit_balance - exit_balance_to_consume
        additional_epochs = (balance_to_process - 1) // per_epoch_churn + 1
        earliest_exit_epoch += additional_epochs
        exit_balance_to_consume += additional_epochs * per_epoch_churn

    # Consume the balance and update state variables.
    state.exit_balance_to_consume = exit_balance_to_consume - exit_balance
    state.earliest_exit_epoch = earliest_exit_epoch

    return state.earliest_exit_epoch

Rationale

  • Independent parameters: a separate churn consolidation is easy to independently tune, in particular adjusted upward if we want to speed up the consolidation process further, and later downward, when the primary wave of validator set consolidation has already happened and the consolidation operation becomes less crucial.
  • Scaling with stake: the exit churn regains proportionality to the total stake, and the consolidation churn maintains it.
  • Preserving the activation cap: the activation churn limit maintains the cap from EIP-7514
  • Efficient consolidation churn utilization: allowing exits to use the consolidation queue when it is shorter than the exit queue ensures that consolidation churn is not wasted when consolidations are not in high demand. With the current parameters, this increases the maximum exit throughput by 75% beyond the base increase, while not impeding the goal of shrinking the validator set size. The conversion factor of $2/3$ preserves the weak subjectivity impact regardless of whether the consolidation queue is used by consolidations or exits.
  • Balancing security and functionality: the exit churn limit is increased by ~4x compared to the current cap, and exactly 2x compared to previous uncapped version, while the consolidation churn limit is increased by ~2x. Moreover, the maximum exit throughput increases by a further 75% when we include routing through the consolidation queue, for a total increase of ~7x. Activations remain capped at the existing limit. As we see later in more detail, accounting for the asymmetric impact of exits and activations on safety degradation, this results in a decrease of the weak subjectivity period from ~15.7 days to ~7 days (see detailed calculations below), or ~6 days if we were to later remove the activation cap, in either case still on the order of a week. Moreover, were consolidations to be removed later, the weak subjectivity period would go up to ~11 days, or ~8.4 days without the activation cap.

Backwards Compatibility

This EIP introduces a backwards-incompatible change to the consensus rules and MUST be activated as part of a scheduled network upgrade.

Test Cases

TODO

Security Considerations

Weak subjectivity period

Let MIN_VALIDATOR_WITHDRAWABILITY_DELAY = 256 epochs, and let $S$ denote the total stake, $E$ the exit churn per epoch, $A$ the activation churn per epoch, and $C$ the consolidation churn per epoch. Each unit of exit churn contributes to a safety degradation (measured in ETH, as the churn) of $\frac{4}{3}$, whereas the safety degradation from activations is only $\frac{2}{3}$ per unit. Finally, it is $2$ per unit for consolidations, as a consolidation is the equivalent of an exit and an activation.

The formula to compute the weak subjectivity period (in epochs) for a 10% safety decay target (exactly corresponding to compute_weak_subjectivity_period) then is:

$\text{WS}_{\text{epochs}} = 256 + \frac{0.1 \cdot S}{\frac{4}{3} \cdot E + \frac{2}{3} \cdot A + 2 \cdot C}$

The churn limits of the current protocol, assuming a total stake $S = 36M$ ETH (approximately the stake at the time of writing) are:

  • $A = E = \min(256, S/2^{16}) = 256$ ETH (capped)
  • $C = S/2^{16} - A \approx 293$ ETH

The weak subjectivity period is then:

$\text{WS}_{\text{epochs}} \approx 3533$

$\Rightarrow\ \textbf{WS} \approx \mathbf{15.7\ \text{days}}$

In days, it is $\text{WS}_{\text{epochs}} / 225$.

Under this EIP, and assuming a total stake $S = 36M$ ETH:

  • $E = S/2^{15} \approx 1098$ ETH
  • $A = \min(256, S/2^{15}) = 256$ ETH (capped)
  • $C = S/2^{16} \approx 549$ ETH

The weak subjectivity period is then:

$\text{WS}_{\text{epochs}} \approx 1573$

$\Rightarrow\ \textbf{WS} \approx \mathbf{7.0\ \text{days}}$

Other possible future scenarios are:

  • Activation cap removed: $\textbf{WS} \approx \mathbf{6.0\ \text{days}}$ ($\text{WS}_{\text{epochs}} \approx 1348$)
  • Consolidations disabled: $\textbf{WS} \approx \mathbf{10.9\ \text{days}}$ ($\text{WS}_{\text{epochs}} \approx 2457$)
  • Consolidations disabled and activation cap removed: $\textbf{WS} \approx \mathbf{8.4\ \text{days}}$ ($\text{WS}_{\text{epochs}} \approx 1894$)

Note that removing the activation cap only reduces the weak subjectivity period by one day, and leaves it on the order of a week. The current parameters might then also be considered acceptable in a future where it is decided to remove the activation cap.

Copyright and related rights waived via CC0.

Citation

Please cite this document as:

Francesco D'Amato (@fradamt), Anders Elowsson (@anderselowsson), "EIP-8061: Increase exit and consolidation churn [DRAFT]," Ethereum Improvement Proposals, no. 8061, October 2025. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-8061.