# 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`](https://github.com/ethereum/consensus-specs/blob/dev/specs/_features/eip6110/beacon-chain.md) (in-protocol deposits).
`CHURN_LIMIT_QUOTIENT` dictates the `validator_churn_limit` which is constant through an epoch variable only to active validator count.
```python
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](https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#get_validator_churn_limit))
## Inflow
Higher `CHURN_LIMIT_QUOTIENT` results in less validators dequeued from that epoch's `activation_epoch`.
```python
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
```python
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.
![](https://i.imgur.com/ngbiw2n.png)
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
:-------------------------:|:-------------------------:
![](https://i.imgur.com/WY5AkuY.png) | ![](https://i.imgur.com/MJmnIFR.png)
![](https://i.imgur.com/pOzFM09.png) | ![](https://i.imgur.com/6EFUzTk.png)