def run_process_registry_updates(state, valid=True): """ Run ``process_crosslinks``, yielding: - pre-state ('pre') - post-state ('post'). If ``valid == False``, run expecting ``AssertionError`` """ # transition state to slot before state transition slot = state.slot + (spec.SLOTS_PER_EPOCH - state.slot % spec.SLOTS_PER_EPOCH) - 1 block = build_empty_block_for_next_slot(state) block.slot = slot sign_block(state, block) state_transition(state, block) # cache state before epoch transition spec.cache_state(state) # process components of epoch transition before registry update spec.process_justification_and_finalization(state) spec.process_crosslinks(state) spec.process_rewards_and_penalties(state) yield 'pre', state process_registry_updates(state) yield 'post', state
def next_epoch_with_attestations(state, fill_cur_epoch, fill_prev_epoch): post_state = deepcopy(state) blocks = [] for _ in range(spec.SLOTS_PER_EPOCH): block = build_empty_block_for_next_slot(post_state) if fill_cur_epoch: slot_to_attest = post_state.slot - spec.MIN_ATTESTATION_INCLUSION_DELAY + 1 if slot_to_attest >= get_epoch_start_slot( get_current_epoch(post_state)): cur_attestation = get_valid_attestation( post_state, slot_to_attest) fill_aggregate_attestation(post_state, cur_attestation) block.body.attestations.append(cur_attestation) if fill_prev_epoch: slot_to_attest = post_state.slot - spec.SLOTS_PER_EPOCH + 1 prev_attestation = get_valid_attestation(post_state, slot_to_attest) fill_aggregate_attestation(post_state, prev_attestation) block.body.attestations.append(prev_attestation) state_transition(post_state, block) blocks.append(block) return state, blocks, post_state
def test_attester_slashing(state): test_state = deepcopy(state) attester_slashing = get_valid_attester_slashing(state) validator_index = attester_slashing.attestation_1.custody_bit_0_indices[0] # # Add to state via block transition # block = build_empty_block_for_next_slot(test_state) block.body.attester_slashings.append(attester_slashing) state_transition(test_state, block) assert not state.validator_registry[validator_index].slashed slashed_validator = test_state.validator_registry[validator_index] 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 get_balance(test_state, validator_index) < get_balance( state, validator_index) proposer_index = get_beacon_proposer_index(test_state) # gained whistleblower reward assert (get_balance(test_state, proposer_index) > get_balance( state, proposer_index)) return state, [block], test_state
def test_attestation(state): state.slot = spec.SLOTS_PER_EPOCH test_state = deepcopy(state) attestation = get_valid_attestation(state) # # Add to state via block transition # attestation_block = build_empty_block_for_next_slot(test_state) attestation_block.slot += spec.MIN_ATTESTATION_INCLUSION_DELAY attestation_block.body.attestations.append(attestation) state_transition(test_state, attestation_block) assert len(test_state.current_epoch_attestations) == len( state.current_epoch_attestations) + 1 # # Epoch transition should move to previous_epoch_attestations # pre_current_epoch_attestations = deepcopy( test_state.current_epoch_attestations) epoch_block = build_empty_block_for_next_slot(test_state) epoch_block.slot += spec.SLOTS_PER_EPOCH state_transition(test_state, epoch_block) assert len(test_state.current_epoch_attestations) == 0 assert test_state.previous_epoch_attestations == pre_current_epoch_attestations return state, [attestation_block, epoch_block], test_state
def test_transfer(state): # overwrite default 0 to test spec.MAX_TRANSFERS = 1 sender_index = get_active_validator_indices(state, get_current_epoch(state))[-1] amount = get_balance(state, sender_index) transfer = get_valid_transfer(state, state.slot + 1, sender_index, amount, signed=True) recipient_index = transfer.recipient pre_transfer_recipient_balance = get_balance(state, recipient_index) # un-activate so validator can transfer state.validator_registry[sender_index].activation_eligibility_epoch = spec.FAR_FUTURE_EPOCH yield 'pre', state # Add to state via block transition block = build_empty_block_for_next_slot(state) block.body.transfers.append(transfer) sign_block(state, block) yield 'blocks', [block], [spec.BeaconBlock] state_transition(state, block) yield 'post', state sender_balance = get_balance(state, sender_index) recipient_balance = get_balance(state, recipient_index) assert sender_balance == 0 assert recipient_balance == pre_transfer_recipient_balance + amount
def test_proposer_slashing(state): # copy for later balance lookups. pre_state = deepcopy(state) proposer_slashing = get_valid_proposer_slashing(state, signed_1=True, signed_2=True) validator_index = proposer_slashing.proposer_index assert not state.validator_registry[validator_index].slashed yield 'pre', state # # Add to state via block transition # block = build_empty_block_for_next_slot(state) block.body.proposer_slashings.append(proposer_slashing) sign_block(state, block) yield 'blocks', [block], [spec.BeaconBlock] state_transition(state, block) yield 'post', state # check if slashed slashed_validator = state.validator_registry[validator_index] 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 get_balance(state, validator_index) < get_balance(pre_state, validator_index)
def test_attestation(state): state.slot = spec.SLOTS_PER_EPOCH yield 'pre', state attestation = get_valid_attestation(state, signed=True) # Add to state via block transition pre_current_attestations_len = len(state.current_epoch_attestations) attestation_block = build_empty_block_for_next_slot(state) attestation_block.slot += spec.MIN_ATTESTATION_INCLUSION_DELAY attestation_block.body.attestations.append(attestation) sign_block(state, attestation_block) state_transition(state, attestation_block) assert len(state.current_epoch_attestations) == pre_current_attestations_len + 1 # Epoch transition should move to previous_epoch_attestations pre_current_attestations_root = spec.hash_tree_root(state.current_epoch_attestations) epoch_block = build_empty_block_for_next_slot(state) epoch_block.slot += spec.SLOTS_PER_EPOCH sign_block(state, epoch_block) state_transition(state, epoch_block) yield 'blocks', [attestation_block, epoch_block], [spec.BeaconBlock] yield 'post', state assert len(state.current_epoch_attestations) == 0 assert spec.hash_tree_root(state.previous_epoch_attestations) == pre_current_attestations_root
def add_attestation_to_state(state, attestation, slot): block = build_empty_block_for_next_slot(state) block.slot = slot block.body.attestations.append(attestation) state_transition_to(state, block.slot) sign_block(state, block) state_transition(state, block)
def next_slot(state): """ Transition to the next slot via an empty block. Return the empty block that triggered the transition. """ block = build_empty_block_for_next_slot(state) state_transition(state, block) return block
def apply_empty_block(state): """ Transition via an empty block (on current slot, assuming no block has been applied yet). :return: the empty block that triggered the transition. """ block = build_empty_block(state, signed=True) state_transition(state, block) return block
def test_success_prevous_epoch(state): attestation = get_valid_attestation(state) block = build_empty_block_for_next_slot(state) block.slot = state.slot + spec.SLOTS_PER_EPOCH state_transition(state, block) pre_state, post_state = run_attestation_processing(state, attestation) return pre_state, attestation, post_state
def next_epoch(state): """ Transition to the start slot of the next epoch via an empty block. Return the empty block that triggered the transition. """ block = build_empty_block_for_next_slot(state) block.slot += spec.SLOTS_PER_EPOCH - (state.slot % spec.SLOTS_PER_EPOCH) state_transition(state, block) return block
def test_after_epoch_slots(state): attestation = get_valid_attestation(state) block = build_empty_block_for_next_slot(state) # increment past latest inclusion slot block.slot = state.slot + spec.SLOTS_PER_EPOCH + 1 state_transition(state, block) pre_state, post_state = run_attestation_processing(state, attestation, False) return pre_state, attestation, post_state
def test_empty_block_transition(state): test_state = deepcopy(state) block = build_empty_block_for_next_slot(test_state) state_transition(test_state, block) assert len(test_state.eth1_data_votes) == len(state.eth1_data_votes) + 1 assert get_block_root_at_slot(test_state, state.slot) == block.previous_block_root return state, [block], test_state
def test_skipped_slots(state): test_state = deepcopy(state) block = build_empty_block_for_next_slot(test_state) block.slot += 3 state_transition(test_state, block) assert test_state.slot == block.slot for slot in range(state.slot, test_state.slot): assert get_block_root_at_slot(test_state, slot) == block.previous_block_root return state, [block], test_state
def test_empty_epoch_transition(state): test_state = deepcopy(state) block = build_empty_block_for_next_slot(test_state) block.slot += spec.SLOTS_PER_EPOCH state_transition(test_state, block) assert test_state.slot == block.slot for slot in range(state.slot, test_state.slot): assert get_block_root_at_slot(test_state, slot) == block.previous_block_root return state, [block], test_state
def test_empty_epoch_transition_not_finalizing(state): test_state = deepcopy(state) block = build_empty_block_for_next_slot(test_state) block.slot += spec.SLOTS_PER_EPOCH * 5 state_transition(test_state, block) assert test_state.slot == block.slot assert test_state.finalized_epoch < get_current_epoch(test_state) - 4 for index in range(len(test_state.validator_registry)): assert get_balance(test_state, index) < get_balance(state, index) return state, [block], test_state
def test_empty_block_transition(state): pre_slot = state.slot pre_eth1_votes = len(state.eth1_data_votes) yield 'pre', state block = build_empty_block_for_next_slot(state, signed=True) yield 'blocks', [block], [spec.BeaconBlock] state_transition(state, block) yield 'post', state assert len(state.eth1_data_votes) == pre_eth1_votes + 1 assert get_block_root_at_slot(state, pre_slot) == block.previous_block_root
def run_process_crosslinks(state, valid=True): # transition state to slot before state transition slot = state.slot + (spec.SLOTS_PER_EPOCH - state.slot % spec.SLOTS_PER_EPOCH) - 1 block = build_empty_block_for_next_slot(state) block.slot = slot state_transition(state, block) # cache state before epoch transition cache_state(state) post_state = deepcopy(state) process_crosslinks(post_state) return state, post_state
def test_historical_batch(state): state.slot += spec.SLOTS_PER_HISTORICAL_ROOT - (state.slot % spec.SLOTS_PER_HISTORICAL_ROOT) - 1 pre_historical_roots_len = len(state.historical_roots) yield 'pre', state block = build_empty_block_for_next_slot(state, signed=True) state_transition(state, block) yield 'blocks', [block], [spec.BeaconBlock] yield 'post', state assert state.slot == block.slot assert get_current_epoch(state) % (spec.SLOTS_PER_HISTORICAL_ROOT // spec.SLOTS_PER_EPOCH) == 0 assert len(state.historical_roots) == pre_historical_roots_len + 1
def test_empty_epoch_transition(state): pre_slot = state.slot yield 'pre', state block = build_empty_block_for_next_slot(state) block.slot += spec.SLOTS_PER_EPOCH sign_block(state, block) yield 'blocks', [block], [spec.BeaconBlock] state_transition(state, block) yield 'post', state assert state.slot == block.slot for slot in range(pre_slot, state.slot): assert get_block_root_at_slot(state, slot) == block.previous_block_root
def test_transfer(state): # overwrite default 0 to test spec.MAX_TRANSFERS = 1 pre_state = deepcopy(state) current_epoch = get_current_epoch(pre_state) sender_index = get_active_validator_indices(pre_state, current_epoch)[-1] recipient_index = get_active_validator_indices(pre_state, current_epoch)[0] transfer_pubkey = pubkeys[-1] transfer_privkey = privkeys[-1] amount = get_balance(pre_state, sender_index) pre_transfer_recipient_balance = get_balance(pre_state, recipient_index) transfer = Transfer( sender=sender_index, recipient=recipient_index, amount=amount, fee=0, slot=pre_state.slot + 1, pubkey=transfer_pubkey, ) transfer.signature = bls.sign(message_hash=signing_root(transfer), privkey=transfer_privkey, domain=get_domain( state=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_eligibility_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 = get_balance(post_state, sender_index) recipient_balance = get_balance(post_state, recipient_index) assert sender_balance == 0 assert recipient_balance == pre_transfer_recipient_balance + amount return pre_state, [block], post_state
def test_historical_batch(state): state.slot += spec.SLOTS_PER_HISTORICAL_ROOT - ( state.slot % spec.SLOTS_PER_HISTORICAL_ROOT) - 1 post_state = deepcopy(state) block = build_empty_block_for_next_slot(post_state) state_transition(post_state, block) assert post_state.slot == block.slot assert get_current_epoch(post_state) % (spec.SLOTS_PER_HISTORICAL_ROOT // spec.SLOTS_PER_EPOCH) == 0 assert len(post_state.historical_roots) == len(state.historical_roots) + 1 return state, [block], post_state
def test_voluntary_exit(state): pre_state = deepcopy(state) validator_index = get_active_validator_indices( pre_state, 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 post_state = deepcopy(pre_state) voluntary_exit = VoluntaryExit( epoch=get_current_epoch(pre_state), validator_index=validator_index, ) voluntary_exit.signature = bls.sign( message_hash=signing_root(voluntary_exit), privkey=privkeys[validator_index], domain=get_domain( state=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 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_voluntary_exit(state): validator_index = get_active_validator_indices( state, get_current_epoch(state) )[-1] # move state forward PERSISTENT_COMMITTEE_PERIOD epochs to allow for exit state.slot += spec.PERSISTENT_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH yield 'pre', state voluntary_exit = VoluntaryExit( epoch=get_current_epoch(state), validator_index=validator_index, ) voluntary_exit.signature = bls_sign( message_hash=signing_root(voluntary_exit), privkey=privkeys[validator_index], domain=get_domain( state=state, domain_type=spec.DOMAIN_VOLUNTARY_EXIT, ) ) # Add to state via block transition initiate_exit_block = build_empty_block_for_next_slot(state) initiate_exit_block.body.voluntary_exits.append(voluntary_exit) sign_block(state, initiate_exit_block) state_transition(state, initiate_exit_block) assert state.validator_registry[validator_index].exit_epoch < spec.FAR_FUTURE_EPOCH # Process within epoch transition exit_block = build_empty_block_for_next_slot(state) exit_block.slot += spec.SLOTS_PER_EPOCH sign_block(state, exit_block) state_transition(state, exit_block) yield 'blocks', [initiate_exit_block, exit_block], [spec.BeaconBlock] yield 'post', state assert state.validator_registry[validator_index].exit_epoch < spec.FAR_FUTURE_EPOCH
def test_balance_driven_status_transitions(state): current_epoch = get_current_epoch(state) validator_index = get_active_validator_indices(state, current_epoch)[-1] assert state.validator_registry[validator_index].exit_epoch == spec.FAR_FUTURE_EPOCH # set validator balance to below ejection threshold state.validator_registry[validator_index].effective_balance = spec.EJECTION_BALANCE yield 'pre', state # trigger epoch transition block = build_empty_block_for_next_slot(state) block.slot += spec.SLOTS_PER_EPOCH sign_block(state, block) state_transition(state, block) yield 'blocks', [block], [spec.BeaconBlock] yield 'post', state assert state.validator_registry[validator_index].exit_epoch < spec.FAR_FUTURE_EPOCH
def run_process_crosslinks(state, valid=True): """ Run ``process_crosslinks``, yielding: - pre-state ('pre') - post-state ('post'). If ``valid == False``, run expecting ``AssertionError`` """ # transition state to slot before state transition slot = state.slot + (spec.SLOTS_PER_EPOCH - state.slot % spec.SLOTS_PER_EPOCH) - 1 block = build_empty_block_for_next_slot(state) block.slot = slot sign_block(state, block) state_transition(state, block) # cache state before epoch transition cache_state(state) yield 'pre', state process_crosslinks(state) yield 'post', state
def test_deposit_top_up(state): pre_state = deepcopy(state) test_deposit_data_leaves = [ZERO_HASH] * len(pre_state.validator_registry) validator_index = 0 amount = spec.MAX_EFFECTIVE_BALANCE // 4 pubkey = pubkeys[validator_index] privkey = privkeys[validator_index] deposit_data = build_deposit_data(pre_state, pubkey, privkey, amount) merkle_index = len(test_deposit_data_leaves) item = deposit_data.hash_tree_root() test_deposit_data_leaves.append(item) tree = calc_merkle_tree_from_leaves(tuple(test_deposit_data_leaves)) root = get_merkle_root((tuple(test_deposit_data_leaves))) proof = list(get_merkle_proof(tree, item_index=merkle_index)) assert verify_merkle_branch(item, proof, spec.DEPOSIT_CONTRACT_TREE_DEPTH, merkle_index, root) deposit = Deposit( proof=list(proof), index=merkle_index, data=deposit_data, ) pre_state.latest_eth1_data.deposit_root = root pre_state.latest_eth1_data.deposit_count = len(test_deposit_data_leaves) block = build_empty_block_for_next_slot(pre_state) block.body.deposits.append(deposit) pre_balance = get_balance(pre_state, validator_index) post_state = deepcopy(pre_state) state_transition(post_state, block) assert len(post_state.validator_registry) == len( pre_state.validator_registry) assert len(post_state.balances) == len(pre_state.balances) assert get_balance(post_state, validator_index) == pre_balance + amount return pre_state, [block], post_state
def test_eth1_data_votes(state): post_state = deepcopy(state) expected_votes = 0 assert len(state.eth1_data_votes) == expected_votes blocks = [] for _ in range(spec.SLOTS_PER_ETH1_VOTING_PERIOD - 1): block = build_empty_block_for_next_slot(post_state) state_transition(post_state, block) expected_votes += 1 assert len(post_state.eth1_data_votes) == expected_votes blocks.append(block) block = build_empty_block_for_next_slot(post_state) state_transition(post_state, block) blocks.append(block) assert post_state.slot % spec.SLOTS_PER_ETH1_VOTING_PERIOD == 0 assert len(post_state.eth1_data_votes) == 1 return state, blocks, post_state
def test_balance_driven_status_transitions(state): current_epoch = get_current_epoch(state) validator_index = get_active_validator_indices(state, current_epoch)[-1] assert state.validator_registry[ validator_index].exit_epoch == spec.FAR_FUTURE_EPOCH # set validator balance to below ejection threshold state.validator_registry[ validator_index].effective_balance = spec.EJECTION_BALANCE post_state = deepcopy(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 state, [block], post_state