def test_initiate_validator_exit(genesis_state, is_already_exited, config): state = genesis_state index = random.choice(range(len(state.validators))) validator = state.validators[index] assert not validator.slashed assert validator.activation_epoch == config.GENESIS_EPOCH assert validator.activation_eligibility_epoch == config.GENESIS_EPOCH assert validator.exit_epoch == FAR_FUTURE_EPOCH assert validator.withdrawable_epoch == FAR_FUTURE_EPOCH if is_already_exited: churn_limit = get_validator_churn_limit(state, config) exit_queue_epoch = _compute_exit_queue_epoch(state, churn_limit, config) validator = validator.copy( exit_epoch=exit_queue_epoch, withdrawable_epoch=exit_queue_epoch + config.MIN_VALIDATOR_WITHDRAWABILITY_DELAY, ) exited_validator = initiate_exit_for_validator(validator, state, config) if is_already_exited: assert exited_validator == validator else: churn_limit = get_validator_churn_limit(state, config) exit_queue_epoch = _compute_exit_queue_epoch(state, churn_limit, config) assert exited_validator.exit_epoch == exit_queue_epoch assert exited_validator.withdrawable_epoch == ( exit_queue_epoch + config.MIN_VALIDATOR_WITHDRAWABILITY_DELAY)
def process_registry_updates(state: BeaconState, config: Eth2Config) -> BeaconState: new_state = state for index in range(len(state.validators)): new_state = _process_activation_eligibility_or_ejections( new_state, index, config) # Queue validators eligible for activation and not yet dequeued for activation activation_queue = sorted( (index for index, validator in enumerate(new_state.validators) if validator.is_eligible_for_activation(state)), # Order by the sequence of activation_eligibility_epoch setting and then index key=lambda index: ( new_state.validators[index].activation_eligibility_epoch, index, ), ) # Dequeued validators for activation up to churn limit for index in activation_queue[:get_validator_churn_limit(state, config)]: new_state = new_state.transform( ("validators", index), _update_validator_activation_epoch(state, config)) return new_state
def process_registry_updates(state: BeaconState, config: Eth2Config) -> BeaconState: new_validators = tuple( _process_activation_eligibility_or_ejections(state, validator, config) for validator in state.validators ) activation_exit_epoch = compute_activation_exit_epoch( state.finalized_checkpoint.epoch, config.ACTIVATION_EXIT_DELAY ) activation_queue = sorted( ( index for index, validator in enumerate(new_validators) if validator.activation_eligibility_epoch != FAR_FUTURE_EPOCH and validator.activation_epoch >= activation_exit_epoch ), key=lambda index: new_validators[index].activation_eligibility_epoch, ) for index in activation_queue[: get_validator_churn_limit(state, config)]: new_validators = update_tuple_item_with_fn( new_validators, index, _update_validator_activation_epoch(state, config) ) return state.copy(validators=new_validators)
def initiate_exit_for_validator(validator: Validator, state: BeaconState, config: Eth2Config) -> Validator: """ Performs the mutations to ``validator`` used to initiate an exit. More convenient given our immutability patterns compared to ``initiate_validator_exit``. """ if validator.exit_epoch != FAR_FUTURE_EPOCH: return validator churn_limit = get_validator_churn_limit(state, config) exit_queue_epoch = _compute_exit_queue_epoch(state, churn_limit, config) return validator.copy( exit_epoch=exit_queue_epoch, withdrawable_epoch=Epoch(exit_queue_epoch + config.MIN_VALIDATOR_WITHDRAWABILITY_DELAY), )
def process_registry_updates(state: BeaconState, config: Eth2Config) -> BeaconState: new_validators = state.validators for index, validator in enumerate(state.validators): new_validator = _process_activation_eligibility_or_ejections( state, validator, config) new_validators = new_validators.set(index, new_validator) activation_exit_epoch = compute_activation_exit_epoch( state.finalized_checkpoint.epoch, config.MAX_SEED_LOOKAHEAD) activation_queue = sorted( (index for index, validator in enumerate(new_validators) if validator.activation_eligibility_epoch != FAR_FUTURE_EPOCH and validator.activation_epoch >= activation_exit_epoch), key=lambda index: new_validators[index].activation_eligibility_epoch, ) for index in activation_queue[:get_validator_churn_limit(state, config)]: new_validators = new_validators.transform( (index, ), _update_validator_activation_epoch(state, config)) return state.set("validators", new_validators)
def test_get_validator_churn_limit(genesis_state, expected_churn_limit, config): assert get_validator_churn_limit(genesis_state, config) == expected_churn_limit