def test_is_active(sample_validator_record_params, activation_epoch, exit_epoch, epoch, expected): validator_record_params = { **sample_validator_record_params, 'activation_epoch': activation_epoch, 'exit_epoch': exit_epoch, } validator = ValidatorRecord(**validator_record_params) assert validator.is_active(epoch) == expected
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_active_validator_indices(sample_validator_record_params): current_epoch = 1 # 3 validators are ACTIVE validators = [ ValidatorRecord(**sample_validator_record_params, ).copy( activation_epoch=0, exit_epoch=FAR_FUTURE_EPOCH, ) for i in range(3) ] active_validator_indices = get_active_validator_indices( validators, current_epoch) assert len(active_validator_indices) == 3 validators[0] = validators[0].copy( activation_epoch=current_epoch + 1, # activation_epoch > current_epoch ) active_validator_indices = get_active_validator_indices( validators, current_epoch) assert len(active_validator_indices) == 2 validators[1] = validators[1].copy( exit_epoch=current_epoch, # current_epoch == exit_epoch ) active_validator_indices = get_active_validator_indices( validators, current_epoch) assert len(active_validator_indices) == 1
def process_deposit(state: BeaconState, deposit: Deposit, slots_per_epoch: int, deposit_contract_tree_depth: int) -> BeaconState: """ Process a deposit from Ethereum 1.0. """ validate_deposit(state, deposit, deposit_contract_tree_depth) # Increment the next deposit index we are expecting. Note that this # needs to be done here because while the deposit contract will never # create an invalid Merkle branch, it may admit an invalid deposit # object, and we need to be able to skip over it state = state.copy(deposit_index=state.deposit_index + 1, ) validator_pubkeys = tuple(v.pubkey for v in state.validator_registry) deposit_input = deposit.deposit_data.deposit_input pubkey = deposit_input.pubkey amount = deposit.deposit_data.amount withdrawal_credentials = deposit_input.withdrawal_credentials if pubkey not in validator_pubkeys: # Verify the proof of possession proof_is_valid = bls.verify( pubkey=pubkey, message_hash=deposit_input.signed_root, signature=deposit_input.proof_of_possession, domain=get_domain( state.fork, state.current_epoch(slots_per_epoch), SignatureDomain.DOMAIN_DEPOSIT, ), ) if not proof_is_valid: return state validator = ValidatorRecord.create_pending_validator( pubkey=pubkey, withdrawal_credentials=withdrawal_credentials, ) # 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] # Update validator's balance and state state = state.update_validator_balance( validator_index=index, balance=state.validator_balances[index] + amount, ) return state
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 process_deposit(*, state: BeaconState, pubkey: BLSPubkey, amount: Gwei, proof_of_possession: BLSSignature, withdrawal_credentials: Hash32, randao_commitment: Hash32, custody_commitment: Hash32, epoch_length: int) -> 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, epoch_length=epoch_length, ) 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 mock_validator_record(pubkey, config: Eth2Config, withdrawal_credentials=ZERO_HASH32, is_active=True): return ValidatorRecord( pubkey=pubkey, withdrawal_credentials=withdrawal_credentials, activation_epoch=config.GENESIS_EPOCH if is_active else FAR_FUTURE_EPOCH, exit_epoch=FAR_FUTURE_EPOCH, withdrawable_epoch=FAR_FUTURE_EPOCH, initiated_exit=False, slashed=False, )
def test_create_pending_validator(): pubkey = 123 withdrawal_credentials = b'\x11' * 32 validator = ValidatorRecord.create_pending_validator( pubkey=pubkey, withdrawal_credentials=withdrawal_credentials, ) assert validator.pubkey == pubkey assert validator.withdrawal_credentials == withdrawal_credentials assert validator.activation_epoch == FAR_FUTURE_EPOCH assert validator.exit_epoch == FAR_FUTURE_EPOCH assert validator.initiated_exit is False assert validator.slashed is False
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, activation_epoch=SERENITY_CONFIG.GENESIS_EPOCH if is_active else FAR_FUTURE_EPOCH, exit_epoch=FAR_FUTURE_EPOCH, withdrawal_epoch=FAR_FUTURE_EPOCH, penalized_epoch=FAR_FUTURE_EPOCH, status_flags=status_flags, )
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 test_create_pending_validator(): pubkey = 123 withdrawal_credentials = b'\x11' * 32 randao_commitment = b'\x22' * 32 validator = ValidatorRecord.create_pending_validator( pubkey=pubkey, withdrawal_credentials=withdrawal_credentials, randao_commitment=randao_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_epoch == FAR_FUTURE_EPOCH assert validator.exit_epoch == FAR_FUTURE_EPOCH assert validator.withdrawal_epoch == FAR_FUTURE_EPOCH assert validator.penalized_epoch == FAR_FUTURE_EPOCH
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_epoch=SERENITY_CONFIG.GENESIS_EPOCH if is_active else FAR_FUTURE_EPOCH, exit_epoch=FAR_FUTURE_EPOCH, withdrawal_epoch=FAR_FUTURE_EPOCH, penalized_epoch=FAR_FUTURE_EPOCH, exit_count=0, status_flags=status_flags, custody_commitment=b'\x55' * 32, latest_custody_reseed_slot=0, penultimate_custody_reseed_slot=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, )
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_update_validator_registry(n, n_validators_state, config, slots_per_epoch): validator_registry = list(n_validators_state.validator_registry) activating_index = n exiting_index = 0 activating_validator = ValidatorRecord.create_pending_validator( pubkey=b'\x10' * 48, withdrawal_credentials=b'\x11' * 32, ) exiting_validator = n_validators_state.validator_registry[exiting_index].copy( exit_epoch=FAR_FUTURE_EPOCH, initiated_exit=True, ) validator_registry[exiting_index] = exiting_validator validator_registry.append(activating_validator) state = n_validators_state.copy( validator_registry=validator_registry, validator_balances=n_validators_state.validator_balances + (config.MAX_DEPOSIT_AMOUNT,), ) state = update_validator_registry(state, config) entry_exit_effect_epoch = get_delayed_activation_exit_epoch( state.current_epoch(slots_per_epoch), config.ACTIVATION_EXIT_DELAY, ) # Check if the activating_validator is activated assert state.validator_registry[activating_index].activation_epoch == entry_exit_effect_epoch # Check if the activating_validator is exited assert state.validator_registry[exiting_index].exit_epoch == entry_exit_effect_epoch
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