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
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
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
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
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
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)
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)
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, )
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
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 ]
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
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, )
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
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
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
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