def test_add_pending_validator(monkeypatch, sample_beacon_state_params,
                               sample_validator_record_params,
                               validator_registry_len,
                               min_empty_validator_index_result,
                               expected_index):
    from eth.beacon import deposit_helpers

    def mock_get_min_empty_validator_index(validators, validator_balances,
                                           current_slot,
                                           zero_balance_validator_ttl):
        if min_empty_validator_index_result is None:
            raise MinEmptyValidatorIndexNotFound()
        else:
            return min_empty_validator_index_result

    monkeypatch.setattr(deposit_helpers, 'get_min_empty_validator_index',
                        mock_get_min_empty_validator_index)

    state = BeaconState(**sample_beacon_state_params).copy(
        validator_registry=[
            ValidatorRecord(**sample_validator_record_params)
            for _ in range(validator_registry_len)
        ],
        validator_balances=[100 for _ in range(validator_registry_len)],
    )
    validator = ValidatorRecord(**sample_validator_record_params)
    deposit = 5566
    state, index = add_pending_validator(
        state,
        validator,
        deposit,
        zero_balance_validator_ttl=0,  # it's for `get_min_empty_validator_index`
    )
    assert index == expected_index
    assert state.validator_registry[index] == validator
def test_is_active(sample_validator_record_params, activation_slot, exit_slot,
                   slot, expected):
    validator_record_params = {
        **sample_validator_record_params,
        'activation_slot': activation_slot,
        'exit_slot': exit_slot,
    }
    validator = ValidatorRecord(**validator_record_params)
    assert validator.is_active(slot) == expected
def test_get_min_empty_validator_index(sample_validator_record_params, balance,
                                       latest_status_change_slot,
                                       zero_balance_validator_ttl,
                                       current_slot, max_deposit, expected):
    validators = [
        ValidatorRecord(**sample_validator_record_params).copy(
            latest_status_change_slot=latest_status_change_slot, )
        for _ in range(10)
    ]
    validator_balances = [balance for _ in range(10)]
    if isinstance(expected, Exception):
        with pytest.raises(MinEmptyValidatorIndexNotFound):
            get_min_empty_validator_index(
                validators=validators,
                validator_balances=validator_balances,
                current_slot=current_slot,
                zero_balance_validator_ttl=zero_balance_validator_ttl,
            )
    else:
        result = get_min_empty_validator_index(
            validators=validators,
            validator_balances=validator_balances,
            current_slot=current_slot,
            zero_balance_validator_ttl=zero_balance_validator_ttl,
        )
        assert result == expected
示例#4
0
def test_get_active_validator_indices(sample_validator_record_params):
    # 3 validators are ACTIVE
    validators = [
        ValidatorRecord(
            **sample_validator_record_params,
        ).copy(
            status=ValidatorStatusCode.ACTIVE,
        )
        for i in range(3)
    ]
    active_validator_indices = get_active_validator_indices(validators)
    assert len(active_validator_indices) == 3

    # Make one validator becomes ACTIVE_PENDING_EXIT.
    validators[0] = validators[0].copy(
        status=ValidatorStatusCode.ACTIVE_PENDING_EXIT,
    )
    active_validator_indices = get_active_validator_indices(validators)
    assert len(active_validator_indices) == 3

    # Make one validator becomes EXITED_WITHOUT_PENALTY.
    validators[0] = validators[0].copy(
        status=ValidatorStatusCode.EXITED_WITHOUT_PENALTY,
    )
    active_validator_indices = get_active_validator_indices(validators)
    assert len(active_validator_indices) == 2
示例#5
0
def process_deposit(*,
                    state: BeaconState,
                    pubkey: BLSPubkey,
                    deposit: Gwei,
                    proof_of_possession: BLSSignature,
                    withdrawal_credentials: Hash32,
                    randao_commitment: Hash32,
                    custody_commitment: Hash32,
                    zero_balance_validator_ttl: int) -> Tuple[BeaconState, ValidatorIndex]:
    """
    Process a deposit from Ethereum 1.0.
    """
    validate_proof_of_possession(
        state,
        pubkey,
        proof_of_possession,
        withdrawal_credentials,
        randao_commitment,
        custody_commitment,
    )

    validator_pubkeys = tuple(v.pubkey for v in state.validator_registry)
    if pubkey not in validator_pubkeys:
        validator = ValidatorRecord.get_pending_validator(
            pubkey=pubkey,
            withdrawal_credentials=withdrawal_credentials,
            randao_commitment=randao_commitment,
            latest_status_change_slot=state.slot,
            custody_commitment=custody_commitment,
        )

        state, index = add_pending_validator(
            state,
            validator,
            deposit,
            zero_balance_validator_ttl,
        )
    else:
        # Top-up - increase balance by deposit
        index = ValidatorIndex(validator_pubkeys.index(pubkey))
        validator = state.validator_registry[index]

        if validator.withdrawal_credentials != withdrawal_credentials:
            raise ValidationError(
                "`withdrawal_credentials` are incorrect:\n"
                "\texpected: %s, found: %s" % (
                    validator.withdrawal_credentials,
                    validator.withdrawal_credentials,
                )
            )

        # Update validator's balance and state
        state = state.update_validator(
            validator_index=index,
            validator=validator,
            balance=state.validator_balances[index] + deposit,
        )

    return state, index
