def test_transfer(state, pubkeys, privkeys): pre_state = deepcopy(state) current_epoch = get_current_epoch(pre_state) sender_index = get_active_validator_indices(pre_state.validator_registry, current_epoch)[-1] recipient_index = get_active_validator_indices(pre_state.validator_registry, current_epoch)[0] transfer_pubkey = pubkeys[-1] transfer_privkey = privkeys[-1] amount = pre_state.validator_balances[sender_index] pre_transfer_recipient_balance = pre_state.validator_balances[recipient_index] transfer = Transfer( sender=sender_index, recipient=recipient_index, amount=amount, fee=0, slot=pre_state.slot + 1, pubkey=transfer_pubkey, signature=EMPTY_SIGNATURE, ) transfer.signature = bls.sign( message_hash=signed_root(transfer), privkey=transfer_privkey, domain=get_domain( fork=pre_state.fork, epoch=get_current_epoch(pre_state), domain_type=spec.DOMAIN_TRANSFER, ) ) # ensure withdrawal_credentials reproducable pre_state.validator_registry[sender_index].withdrawal_credentials = ( spec.BLS_WITHDRAWAL_PREFIX_BYTE + hash(transfer_pubkey)[1:] ) # un-activate so validator can transfer pre_state.validator_registry[sender_index].activation_epoch = spec.FAR_FUTURE_EPOCH post_state = deepcopy(pre_state) # # Add to state via block transition # block = build_empty_block_for_next_slot(post_state) block.body.transfers.append(transfer) state_transition(post_state, block) sender_balance = post_state.validator_balances[sender_index] recipient_balance = post_state.validator_balances[recipient_index] assert sender_balance == 0 assert recipient_balance == pre_transfer_recipient_balance + amount return pre_state, [block], post_state
def test_validator_already_exited(state): pre_state = deepcopy(state) # # setup pre_state # # move state forward PERSISTENT_COMMITTEE_PERIOD epochs to allow validator able to exit pre_state.slot += spec.PERSISTENT_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH current_epoch = get_current_epoch(pre_state) validator_index = get_active_validator_indices( pre_state.validator_registry, current_epoch)[0] privkey = pubkey_to_privkey[ pre_state.validator_registry[validator_index].pubkey] # but validator already has exited pre_state.validator_registry[ validator_index].exit_epoch = current_epoch + 2 # # build voluntary exit # voluntary_exit = build_voluntary_exit( pre_state, current_epoch, validator_index, privkey, ) with pytest.raises(AssertionError): process_voluntary_exit(pre_state, voluntary_exit) return pre_state, voluntary_exit, None
def test_validator_not_active(state): pre_state = deepcopy(state) current_epoch = get_current_epoch(pre_state) validator_index = get_active_validator_indices( pre_state.validator_registry, current_epoch)[0] privkey = pubkey_to_privkey[ pre_state.validator_registry[validator_index].pubkey] # # setup pre_state # pre_state.validator_registry[ validator_index].activation_epoch = spec.FAR_FUTURE_EPOCH # # build and test voluntary exit # voluntary_exit = build_voluntary_exit( pre_state, current_epoch, validator_index, privkey, ) with pytest.raises(AssertionError): process_voluntary_exit(pre_state, voluntary_exit) return pre_state, voluntary_exit, None
def test_success(state): pre_state = deepcopy(state) # # setup pre_state # # move state forward PERSISTENT_COMMITTEE_PERIOD epochs to allow for exit pre_state.slot += spec.PERSISTENT_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH # # build voluntary exit # current_epoch = get_current_epoch(pre_state) validator_index = get_active_validator_indices( pre_state.validator_registry, current_epoch)[0] privkey = pubkey_to_privkey[ pre_state.validator_registry[validator_index].pubkey] voluntary_exit = build_voluntary_exit( pre_state, current_epoch, validator_index, privkey, ) post_state = deepcopy(pre_state) # # test valid exit # process_voluntary_exit(post_state, voluntary_exit) assert not pre_state.validator_registry[validator_index].initiated_exit assert post_state.validator_registry[validator_index].initiated_exit return pre_state, voluntary_exit, post_state
def test_validator_not_active_long_enough(state): pre_state = deepcopy(state) # # setup pre_state # current_epoch = get_current_epoch(pre_state) validator_index = get_active_validator_indices( pre_state.validator_registry, current_epoch)[0] privkey = pubkey_to_privkey[ pre_state.validator_registry[validator_index].pubkey] # but validator already has initiated exit pre_state.validator_registry[validator_index].initiated_exit = True # # build voluntary exit # voluntary_exit = build_voluntary_exit( pre_state, current_epoch, validator_index, privkey, ) assert (current_epoch - pre_state.validator_registry[validator_index].activation_epoch < spec.PERSISTENT_COMMITTEE_PERIOD) with pytest.raises(AssertionError): process_voluntary_exit(pre_state, voluntary_exit) return pre_state, voluntary_exit, None
def test_proposer_slashing(state, pubkeys, privkeys): test_state = deepcopy(state) current_epoch = get_current_epoch(test_state) validator_index = get_active_validator_indices(test_state.validator_registry, current_epoch)[-1] privkey = privkeys[validator_index] slot = spec.GENESIS_SLOT header_1 = BeaconBlockHeader( slot=slot, previous_block_root=ZERO_HASH, state_root=ZERO_HASH, block_body_root=ZERO_HASH, signature=EMPTY_SIGNATURE, ) header_2 = deepcopy(header_1) header_2.previous_block_root = b'\x02' * 32 header_2.slot = slot + 1 domain = get_domain( fork=test_state.fork, epoch=get_current_epoch(test_state), domain_type=spec.DOMAIN_BEACON_BLOCK, ) header_1.signature = bls.sign( message_hash=signed_root(header_1), privkey=privkey, domain=domain, ) header_2.signature = bls.sign( message_hash=signed_root(header_2), privkey=privkey, domain=domain, ) proposer_slashing = ProposerSlashing( proposer_index=validator_index, header_1=header_1, header_2=header_2, ) # # Add to state via block transition # block = build_empty_block_for_next_slot(test_state) block.body.proposer_slashings.append(proposer_slashing) state_transition(test_state, block) assert not state.validator_registry[validator_index].initiated_exit assert not state.validator_registry[validator_index].slashed slashed_validator = test_state.validator_registry[validator_index] assert not slashed_validator.initiated_exit assert slashed_validator.slashed assert slashed_validator.exit_epoch < spec.FAR_FUTURE_EPOCH assert slashed_validator.withdrawable_epoch < spec.FAR_FUTURE_EPOCH # lost whistleblower reward assert test_state.validator_balances[validator_index] < state.validator_balances[validator_index] return state, [block], test_state
def test_voluntary_exit(state, pubkeys, privkeys): pre_state = deepcopy(state) validator_index = get_active_validator_indices(pre_state.validator_registry, get_current_epoch(pre_state))[-1] # move state forward PERSISTENT_COMMITTEE_PERIOD epochs to allow for exit pre_state.slot += spec.PERSISTENT_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH # artificially trigger registry update at next epoch transition pre_state.validator_registry_update_epoch -= 1 post_state = deepcopy(pre_state) voluntary_exit = VoluntaryExit( epoch=get_current_epoch(pre_state), validator_index=validator_index, signature=EMPTY_SIGNATURE, ) voluntary_exit.signature = bls.sign( message_hash=signed_root(voluntary_exit), privkey=privkeys[validator_index], domain=get_domain( fork=pre_state.fork, epoch=get_current_epoch(pre_state), domain_type=spec.DOMAIN_VOLUNTARY_EXIT, ) ) # # Add to state via block transition # initiate_exit_block = build_empty_block_for_next_slot(post_state) initiate_exit_block.body.voluntary_exits.append(voluntary_exit) state_transition(post_state, initiate_exit_block) assert not pre_state.validator_registry[validator_index].initiated_exit assert post_state.validator_registry[validator_index].initiated_exit assert post_state.validator_registry[validator_index].exit_epoch == spec.FAR_FUTURE_EPOCH # # Process within epoch transition # exit_block = build_empty_block_for_next_slot(post_state) exit_block.slot += spec.SLOTS_PER_EPOCH state_transition(post_state, exit_block) assert post_state.validator_registry[validator_index].exit_epoch < spec.FAR_FUTURE_EPOCH return pre_state, [initiate_exit_block, exit_block], post_state
def test_ejection(state): pre_state = deepcopy(state) current_epoch = get_current_epoch(pre_state) validator_index = get_active_validator_indices(pre_state.validator_registry, current_epoch)[-1] assert pre_state.validator_registry[validator_index].exit_epoch == spec.FAR_FUTURE_EPOCH # set validator balance to below ejection threshold pre_state.validator_balances[validator_index] = spec.EJECTION_BALANCE - 1 post_state = deepcopy(pre_state) # # trigger epoch transition # block = build_empty_block_for_next_slot(post_state) block.slot += spec.SLOTS_PER_EPOCH state_transition(post_state, block) assert post_state.validator_registry[validator_index].exit_epoch < spec.FAR_FUTURE_EPOCH return pre_state, [block], post_state