Try   HackMD

Increase CHURN_LIMIT_QUOTIENT

Rationale

Current CHURN_LIMIT_QUOTIENT in Gnosis is low such that the network's validator set can change significantly in short periods of time posing unnecessary risks to the network. The original value was chosen without a great deal of care to facilitate staker onboarding UX. Even that argument will no longer apply with eip6110 (in-protocol deposits).

CHURN_LIMIT_QUOTIENT dictates the validator_churn_limit which is constant through an epoch variable only to active validator count.

def get_validator_churn_limit(state: BeaconState) -> uint64:
    """
    Return the validator churn limit for the current epoch.
    """
    active_validator_indices = get_active_validator_indices(state, get_current_epoch(state))
    return max(MIN_PER_EPOCH_CHURN_LIMIT, uint64(len(active_validator_indices)) // CHURN_LIMIT_QUOTIENT)

(specs/phase0/beacon-chain.md)

Inflow

Higher CHURN_LIMIT_QUOTIENT results in less validators dequeued from that epoch's activation_epoch.

def process_registry_updates(state: BeaconState) -> None:
    ...
    # Dequeued validators for activation up to churn limit
    for index in activation_queue[:get_validator_churn_limit(state)]:
        validator = state.validators[index]
        validator.activation_epoch = compute_activation_exit_epoch(get_current_epoch(state))

Outflow

The result of computing the validator churn limit is persisted in the state for outflows. Below initiate_validator_exit

  • Compute the highest registered exit_epoch, and count how many validators will exit at the epoch
  • If that count exceeds churn limit, schedule to exit validator at max epoch + 1. By definition that will not have any validators scheduled to exit on it
def initiate_validator_exit(state: BeaconState, index: ValidatorIndex) -> None:
    ...
    # Compute exit queue epoch
    exit_epochs = [v.exit_epoch for v in state.validators if v.exit_epoch != FAR_FUTURE_EPOCH]
    exit_queue_epoch = max(exit_epochs + [compute_activation_exit_epoch(get_current_epoch(state))])
    exit_queue_churn = len([v for v in state.validators if v.exit_epoch == exit_queue_epoch])
    if exit_queue_churn >= get_validator_churn_limit(state):
        exit_queue_epoch += Epoch(1)

    # Set validator exit epoch and withdrawable epoch
    validator.exit_epoch = exit_queue_epoch
    validator.withdrawable_epoch = Epoch(validator.exit_epoch + MIN_VALIDATOR_WITHDRAWABILITY_DELAY)

Irrespective of the current status of the exit churn, the chrun decrease is well handled with the spec as is.

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

Implementations must make sure to invalidate any exit churn cache and recompute that fork boundary.

New CHURN_LIMIT_QUOTIENT

TBD pending research. Current tentative value Ethereum's 65536

Max churn simulation

Consensus layer config differences to Ethereum

Config value Ethereum Gnosis
CHURN_LIMIT_QUOTIENT 65536 4096
  • CHURN_LIMIT_QUOTIENT: The churn to enter and exit the validator set is greater. For 100_000 validators, 100000 / 4096 = 24 validators can activate and exit per epoch.
Churn out Churn in