示例#6
0
def test_is_active(sample_validator_record_params,
                   status,
                   expected):
    validator_record_params = {
        **sample_validator_record_params,
        'status': status
    }
    validator = ValidatorRecord(**validator_record_params)
    assert validator.is_active == expected
示例#7
0
def mock_validator_record(pubkey):
    return ValidatorRecord(
        pubkey=pubkey,
        withdrawal_credentials=b'\x44' * 32,
        randao_commitment=b'\x55' * 32,
        randao_layers=0,
        status=ValidatorStatusCode.ACTIVE,
        latest_status_change_slot=0,
        exit_count=0,
    )
def test_add_pending_validator(sample_beacon_state_params,
                               sample_validator_record_params):

    validator_registry_len = 2
    state = BeaconState(**sample_beacon_state_params).copy(
        validator_registry=[
            ValidatorRecord(**sample_validator_record_params)
            for _ in range(validator_registry_len)
        ],
        validator_balances=(100, ) * validator_registry_len,
    )
    validator = ValidatorRecord(**sample_validator_record_params)
    amount = 5566
    state = add_pending_validator(
        state,
        validator,
        amount,
    )

    assert state.validator_registry[-1] == validator
示例#9
0
def genesis_validators(init_validator_keys, init_randao, max_deposit):
    return tuple(
        ValidatorRecord(
            pubkey=pub,
            withdrawal_credentials=ZERO_HASH32,
            randao_commitment=init_randao,
            randao_layers=0,
            status=ValidatorStatusCode.ACTIVE,
            latest_status_change_slot=0,
            exit_count=0,
        ) for pub in init_validator_keys)
示例#10
0
def mock_validator_record(pubkey,
                          deposit_size,
                          default_end_dynasty,
                          start_dynasty=0):
    return ValidatorRecord(pubkey=pubkey,
                           withdrawal_shard=0,
                           withdrawal_address=pubkey.to_bytes(32, 'big')[-20:],
                           randao_commitment=b'\x55' * 32,
                           balance=deposit_size,
                           start_dynasty=start_dynasty,
                           end_dynasty=default_end_dynasty)
示例#11
0
def mock_validator_record(pubkey, max_deposit):
    return ValidatorRecord(
        pubkey=pubkey,
        withdrawal_credentials=b'\x44' * 32,
        randao_commitment=b'\x55' * 32,
        randao_skips=0,
        balance=max_deposit,
        status=ValidatorStatusCode.ACTIVE,
        latest_status_change_slot=0,
        exit_count=0,
    )
示例#12
0
def process_deposit(*, state: BeaconState, pubkey: BLSPubkey, amount: Gwei,
                    proof_of_possession: BLSSignature,
                    withdrawal_credentials: Hash32, randao_commitment: Hash32,
                    custody_commitment: Hash32) -> BeaconState:
    """
    Process a deposit from Ethereum 1.0.
    """
    validate_proof_of_possession(
        state=state,
        pubkey=pubkey,
        proof_of_possession=proof_of_possession,
        withdrawal_credentials=withdrawal_credentials,
        randao_commitment=randao_commitment,
        custody_commitment=custody_commitment,
    )

    validator_pubkeys = tuple(v.pubkey for v in state.validator_registry)
    if pubkey not in validator_pubkeys:
        validator = ValidatorRecord.create_pending_validator(
            pubkey=pubkey,
            withdrawal_credentials=withdrawal_credentials,
            randao_commitment=randao_commitment,
            custody_commitment=custody_commitment,
        )

        # Note: In phase 2 registry indices that has been withdrawn for a long time
        # will be recycled.
        state = add_pending_validator(
            state,
            validator,
            amount,
        )
    else:
        # Top-up - increase balance by deposit
        index = ValidatorIndex(validator_pubkeys.index(pubkey))
        validator = state.validator_registry[index]

        if validator.withdrawal_credentials != withdrawal_credentials:
            raise ValidationError("`withdrawal_credentials` are incorrect:\n"
                                  "\texpected: %s, found: %s" % (
                                      validator.withdrawal_credentials,
                                      validator.withdrawal_credentials,
                                  ))

        # Update validator's balance and state
        state = state.update_validator_balance(
            validator_index=index,
            balance=state.validator_balances[index] + amount,
        )

    return state
