예제 #1
0
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)
예제 #2
0
def _update_validator_activation_epoch(state: BeaconState, config: Eth2Config,
                                       validator: Validator) -> Validator:
    return validator.set(
        "activation_epoch",
        compute_activation_exit_epoch(
            state.current_epoch(config.SLOTS_PER_EPOCH),
            config.MAX_SEED_LOOKAHEAD),
    )
예제 #3
0
def _update_validator_activation_epoch(state: BeaconState, config: Eth2Config,
                                       validator: Validator) -> Validator:
    if validator.activation_epoch == FAR_FUTURE_EPOCH:
        return validator.copy(activation_epoch=compute_activation_exit_epoch(
            state.current_epoch(config.SLOTS_PER_EPOCH),
            config.ACTIVATION_EXIT_DELAY,
        ))
    else:
        return validator
예제 #4
0
def _update_validator_activation_epoch(
    state: BeaconState, config: Eth2Config, validator: Validator
) -> Validator:
    if validator.activation_epoch == FAR_FUTURE_EPOCH:
        return validator.copy(
            activation_epoch=compute_activation_exit_epoch(
                state.current_epoch(config.SLOTS_PER_EPOCH), config.MAX_SEED_LOOKAHEAD
            )
        )
    else:
        return validator
예제 #5
0
def _compute_exit_queue_epoch(state: BeaconState, churn_limit: int,
                              config: Eth2Config) -> Epoch:
    slots_per_epoch = config.SLOTS_PER_EPOCH

    exit_epochs = tuple(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(
        state.current_epoch(slots_per_epoch), config.MAX_SEED_LOOKAHEAD), ))
    exit_queue_churn = len(
        tuple(v for v in state.validators if v.exit_epoch == exit_queue_epoch))
    if exit_queue_churn >= churn_limit:
        exit_queue_epoch += 1
    return Epoch(exit_queue_epoch)
예제 #6
0
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)
예제 #7
0
def test_compute_exit_queue_epoch(
    genesis_state,
    is_delayed_exit_epoch_the_maximum_exit_queue_epoch,
    is_churn_limit_met,
    config,
):
    state = genesis_state
    for index in random.sample(range(len(state.validators)),
                               len(state.validators) // 4):
        some_future_epoch = config.GENESIS_EPOCH + random.randrange(1, 2**32)
        state = state.update_validator_with_fn(
            index,
            lambda validator, *_: validator.copy(exit_epoch=some_future_epoch))

    if is_delayed_exit_epoch_the_maximum_exit_queue_epoch:
        expected_candidate_exit_queue_epoch = compute_activation_exit_epoch(
            state.current_epoch(config.SLOTS_PER_EPOCH),
            config.MAX_SEED_LOOKAHEAD)
        for index, validator in enumerate(state.validators):
            if validator.exit_epoch == FAR_FUTURE_EPOCH:
                continue
            some_prior_epoch = random.randrange(
                config.GENESIS_EPOCH, expected_candidate_exit_queue_epoch)
            state = state.update_validator_with_fn(
                index, lambda validator, *_: validator.copy(exit_epoch=
                                                            some_prior_epoch))
            validator = state.validators[index]
            assert expected_candidate_exit_queue_epoch >= validator.exit_epoch
    else:
        expected_candidate_exit_queue_epoch = -1
        for validator in state.validators:
            if validator.exit_epoch == FAR_FUTURE_EPOCH:
                continue
            if validator.exit_epoch > expected_candidate_exit_queue_epoch:
                expected_candidate_exit_queue_epoch = validator.exit_epoch
        assert expected_candidate_exit_queue_epoch >= config.GENESIS_EPOCH

    if is_churn_limit_met:
        churn_limit = 0
        expected_exit_queue_epoch = expected_candidate_exit_queue_epoch + 1
    else:
        # add more validators to the queued epoch to make the test less trivial
        # with the setup so far, it is likely that the queue in the target epoch is size 1.
        queued_validators = {
            index: validator
            for index, validator in state.validators
            if validator.exit_epoch == expected_candidate_exit_queue_epoch
        }
        additional_queued_validator_count = random.randrange(
            len(queued_validators), len(state.validators))
        unqueued_validators = tuple(v for v in state.validators
                                    if v.exit_epoch == FAR_FUTURE_EPOCH)
        for index in random.sample(range(len(unqueued_validators)),
                                   additional_queued_validator_count):
            state = state.update_validator_with_fn(
                index,
                lambda validator, *_: validator.copy(
                    exit_epoch=expected_candidate_exit_queue_epoch),
            )

        all_queued_validators = tuple(
            v for v in state.validators
            if v.exit_epoch == expected_candidate_exit_queue_epoch)
        churn_limit = len(all_queued_validators) + 1

        expected_exit_queue_epoch = expected_candidate_exit_queue_epoch

    assert (_compute_exit_queue_epoch(state, churn_limit,
                                      config) == expected_exit_queue_epoch)
def test_compute_activation_exit_epoch(max_seed_lookahead):
    epoch = random.randrange(0, FAR_FUTURE_EPOCH)
    entry_exit_effect_epoch = compute_activation_exit_epoch(
        epoch, max_seed_lookahead)
    assert entry_exit_effect_epoch == (epoch + 1 + max_seed_lookahead)
예제 #9
0
def test_compute_activation_exit_epoch(activation_exit_delay):
    epoch = random.randrange(0, FAR_FUTURE_EPOCH)
    entry_exit_effect_epoch = compute_activation_exit_epoch(
        epoch, activation_exit_delay)
    assert entry_exit_effect_epoch == (epoch + 1 + activation_exit_delay)