示例#13
0
def genesis_validators(init_validator_keys, init_randao, deposit_size,
                       default_end_dynasty):
    current_dynasty = 1
    return [
        ValidatorRecord(pubkey=pub,
                        withdrawal_shard=0,
                        withdrawal_address=blake(pub.to_bytes(32,
                                                              'big'))[-20:],
                        randao_commitment=init_randao,
                        balance=deposit_size,
                        start_dynasty=current_dynasty,
                        end_dynasty=default_end_dynasty)
        for pub in init_validator_keys
    ]
示例#14
0
def test_get_active_validator_indices(sample_validator_record_params):
    current_slot = 1
    # 3 validators are ACTIVE
    validators = [
        ValidatorRecord(**sample_validator_record_params, ).copy(
            activation_slot=0,
            exit_slot=FAR_FUTURE_SLOT,
        ) for i in range(3)
    ]
    active_validator_indices = get_active_validator_indices(
        validators, current_slot)
    assert len(active_validator_indices) == 3

    validators[0] = validators[0].copy(
        activation_slot=current_slot + 1,  # activation_slot > current_slot
    )
    active_validator_indices = get_active_validator_indices(
        validators, current_slot)
    assert len(active_validator_indices) == 2
示例#15
0
def mock_validator_record(pubkey,
                          withdrawal_credentials=ZERO_HASH32,
                          randao_commitment=ZERO_HASH32,
                          status_flags=0,
                          is_active=True):
    return ValidatorRecord(
        pubkey=pubkey,
        withdrawal_credentials=withdrawal_credentials,
        randao_commitment=randao_commitment,
        randao_layers=0,
        activation_slot=0 if is_active else FAR_FUTURE_SLOT,
        exit_slot=FAR_FUTURE_SLOT,
        withdrawal_slot=FAR_FUTURE_SLOT,
        penalized_slot=FAR_FUTURE_SLOT,
        exit_count=0,
        status_flags=status_flags,
        custody_commitment=b'\x55' * 32,
        latest_custody_reseed_slot=0,
        penultimate_custody_reseed_slot=0,
    )
示例#16
0
def test_get_pending_validator():
    pubkey = 123
    withdrawal_credentials = b'\x11' * 32
    randao_commitment = b'\x22' * 32
    latest_status_change_slot = 10

    validator = ValidatorRecord.get_pending_validator(
        pubkey=pubkey,
        withdrawal_credentials=withdrawal_credentials,
        randao_commitment=randao_commitment,
        latest_status_change_slot=latest_status_change_slot,
    )

    assert validator.pubkey == pubkey
    assert validator.withdrawal_credentials == withdrawal_credentials
    assert validator.randao_commitment == randao_commitment
    assert validator.latest_status_change_slot == latest_status_change_slot

    assert validator.status == ValidatorStatusCode.PENDING_ACTIVATION
    assert validator.randao_layers == 0
    assert validator.exit_count == 0
示例#17
0
def test_create_pending_validator():
    pubkey = 123
    withdrawal_credentials = b'\x11' * 32
    randao_commitment = b'\x22' * 32
    custody_commitment = b'\x33' * 32

    validator = ValidatorRecord.create_pending_validator(
        pubkey=pubkey,
        withdrawal_credentials=withdrawal_credentials,
        randao_commitment=randao_commitment,
        custody_commitment=custody_commitment,
    )

    assert validator.pubkey == pubkey
    assert validator.withdrawal_credentials == withdrawal_credentials
    assert validator.randao_commitment == randao_commitment
    assert validator.randao_layers == 0
    assert validator.activation_slot == FAR_FUTURE_SLOT
    assert validator.exit_slot == FAR_FUTURE_SLOT
    assert validator.withdrawal_slot == FAR_FUTURE_SLOT
    assert validator.penalized_slot == FAR_FUTURE_SLOT
    assert validator.exit_count == 0
示例#18
0
def test_defaults(sample_validator_record_params):
    validator = ValidatorRecord(**sample_validator_record_params)
    assert validator.pubkey == sample_validator_record_params['pubkey']
    assert validator.withdrawal_credentials == sample_validator_record_params['withdrawal_credentials']  # noqa: E501
示例#19
0
def test_get_effective_balance(balance, max_deposit, expected,
                               sample_validator_record_params):
    validator = ValidatorRecord(**sample_validator_record_params).copy(
        balance=balance, )
    result = get_effective_balance(validator, max_deposit)
    assert result == expected