Merge pull request #1206 from ethereum/cov-hunt

Test coverage improvements
This commit is contained in:
Danny Ryan
2019-06-29 16:09:52 -05:00
committed by GitHub
12 changed files with 1011 additions and 124 deletions

View File

@@ -4,13 +4,15 @@ from eth2spec.utils.bls import bls_sign
from eth2spec.utils.ssz.ssz_impl import signing_root
def get_valid_transfer(spec, state, slot=None, sender_index=None, amount=None, fee=None, signed=False):
def get_valid_transfer(spec, state, slot=None, sender_index=None,
recipient_index=None, amount=None, fee=None, signed=False):
if slot is None:
slot = state.slot
current_epoch = spec.get_current_epoch(state)
if sender_index is None:
sender_index = spec.get_active_validator_indices(state, current_epoch)[-1]
recipient_index = spec.get_active_validator_indices(state, current_epoch)[0]
if recipient_index is None:
recipient_index = spec.get_active_validator_indices(state, current_epoch)[0]
transfer_pubkey = pubkeys[-1]
transfer_privkey = privkeys[-1]

View File

@@ -84,6 +84,29 @@ def test_success_since_max_epochs_per_crosslink(spec, state):
yield from run_attestation_processing(spec, state, attestation)
@with_all_phases
@spec_state_test
def test_wrong_end_epoch_with_max_epochs_per_crosslink(spec, state):
for _ in range(spec.MAX_EPOCHS_PER_CROSSLINK + 2):
next_epoch(spec, state)
apply_empty_block(spec, state)
attestation = get_valid_attestation(spec, state)
data = attestation.data
# test logic sanity check: make sure the attestation only includes MAX_EPOCHS_PER_CROSSLINK epochs
assert data.crosslink.end_epoch - data.crosslink.start_epoch == spec.MAX_EPOCHS_PER_CROSSLINK
# Now change it to be different
data.crosslink.end_epoch += 1
sign_attestation(spec, state, attestation)
for _ in range(spec.MIN_ATTESTATION_INCLUSION_DELAY):
next_slot(spec, state)
apply_empty_block(spec, state)
yield from run_attestation_processing(spec, state, attestation, False)
@with_all_phases
@always_bls
@spec_state_test
@@ -147,6 +170,47 @@ def test_wrong_shard(spec, state):
yield from run_attestation_processing(spec, state, attestation, False)
@with_all_phases
@spec_state_test
def test_invalid_shard(spec, state):
attestation = get_valid_attestation(spec, state)
state.slot += spec.MIN_ATTESTATION_INCLUSION_DELAY
# off by one (with respect to valid range) on purpose
attestation.data.crosslink.shard = spec.SHARD_COUNT
sign_attestation(spec, state, attestation)
yield from run_attestation_processing(spec, state, attestation, False)
@with_all_phases
@spec_state_test
def test_old_target_epoch(spec, state):
assert spec.MIN_ATTESTATION_INCLUSION_DELAY < spec.SLOTS_PER_EPOCH * 2
attestation = get_valid_attestation(spec, state, signed=True)
state.slot = spec.SLOTS_PER_EPOCH * 2 # target epoch will be too old to handle
yield from run_attestation_processing(spec, state, attestation, False)
@with_all_phases
@spec_state_test
def test_future_target_epoch(spec, state):
assert spec.MIN_ATTESTATION_INCLUSION_DELAY < spec.SLOTS_PER_EPOCH * 2
attestation = get_valid_attestation(spec, state)
state.slot += spec.MIN_ATTESTATION_INCLUSION_DELAY
attestation.data.target.epoch = spec.get_current_epoch(state) + 1 # target epoch will be too new to handle
sign_attestation(spec, state, attestation)
yield from run_attestation_processing(spec, state, attestation, False)
@with_all_phases
@spec_state_test
def test_new_source_epoch(spec, state):

View File

@@ -200,12 +200,106 @@ def test_participants_already_slashed(spec, state):
@with_all_phases
@spec_state_test
def test_custody_bit_0_and_1(spec, state):
def test_custody_bit_0_and_1_intersect(spec, state):
attester_slashing = get_valid_attester_slashing(spec, state, signed_1=False, signed_2=True)
attester_slashing.attestation_1.custody_bit_1_indices = (
attester_slashing.attestation_1.custody_bit_0_indices
attester_slashing.attestation_1.custody_bit_1_indices.append(
attester_slashing.attestation_1.custody_bit_0_indices[0]
)
sign_indexed_attestation(spec, state, attester_slashing.attestation_1)
yield from run_attester_slashing_processing(spec, state, attester_slashing, False)
@always_bls
@with_all_phases
@spec_state_test
def test_att1_bad_extra_index(spec, state):
attester_slashing = get_valid_attester_slashing(spec, state, signed_1=True, signed_2=True)
indices = attester_slashing.attestation_1.custody_bit_0_indices
options = list(set(range(len(state.validators))) - set(indices))
indices.append(options[len(options) // 2]) # add random index, not previously in attestation.
attester_slashing.attestation_1.custody_bit_0_indices = sorted(indices)
# Do not sign the modified attestation (it's ok to slash if attester signed, not if they did not),
# see if the bad extra index is spotted, and slashing is aborted.
yield from run_attester_slashing_processing(spec, state, attester_slashing, False)
@always_bls
@with_all_phases
@spec_state_test
def test_att1_bad_replaced_index(spec, state):
attester_slashing = get_valid_attester_slashing(spec, state, signed_1=True, signed_2=True)
indices = attester_slashing.attestation_1.custody_bit_0_indices
options = list(set(range(len(state.validators))) - set(indices))
indices[3] = options[len(options) // 2] # replace with random index, not previously in attestation.
attester_slashing.attestation_1.custody_bit_0_indices = sorted(indices)
# Do not sign the modified attestation (it's ok to slash if attester signed, not if they did not),
# see if the bad replaced index is spotted, and slashing is aborted.
yield from run_attester_slashing_processing(spec, state, attester_slashing, False)
@always_bls
@with_all_phases
@spec_state_test
def test_att2_bad_extra_index(spec, state):
attester_slashing = get_valid_attester_slashing(spec, state, signed_1=True, signed_2=True)
indices = attester_slashing.attestation_2.custody_bit_0_indices
options = list(set(range(len(state.validators))) - set(indices))
indices.append(options[len(options) // 2]) # add random index, not previously in attestation.
attester_slashing.attestation_2.custody_bit_0_indices = sorted(indices)
# Do not sign the modified attestation (it's ok to slash if attester signed, not if they did not),
# see if the bad extra index is spotted, and slashing is aborted.
yield from run_attester_slashing_processing(spec, state, attester_slashing, False)
@always_bls
@with_all_phases
@spec_state_test
def test_att2_bad_replaced_index(spec, state):
attester_slashing = get_valid_attester_slashing(spec, state, signed_1=True, signed_2=True)
indices = attester_slashing.attestation_2.custody_bit_0_indices
options = list(set(range(len(state.validators))) - set(indices))
indices[3] = options[len(options) // 2] # replace with random index, not previously in attestation.
attester_slashing.attestation_2.custody_bit_0_indices = sorted(indices)
# Do not sign the modified attestation (it's ok to slash if attester signed, not if they did not),
# see if the bad replaced index is spotted, and slashing is aborted.
yield from run_attester_slashing_processing(spec, state, attester_slashing, False)
@with_all_phases
@spec_state_test
def test_unsorted_att_1_bit0(spec, state):
attester_slashing = get_valid_attester_slashing(spec, state, signed_1=False, signed_2=True)
indices = attester_slashing.attestation_1.custody_bit_0_indices
assert len(indices) >= 3
indices[1], indices[2] = indices[2], indices[1] # unsort second and third index
sign_indexed_attestation(spec, state, attester_slashing.attestation_1)
yield from run_attester_slashing_processing(spec, state, attester_slashing, False)
@with_all_phases
@spec_state_test
def test_unsorted_att_2_bit0(spec, state):
attester_slashing = get_valid_attester_slashing(spec, state, signed_1=True, signed_2=False)
indices = attester_slashing.attestation_2.custody_bit_0_indices
assert len(indices) >= 3
indices[1], indices[2] = indices[2], indices[1] # unsort second and third index
sign_indexed_attestation(spec, state, attester_slashing.attestation_2)
yield from run_attester_slashing_processing(spec, state, attester_slashing, False)
# note: unsorted indices for custody bit 0 are to be introduced in phase 1 testing.

View File

@@ -49,20 +49,50 @@ def run_deposit_processing(spec, state, deposit, validator_index, valid=True, ef
assert len(state.balances) == pre_validator_count + 1
assert get_balance(state, validator_index) == pre_balance + deposit.data.amount
effective = min(spec.MAX_EFFECTIVE_BALANCE,
pre_balance + deposit.data.amount)
effective -= effective % spec.EFFECTIVE_BALANCE_INCREMENT
assert state.validators[validator_index].effective_balance == effective
assert state.eth1_deposit_index == state.eth1_data.deposit_count
@with_all_phases
@spec_state_test
def test_new_deposit(spec, state):
def test_new_deposit_under_max(spec, state):
# fresh deposit = next validator index = validator appended to registry
validator_index = len(state.validators)
# effective balance will be 1 EFFECTIVE_BALANCE_INCREMENT smaller because of this small decrement.
amount = spec.MAX_EFFECTIVE_BALANCE - 1
deposit = prepare_state_and_deposit(spec, state, validator_index, amount, signed=True)
yield from run_deposit_processing(spec, state, deposit, validator_index)
@with_all_phases
@spec_state_test
def test_new_deposit_max(spec, state):
# fresh deposit = next validator index = validator appended to registry
validator_index = len(state.validators)
# effective balance will be exactly the same as balance.
amount = spec.MAX_EFFECTIVE_BALANCE
deposit = prepare_state_and_deposit(spec, state, validator_index, amount, signed=True)
yield from run_deposit_processing(spec, state, deposit, validator_index)
@with_all_phases
@spec_state_test
def test_new_deposit_over_max(spec, state):
# fresh deposit = next validator index = validator appended to registry
validator_index = len(state.validators)
# just 1 over the limit, effective balance should be set MAX_EFFECTIVE_BALANCE during processing
amount = spec.MAX_EFFECTIVE_BALANCE + 1
deposit = prepare_state_and_deposit(spec, state, validator_index, amount, signed=True)
yield from run_deposit_processing(spec, state, deposit, validator_index)
@with_all_phases
@always_bls
@spec_state_test

View File

@@ -1,7 +1,7 @@
from eth2spec.test.context import spec_state_test, expect_assertion_error, always_bls, with_all_phases
from eth2spec.test.helpers.state import next_epoch
from eth2spec.test.helpers.block import apply_empty_block
from eth2spec.test.helpers.transfers import get_valid_transfer
from eth2spec.test.helpers.transfers import get_valid_transfer, sign_transfer
def run_transfer_processing(spec, state, transfer, valid=True):
@@ -13,11 +13,6 @@ def run_transfer_processing(spec, state, transfer, valid=True):
If ``valid == False``, run expecting ``AssertionError``
"""
proposer_index = spec.get_beacon_proposer_index(state)
pre_transfer_sender_balance = state.balances[transfer.sender]
pre_transfer_recipient_balance = state.balances[transfer.recipient]
pre_transfer_proposer_balance = state.balances[proposer_index]
yield 'pre', state
yield 'transfer', transfer
@@ -26,6 +21,11 @@ def run_transfer_processing(spec, state, transfer, valid=True):
yield 'post', None
return
proposer_index = spec.get_beacon_proposer_index(state)
pre_transfer_sender_balance = state.balances[transfer.sender]
pre_transfer_recipient_balance = state.balances[transfer.recipient]
pre_transfer_proposer_balance = state.balances[proposer_index]
spec.process_transfer(state, transfer)
yield 'post', state
@@ -107,20 +107,48 @@ def test_active_but_transfer_past_effective_balance(spec, state):
def test_incorrect_slot(spec, state):
transfer = get_valid_transfer(spec, state, slot=state.slot + 1, signed=True)
# un-activate so validator can transfer
state.validators[transfer.sender].activation_epoch = spec.FAR_FUTURE_EPOCH
state.validators[transfer.sender].activation_eligibility_epoch = spec.FAR_FUTURE_EPOCH
yield from run_transfer_processing(spec, state, transfer, False)
@with_all_phases
@spec_state_test
def test_insufficient_balance_for_fee_result_dust(spec, state):
def test_transfer_clean(spec, state):
sender_index = spec.get_active_validator_indices(state, spec.get_current_epoch(state))[-1]
state.balances[sender_index] = spec.MAX_EFFECTIVE_BALANCE
state.balances[sender_index] = spec.MIN_DEPOSIT_AMOUNT
transfer = get_valid_transfer(spec, state, sender_index=sender_index,
amount=spec.MIN_DEPOSIT_AMOUNT, fee=0, signed=True)
# un-activate so validator can transfer
state.validators[transfer.sender].activation_eligibility_epoch = spec.FAR_FUTURE_EPOCH
yield from run_transfer_processing(spec, state, transfer)
@with_all_phases
@spec_state_test
def test_transfer_clean_split_to_fee(spec, state):
sender_index = spec.get_active_validator_indices(state, spec.get_current_epoch(state))[-1]
state.balances[sender_index] = spec.MIN_DEPOSIT_AMOUNT
transfer = get_valid_transfer(spec, state, sender_index=sender_index,
amount=spec.MIN_DEPOSIT_AMOUNT // 2, fee=spec.MIN_DEPOSIT_AMOUNT // 2, signed=True)
# un-activate so validator can transfer
state.validators[transfer.sender].activation_eligibility_epoch = spec.FAR_FUTURE_EPOCH
yield from run_transfer_processing(spec, state, transfer)
@with_all_phases
@spec_state_test
def test_insufficient_balance_for_fee(spec, state):
sender_index = spec.get_active_validator_indices(state, spec.get_current_epoch(state))[-1]
state.balances[sender_index] = spec.MIN_DEPOSIT_AMOUNT
transfer = get_valid_transfer(spec, state, sender_index=sender_index, amount=0, fee=1, signed=True)
# un-activate so validator can transfer
state.validators[transfer.sender].activation_epoch = spec.FAR_FUTURE_EPOCH
state.validators[transfer.sender].activation_eligibility_epoch = spec.FAR_FUTURE_EPOCH
yield from run_transfer_processing(spec, state, transfer, False)
@@ -142,11 +170,11 @@ def test_insufficient_balance_for_fee_result_full(spec, state):
@spec_state_test
def test_insufficient_balance_for_amount_result_dust(spec, state):
sender_index = spec.get_active_validator_indices(state, spec.get_current_epoch(state))[-1]
state.balances[sender_index] = spec.MAX_EFFECTIVE_BALANCE
state.balances[sender_index] = spec.MIN_DEPOSIT_AMOUNT
transfer = get_valid_transfer(spec, state, sender_index=sender_index, amount=1, fee=0, signed=True)
# un-activate so validator can transfer
state.validators[transfer.sender].activation_epoch = spec.FAR_FUTURE_EPOCH
state.validators[transfer.sender].activation_eligibility_epoch = spec.FAR_FUTURE_EPOCH
yield from run_transfer_processing(spec, state, transfer, False)
@@ -287,7 +315,7 @@ def test_no_dust_sender(spec, state):
)
# un-activate so validator can transfer
state.validators[transfer.sender].activation_epoch = spec.FAR_FUTURE_EPOCH
state.validators[transfer.sender].activation_eligibility_epoch = spec.FAR_FUTURE_EPOCH
yield from run_transfer_processing(spec, state, transfer, False)
@@ -301,7 +329,29 @@ def test_no_dust_recipient(spec, state):
state.balances[transfer.recipient] = 0
# un-activate so validator can transfer
state.validators[transfer.sender].activation_epoch = spec.FAR_FUTURE_EPOCH
state.validators[transfer.sender].activation_eligibility_epoch = spec.FAR_FUTURE_EPOCH
yield from run_transfer_processing(spec, state, transfer, False)
@with_all_phases
@spec_state_test
def test_non_existent_sender(spec, state):
sender_index = spec.get_active_validator_indices(state, spec.get_current_epoch(state))[-1]
transfer = get_valid_transfer(spec, state, sender_index=sender_index, amount=1, fee=0)
transfer.sender = len(state.validators)
sign_transfer(spec, state, transfer, 42) # mostly valid signature, but sender won't exist, use bogus key.
yield from run_transfer_processing(spec, state, transfer, False)
@with_all_phases
@spec_state_test
def test_non_existent_recipient(spec, state):
sender_index = spec.get_active_validator_indices(state, spec.get_current_epoch(state))[-1]
state.balances[sender_index] = spec.MAX_EFFECTIVE_BALANCE + 1
transfer = get_valid_transfer(spec, state, sender_index=sender_index,
recipient_index=len(state.validators), amount=1, fee=0, signed=True)
yield from run_transfer_processing(spec, state, transfer, False)
@@ -313,6 +363,6 @@ def test_invalid_pubkey(spec, state):
state.validators[transfer.sender].withdrawal_credentials = spec.ZERO_HASH
# un-activate so validator can transfer
state.validators[transfer.sender].activation_epoch = spec.FAR_FUTURE_EPOCH
state.validators[transfer.sender].activation_eligibility_epoch = spec.FAR_FUTURE_EPOCH
yield from run_transfer_processing(spec, state, transfer, False)

View File

@@ -0,0 +1,45 @@
process_calls = [
'process_justification_and_finalization',
'process_crosslinks',
'process_rewards_and_penalties',
'process_registry_updates',
'process_reveal_deadlines',
'process_challenge_deadlines',
'process_slashings',
'process_final_updates',
'after_process_final_updates',
]
def run_epoch_processing_to(spec, state, process_name: str):
"""
Processes to the next epoch transition, up to, but not including, the sub-transition named ``process_name``
"""
slot = state.slot + (spec.SLOTS_PER_EPOCH - state.slot % spec.SLOTS_PER_EPOCH)
# transition state to slot before epoch state transition
spec.process_slots(state, slot - 1)
# start transitioning, do one slot update before the epoch itself.
spec.process_slot(state)
# process components of epoch transition before final-updates
for name in process_calls:
if name == process_name:
break
# only run when present. Later phases introduce more to the epoch-processing.
if hasattr(spec, name):
getattr(spec, name)(state)
def run_epoch_processing_with(spec, state, process_name: str):
"""
Processes to the next epoch transition, up to and including the sub-transition named ``process_name``
- pre-state ('pre'), state before calling ``process_name``
- post-state ('post'), state after calling ``process_name``
"""
run_epoch_processing_to(spec, state, process_name)
yield 'pre', state
getattr(spec, process_name)(state)
yield 'post', state

View File

@@ -3,42 +3,20 @@ from copy import deepcopy
from eth2spec.test.context import spec_state_test, with_all_phases
from eth2spec.test.helpers.state import (
next_epoch,
next_slot,
state_transition_and_sign_block,
next_slot
)
from eth2spec.test.helpers.block import apply_empty_block, sign_block
from eth2spec.test.helpers.block import apply_empty_block
from eth2spec.test.helpers.attestations import (
add_attestation_to_state,
build_empty_block_for_next_slot,
fill_aggregate_attestation,
get_valid_attestation,
sign_attestation,
)
from eth2spec.test.phase_0.epoch_processing.run_epoch_process_base import run_epoch_processing_with
def run_process_crosslinks(spec, 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(spec, state)
block.slot = slot
sign_block(spec, state, block)
state_transition_and_sign_block(spec, state, block)
# cache state before epoch transition
spec.process_slot(state)
# process components of epoch transition before processing crosslinks
spec.process_justification_and_finalization(state)
yield 'pre', state
spec.process_crosslinks(state)
yield 'post', state
def run_process_crosslinks(spec, state):
yield from run_epoch_processing_with(spec, state, 'process_crosslinks')
@with_all_phases

View File

@@ -0,0 +1,91 @@
from eth2spec.test.context import spec_state_test, with_all_phases
from eth2spec.test.phase_0.epoch_processing.run_epoch_process_base import (
run_epoch_processing_with, run_epoch_processing_to
)
def run_process_final_updates(spec, state):
yield from run_epoch_processing_with(spec, state, 'process_final_updates')
@with_all_phases
@spec_state_test
def test_eth1_vote_no_reset(spec, state):
assert spec.SLOTS_PER_ETH1_VOTING_PERIOD > spec.SLOTS_PER_EPOCH
# skip ahead to the end of the epoch
state.slot = spec.SLOTS_PER_EPOCH - 1
for i in range(state.slot + 1): # add a vote for each skipped slot.
state.eth1_data_votes.append(
spec.Eth1Data(deposit_root=b'\xaa' * 32,
deposit_count=state.eth1_deposit_index,
block_hash=b'\xbb' * 32))
yield from run_process_final_updates(spec, state)
assert len(state.eth1_data_votes) == spec.SLOTS_PER_EPOCH
@with_all_phases
@spec_state_test
def test_eth1_vote_reset(spec, state):
# skip ahead to the end of the voting period
state.slot = spec.SLOTS_PER_ETH1_VOTING_PERIOD - 1
for i in range(state.slot + 1): # add a vote for each skipped slot.
state.eth1_data_votes.append(
spec.Eth1Data(deposit_root=b'\xaa' * 32,
deposit_count=state.eth1_deposit_index,
block_hash=b'\xbb' * 32))
yield from run_process_final_updates(spec, state)
assert len(state.eth1_data_votes) == 0
@with_all_phases
@spec_state_test
def test_effective_balance_hysteresis(spec, state):
# Prepare state up to the final-updates.
# Then overwrite the balances, we only want to focus to be on the hysteresis based changes.
run_epoch_processing_to(spec, state, 'process_final_updates')
# Set some edge cases for balances
max = spec.MAX_EFFECTIVE_BALANCE
min = spec.EJECTION_BALANCE
inc = spec.EFFECTIVE_BALANCE_INCREMENT
half_inc = inc // 2
cases = [
(max, max, max, "as-is"),
(max, max - 1, max - inc, "round down, step lower"),
(max, max + 1, max, "round down"),
(max, max - inc, max - inc, "exactly 1 step lower"),
(max, max - inc - 1, max - (2 * inc), "just 1 over 1 step lower"),
(max, max - inc + 1, max - inc, "close to 1 step lower"),
(min, min + (half_inc * 3), min, "bigger balance, but not high enough"),
(min, min + (half_inc * 3) + 1, min + inc, "bigger balance, high enough, but small step"),
(min, min + (half_inc * 4) - 1, min + inc, "bigger balance, high enough, close to double step"),
(min, min + (half_inc * 4), min + (2 * inc), "exact two step balance increment"),
(min, min + (half_inc * 4) + 1, min + (2 * inc), "over two steps, round down"),
]
current_epoch = spec.get_current_epoch(state)
for i, (pre_eff, bal, _, _) in enumerate(cases):
assert spec.is_active_validator(state.validators[i], current_epoch)
state.validators[i].effective_balance = pre_eff
state.balances[i] = bal
yield 'pre', state
spec.process_final_updates(state)
yield 'post', state
for i, (_, _, post_eff, name) in enumerate(cases):
assert state.validators[i].effective_balance == post_eff, name
@with_all_phases
@spec_state_test
def test_historical_root_accumulator(spec, state):
# skip ahead to near the end of the historical roots period (excl block before epoch processing)
state.slot = spec.SLOTS_PER_HISTORICAL_ROOT - 1
history_len = len(state.historical_roots)
yield from run_process_final_updates(spec, state)
assert len(state.historical_roots) == history_len + 1

View File

@@ -0,0 +1,280 @@
from eth2spec.test.context import spec_state_test, with_all_phases
from eth2spec.test.phase_0.epoch_processing.run_epoch_process_base import (
run_epoch_processing_with
)
def run_process_just_and_fin(spec, state):
yield from run_epoch_processing_with(spec, state, 'process_justification_and_finalization')
def get_shards_for_slot(spec, state, slot):
epoch = spec.slot_to_epoch(slot)
epoch_start_shard = spec.get_epoch_start_shard(state, epoch)
committees_per_slot = spec.get_epoch_committee_count(state, epoch) // spec.SLOTS_PER_EPOCH
shard = (epoch_start_shard + committees_per_slot * (slot % spec.SLOTS_PER_EPOCH)) % spec.SHARD_COUNT
return [shard + i for i in range(committees_per_slot)]
def add_mock_attestations(spec, state, epoch, source, target, sufficient_support=False):
# we must be at the end of the epoch
assert (state.slot + 1) % spec.SLOTS_PER_EPOCH == 0
previous_epoch = spec.get_previous_epoch(state)
current_epoch = spec.get_current_epoch(state)
if current_epoch == epoch:
attestations = state.current_epoch_attestations
elif previous_epoch == epoch:
attestations = state.previous_epoch_attestations
else:
raise Exception(f"cannot include attestations in epoch ${epoch} from epoch ${current_epoch}")
total_balance = spec.get_total_active_balance(state)
remaining_balance = total_balance * 2 // 3
epoch_start_slot = spec.get_epoch_start_slot(epoch)
for slot in range(epoch_start_slot, epoch_start_slot + spec.SLOTS_PER_EPOCH):
for shard in get_shards_for_slot(spec, state, slot):
# Check if we already have had sufficient balance. (and undone if we don't want it).
# If so, do not create more attestations. (we do not have empty pending attestations normally anyway)
if remaining_balance < 0:
return
committee = spec.get_crosslink_committee(state, spec.slot_to_epoch(slot), shard)
# Create a bitfield filled with the given count per attestation,
# exactly on the right-most part of the committee field.
aggregation_bits = [0] * len(committee)
for v in range(len(committee) * 2 // 3 + 1):
if remaining_balance > 0:
remaining_balance -= state.validators[v].effective_balance
aggregation_bits[v] = 1
else:
break
# remove just one attester to make the marginal support insufficient
if not sufficient_support:
aggregation_bits[aggregation_bits.index(1)] = 0
attestations.append(spec.PendingAttestation(
aggregation_bits=aggregation_bits,
data=spec.AttestationData(
beacon_block_root=b'\xff' * 32, # irrelevant to testing
source=source,
target=target,
crosslink=spec.Crosslink(shard=shard)
),
inclusion_delay=1,
))
def get_checkpoints(spec, epoch):
c1 = None if epoch < 1 else spec.Checkpoint(epoch=epoch - 1, root=b'\xaa' * 32)
c2 = None if epoch < 2 else spec.Checkpoint(epoch=epoch - 2, root=b'\xbb' * 32)
c3 = None if epoch < 3 else spec.Checkpoint(epoch=epoch - 3, root=b'\xcc' * 32)
c4 = None if epoch < 4 else spec.Checkpoint(epoch=epoch - 4, root=b'\xdd' * 32)
c5 = None if epoch < 5 else spec.Checkpoint(epoch=epoch - 5, root=b'\xee' * 32)
return c1, c2, c3, c4, c5
def put_checkpoints_in_block_roots(spec, state, checkpoints):
for c in checkpoints:
state.block_roots[spec.get_epoch_start_slot(c.epoch) % spec.SLOTS_PER_HISTORICAL_ROOT] = c.root
def finalize_on_234(spec, state, epoch, sufficient_support):
assert epoch > 4
state.slot = (spec.SLOTS_PER_EPOCH * epoch) - 1 # skip ahead to just before epoch
# 43210 -- epochs ago
# 3210x -- justification bitfield indices
# 11*0. -- justification bitfield contents, . = this epoch, * is being justified now
# checkpoints for the epochs ago:
c1, c2, c3, c4, _ = get_checkpoints(spec, epoch)
put_checkpoints_in_block_roots(spec, state, [c1, c2, c3, c4])
old_finalized = state.finalized_checkpoint
state.previous_justified_checkpoint = c4
state.current_justified_checkpoint = c3
state.justification_bits = spec.Bitvector[spec.JUSTIFICATION_BITS_LENGTH]()
state.justification_bits[1:3] = [1, 1] # mock 3rd and 4th latest epochs as justified (indices are pre-shift)
# mock the 2nd latest epoch as justifiable, with 4th as source
add_mock_attestations(spec, state,
epoch=epoch - 2,
source=c4,
target=c2,
sufficient_support=sufficient_support)
# process!
yield from run_process_just_and_fin(spec, state)
assert state.previous_justified_checkpoint == c3 # changed to old current
if sufficient_support:
assert state.current_justified_checkpoint == c2 # changed to 2nd latest
assert state.finalized_checkpoint == c4 # finalized old previous justified epoch
else:
assert state.current_justified_checkpoint == c3 # still old current
assert state.finalized_checkpoint == old_finalized # no new finalized
def finalize_on_23(spec, state, epoch, sufficient_support):
assert epoch > 3
state.slot = (spec.SLOTS_PER_EPOCH * epoch) - 1 # skip ahead to just before epoch
# 43210 -- epochs ago
# 210xx -- justification bitfield indices (pre shift)
# 3210x -- justification bitfield indices (post shift)
# 01*0. -- justification bitfield contents, . = this epoch, * is being justified now
# checkpoints for the epochs ago:
c1, c2, c3, _, _ = get_checkpoints(spec, epoch)
put_checkpoints_in_block_roots(spec, state, [c1, c2, c3])
old_finalized = state.finalized_checkpoint
state.previous_justified_checkpoint = c3
state.current_justified_checkpoint = c3
state.justification_bits = spec.Bitvector[spec.JUSTIFICATION_BITS_LENGTH]()
state.justification_bits[1] = 1 # mock 3rd latest epoch as justified (index is pre-shift)
# mock the 2nd latest epoch as justifiable, with 3rd as source
add_mock_attestations(spec, state,
epoch=epoch - 2,
source=c3,
target=c2,
sufficient_support=sufficient_support)
# process!
yield from run_process_just_and_fin(spec, state)
assert state.previous_justified_checkpoint == c3 # changed to old current
if sufficient_support:
assert state.current_justified_checkpoint == c2 # changed to 2nd latest
assert state.finalized_checkpoint == c3 # finalized old previous justified epoch
else:
assert state.current_justified_checkpoint == c3 # still old current
assert state.finalized_checkpoint == old_finalized # no new finalized
def finalize_on_123(spec, state, epoch, sufficient_support):
assert epoch > 5
state.slot = (spec.SLOTS_PER_EPOCH * epoch) - 1 # skip ahead to just before epoch
# 43210 -- epochs ago
# 210xx -- justification bitfield indices (pre shift)
# 3210x -- justification bitfield indices (post shift)
# 011*. -- justification bitfield contents, . = this epoch, * is being justified now
# checkpoints for the epochs ago:
c1, c2, c3, c4, c5 = get_checkpoints(spec, epoch)
put_checkpoints_in_block_roots(spec, state, [c1, c2, c3, c4, c5])
old_finalized = state.finalized_checkpoint
state.previous_justified_checkpoint = c5
state.current_justified_checkpoint = c3
state.justification_bits = spec.Bitvector[spec.JUSTIFICATION_BITS_LENGTH]()
state.justification_bits[1] = 1 # mock 3rd latest epochs as justified (index is pre-shift)
# mock the 2nd latest epoch as justifiable, with 5th as source
add_mock_attestations(spec, state,
epoch=epoch - 2,
source=c5,
target=c2,
sufficient_support=sufficient_support)
# mock the 1st latest epoch as justifiable, with 3rd as source
add_mock_attestations(spec, state,
epoch=epoch - 1,
source=c3,
target=c1,
sufficient_support=sufficient_support)
# process!
yield from run_process_just_and_fin(spec, state)
assert state.previous_justified_checkpoint == c3 # changed to old current
if sufficient_support:
assert state.current_justified_checkpoint == c1 # changed to 1st latest
assert state.finalized_checkpoint == c3 # finalized old current
else:
assert state.current_justified_checkpoint == c3 # still old current
assert state.finalized_checkpoint == old_finalized # no new finalized
def finalize_on_12(spec, state, epoch, sufficient_support):
assert epoch > 2
state.slot = (spec.SLOTS_PER_EPOCH * epoch) - 1 # skip ahead to just before epoch
# 43210 -- epochs ago
# 210xx -- justification bitfield indices (pre shift)
# 3210x -- justification bitfield indices (post shift)
# 001*. -- justification bitfield contents, . = this epoch, * is being justified now
# checkpoints for the epochs ago:
c1, c2, _, _, _ = get_checkpoints(spec, epoch)
put_checkpoints_in_block_roots(spec, state, [c1, c2])
old_finalized = state.finalized_checkpoint
state.previous_justified_checkpoint = c2
state.current_justified_checkpoint = c2
state.justification_bits = spec.Bitvector[spec.JUSTIFICATION_BITS_LENGTH]()
state.justification_bits[0] = 1 # mock 2nd latest epoch as justified (this is pre-shift)
# mock the 1st latest epoch as justifiable, with 2nd as source
add_mock_attestations(spec, state,
epoch=epoch - 1,
source=c2,
target=c1,
sufficient_support=sufficient_support)
# process!
yield from run_process_just_and_fin(spec, state)
assert state.previous_justified_checkpoint == c2 # changed to old current
if sufficient_support:
assert state.current_justified_checkpoint == c1 # changed to 1st latest
assert state.finalized_checkpoint == c2 # finalized previous justified epoch
else:
assert state.current_justified_checkpoint == c2 # still old current
assert state.finalized_checkpoint == old_finalized # no new finalized
@with_all_phases
@spec_state_test
def test_234_ok_support(spec, state):
yield from finalize_on_234(spec, state, 5, True)
@with_all_phases
@spec_state_test
def test_234_poor_support(spec, state):
yield from finalize_on_234(spec, state, 5, False)
@with_all_phases
@spec_state_test
def test_23_ok_support(spec, state):
yield from finalize_on_23(spec, state, 4, True)
@with_all_phases
@spec_state_test
def test_23_poor_support(spec, state):
yield from finalize_on_23(spec, state, 4, False)
@with_all_phases
@spec_state_test
def test_123_ok_support(spec, state):
yield from finalize_on_123(spec, state, 6, True)
@with_all_phases
@spec_state_test
def test_123_poor_support(spec, state):
yield from finalize_on_123(spec, state, 6, False)
@with_all_phases
@spec_state_test
def test_12_ok_support(spec, state):
yield from finalize_on_12(spec, state, 3, True)
@with_all_phases
@spec_state_test
def test_12_poor_support(spec, state):
yield from finalize_on_12(spec, state, 3, False)

View File

@@ -1,46 +1,25 @@
from eth2spec.test.helpers.block import build_empty_block_for_next_slot, sign_block
from eth2spec.test.helpers.state import next_epoch, state_transition_and_sign_block
from eth2spec.test.helpers.state import next_epoch
from eth2spec.test.context import spec_state_test, with_all_phases
from eth2spec.test.phase_0.epoch_processing.run_epoch_process_base import run_epoch_processing_with
def run_process_registry_updates(spec, 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(spec, state)
block.slot = slot
sign_block(spec, state, block)
state_transition_and_sign_block(spec, state, block)
def run_process_registry_updates(spec, state):
yield from run_epoch_processing_with(spec, state, 'process_registry_updates')
# cache state before epoch transition
spec.process_slot(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
spec.process_registry_updates(state)
yield 'post', state
def mock_deposit(spec, state, index):
assert spec.is_active_validator(state.validators[index], spec.get_current_epoch(state))
state.validators[index].activation_eligibility_epoch = spec.FAR_FUTURE_EPOCH
state.validators[index].activation_epoch = spec.FAR_FUTURE_EPOCH
state.validators[index].effective_balance = spec.MAX_EFFECTIVE_BALANCE
assert not spec.is_active_validator(state.validators[index], spec.get_current_epoch(state))
@with_all_phases
@spec_state_test
def test_activation(spec, state):
index = 0
assert spec.is_active_validator(state.validators[index], spec.get_current_epoch(state))
# Mock a new deposit
state.validators[index].activation_eligibility_epoch = spec.FAR_FUTURE_EPOCH
state.validators[index].activation_epoch = spec.FAR_FUTURE_EPOCH
state.validators[index].effective_balance = spec.MAX_EFFECTIVE_BALANCE
assert not spec.is_active_validator(state.validators[index], spec.get_current_epoch(state))
mock_deposit(spec, state, index)
for _ in range(spec.ACTIVATION_EXIT_DELAY + 1):
next_epoch(spec, state)
@@ -49,10 +28,39 @@ def test_activation(spec, state):
assert state.validators[index].activation_eligibility_epoch != spec.FAR_FUTURE_EPOCH
assert state.validators[index].activation_epoch != spec.FAR_FUTURE_EPOCH
assert spec.is_active_validator(
state.validators[index],
spec.get_current_epoch(state),
)
assert spec.is_active_validator(state.validators[index], spec.get_current_epoch(state))
@with_all_phases
@spec_state_test
def test_activation_queue_sorting(spec, state):
mock_activations = 10
epoch = spec.get_current_epoch(state)
for i in range(mock_activations):
mock_deposit(spec, state, i)
state.validators[i].activation_eligibility_epoch = epoch + 1
# give the last priority over the others
state.validators[mock_activations - 1].activation_eligibility_epoch = epoch
# make sure we are hitting the churn
churn_limit = spec.get_churn_limit(state)
assert mock_activations > churn_limit
yield from run_process_registry_updates(spec, state)
# the first got in as second
assert state.validators[0].activation_epoch != spec.FAR_FUTURE_EPOCH
# the prioritized got in as first
assert state.validators[mock_activations - 1].activation_epoch != spec.FAR_FUTURE_EPOCH
# the second last is at the end of the queue, and did not make the churn,
# hence is not assigned an activation_epoch yet.
assert state.validators[mock_activations - 2].activation_epoch == spec.FAR_FUTURE_EPOCH
# the one at churn_limit - 1 did not make it, it was out-prioritized
assert state.validators[churn_limit - 1].activation_epoch == spec.FAR_FUTURE_EPOCH
# but the the one in front of the above did
assert state.validators[churn_limit - 2].activation_epoch != spec.FAR_FUTURE_EPOCH
@with_all_phases

View File

@@ -0,0 +1,125 @@
from eth2spec.test.context import spec_state_test, with_all_phases
from eth2spec.test.phase_0.epoch_processing.run_epoch_process_base import (
run_epoch_processing_with, run_epoch_processing_to
)
def run_process_slashings(spec, state):
yield from run_epoch_processing_with(spec, state, 'process_slashings')
def slash_validators(spec, state, indices, out_epochs):
total_slashed_balance = 0
for i, out_epoch in zip(indices, out_epochs):
v = state.validators[i]
v.slashed = True
spec.initiate_validator_exit(state, i)
v.withdrawable_epoch = out_epoch
total_slashed_balance += v.effective_balance
state.slashings[
spec.get_current_epoch(state) % spec.EPOCHS_PER_SLASHINGS_VECTOR
] = total_slashed_balance
@with_all_phases
@spec_state_test
def test_max_penalties(spec, state):
slashed_count = (len(state.validators) // 3) + 1
out_epoch = spec.get_current_epoch(state) + (spec.EPOCHS_PER_SLASHINGS_VECTOR // 2)
slashed_indices = list(range(slashed_count))
slash_validators(spec, state, slashed_indices, [out_epoch] * slashed_count)
total_balance = spec.get_total_active_balance(state)
total_penalties = sum(state.slashings)
assert total_balance // 3 <= total_penalties
yield from run_process_slashings(spec, state)
for i in slashed_indices:
assert state.balances[i] == 0
@with_all_phases
@spec_state_test
def test_small_penalty(spec, state):
# Just the bare minimum for this one validator
state.balances[0] = state.validators[0].effective_balance = spec.EJECTION_BALANCE
# All the other validators get the maximum.
for i in range(1, len(state.validators)):
state.validators[i].effective_balance = state.balances[i] = spec.MAX_EFFECTIVE_BALANCE
out_epoch = spec.get_current_epoch(state) + (spec.EPOCHS_PER_SLASHINGS_VECTOR // 2)
slash_validators(spec, state, [0], [out_epoch])
total_balance = spec.get_total_active_balance(state)
total_penalties = sum(state.slashings)
assert total_balance // 3 > total_penalties
run_epoch_processing_to(spec, state, 'process_slashings')
pre_slash_balances = list(state.balances)
yield 'pre', state
spec.process_slashings(state)
yield 'post', state
assert state.balances[0] == pre_slash_balances[0] - (state.validators[0].effective_balance
* 3 * total_penalties // total_balance)
@with_all_phases
@spec_state_test
def test_scaled_penalties(spec, state):
# skip to next epoch
state.slot = spec.SLOTS_PER_EPOCH
# Also mock some previous slashings, so that we test to have the delta in the penalties computation.
base = spec.EJECTION_BALANCE
incr = spec.EFFECTIVE_BALANCE_INCREMENT
# Just add some random slashings. non-zero slashings are at least the minimal effective balance.
state.slashings[0] = base + (incr * 12)
state.slashings[4] = base + (incr * 3)
state.slashings[5] = base + (incr * 6)
state.slashings[spec.EPOCHS_PER_SLASHINGS_VECTOR - 1] = base + (incr * 7)
slashed_count = len(state.validators) // 4
assert slashed_count > 10
# make the balances non-uniform.
# Otherwise it would just be a simple 3/4 balance slashing. Test the per-validator scaled penalties.
diff = spec.MAX_EFFECTIVE_BALANCE - base
increments = diff // incr
for i in range(10):
state.validators[i].effective_balance = base + (incr * (i % increments))
assert state.validators[i].effective_balance <= spec.MAX_EFFECTIVE_BALANCE
# add/remove some, see if balances different than the effective balances are picked up
state.balances[i] = state.validators[i].effective_balance + i - 5
total_balance = spec.get_total_active_balance(state)
out_epoch = spec.get_current_epoch(state) + (spec.EPOCHS_PER_SLASHINGS_VECTOR // 2)
slashed_indices = list(range(slashed_count))
# Process up to the sub-transition, then Hi-jack and get the balances.
# We just want to test the slashings.
# But we are not interested in the other balance changes during the same epoch transition.
run_epoch_processing_to(spec, state, 'process_slashings')
pre_slash_balances = list(state.balances)
slash_validators(spec, state, slashed_indices, [out_epoch] * slashed_count)
yield 'pre', state
spec.process_slashings(state)
yield 'post', state
total_penalties = sum(state.slashings)
for i in slashed_indices:
v = state.validators[i]
penalty = v.effective_balance * total_penalties * 3 // total_balance
assert state.balances[i] == pre_slash_balances[i] - penalty

View File

@@ -4,15 +4,46 @@ from eth2spec.utils.ssz.ssz_impl import signing_root
from eth2spec.utils.bls import bls_sign
from eth2spec.test.helpers.state import get_balance, state_transition_and_sign_block
# from eth2spec.test.helpers.transfers import get_valid_transfer
from eth2spec.test.helpers.block import build_empty_block_for_next_slot, sign_block
from eth2spec.test.helpers.block import build_empty_block_for_next_slot, build_empty_block, sign_block
from eth2spec.test.helpers.keys import privkeys, pubkeys
from eth2spec.test.helpers.attester_slashings import get_valid_attester_slashing
from eth2spec.test.helpers.proposer_slashings import get_valid_proposer_slashing
from eth2spec.test.helpers.attestations import get_valid_attestation
from eth2spec.test.helpers.deposits import prepare_state_and_deposit
from eth2spec.test.context import spec_state_test, with_all_phases
from eth2spec.test.context import spec_state_test, with_all_phases, expect_assertion_error
@with_all_phases
@spec_state_test
def test_prev_slot_block_transition(spec, state):
# Go to clean slot
spec.process_slots(state, state.slot + 1)
# Make a block for it
block = build_empty_block(spec, state, slot=state.slot, signed=True)
# Transition to next slot, above block will not be invalid on top of new state.
spec.process_slots(state, state.slot + 1)
yield 'pre', state
expect_assertion_error(lambda: state_transition_and_sign_block(spec, state, block))
yield 'blocks', [block]
yield 'post', None
@with_all_phases
@spec_state_test
def test_same_slot_block_transition(spec, state):
# Same slot on top of pre-state, but move out of slot 0 first.
spec.process_slots(state, state.slot + 1)
block = build_empty_block(spec, state, slot=state.slot, signed=True)
yield 'pre', state
state_transition_and_sign_block(spec, state, block)
yield 'blocks', [block]
yield 'post', state
@with_all_phases
@@ -35,6 +66,22 @@ def test_empty_block_transition(spec, state):
assert spec.get_randao_mix(state, spec.get_current_epoch(state)) != spec.ZERO_HASH
@with_all_phases
@spec_state_test
def test_invalid_state_root(spec, state):
yield 'pre', state
block = build_empty_block_for_next_slot(spec, state)
block.state_root = b"\xaa" * 32
sign_block(spec, state, block)
expect_assertion_error(
lambda: spec.state_transition(state, block, validate_state_root=True))
yield 'blocks', [block]
yield 'post', None
@with_all_phases
@spec_state_test
def test_skipped_slots(spec, state):
@@ -76,26 +123,29 @@ def test_empty_epoch_transition(spec, state):
assert spec.get_block_root_at_slot(state, slot) == block.parent_root
# @with_all_phases
# @spec_state_test
# def test_empty_epoch_transition_not_finalizing(spec, state):
# # copy for later balance lookups.
# pre_state = deepcopy(state)
# yield 'pre', state
@with_all_phases
@spec_state_test
def test_empty_epoch_transition_not_finalizing(spec, state):
# Don't run for non-minimal configs, it takes very long, and the effect
# of calling finalization/justification is just the same as with the minimal configuration.
if spec.SLOTS_PER_EPOCH > 8:
return
# block = build_empty_block_for_next_slot(spec, state)
# block.slot += spec.SLOTS_PER_EPOCH * 5
# sign_block(spec, state, block, proposer_index=0)
# copy for later balance lookups.
pre_balances = list(state.balances)
yield 'pre', state
# state_transition_and_sign_block(spec, state, block)
spec.process_slots(state, state.slot + (spec.SLOTS_PER_EPOCH * 5))
block = build_empty_block_for_next_slot(spec, state, signed=True)
state_transition_and_sign_block(spec, state, block)
# yield 'blocks', [block]
# yield 'post', state
yield 'blocks', [block]
yield 'post', state
# assert state.slot == block.slot
# assert state.finalized_epoch < spec.get_current_epoch(state) - 4
# for index in range(len(state.validators)):
# assert get_balance(state, index) < get_balance(pre_state, index)
assert state.slot == block.slot
assert state.finalized_checkpoint.epoch < spec.get_current_epoch(state) - 4
for index in range(len(state.validators)):
assert state.balances[index] < pre_balances[index]
@with_all_phases
@@ -172,7 +222,27 @@ def test_attester_slashing(spec, state):
)
# TODO update functions below to be like above, i.e. with @spec_state_test and yielding data to put into the test vector
@with_all_phases
@spec_state_test
def test_expected_deposit_in_block(spec, state):
# Make the state expect a deposit, then don't provide it.
state.eth1_data.deposit_count += 1
yield 'pre', state
block = build_empty_block_for_next_slot(spec, state)
sign_block(spec, state, block)
bad = False
try:
state_transition_and_sign_block(spec, state, block)
bad = True
except AssertionError:
pass
if bad:
raise AssertionError("expected deposit was not enforced")
yield 'blocks', [block]
yield 'post', None
@with_all_phases
@spec_state_test
@@ -376,6 +446,7 @@ def test_historical_batch(spec, state):
yield 'pre', state
block = build_empty_block_for_next_slot(spec, state, signed=True)
sign_block(spec, state, block)
state_transition_and_sign_block(spec, state, block)
yield 'blocks', [block]
@@ -386,29 +457,78 @@ def test_historical_batch(spec, state):
assert len(state.historical_roots) == pre_historical_roots_len + 1
# @with_all_phases
# @spec_state_test
# def test_eth1_data_votes(spec, state):
# yield 'pre', state
@with_all_phases
@spec_state_test
def test_eth1_data_votes_consensus(spec, state):
# Don't run when it will take very, very long to simulate. Minimal configuration suffices.
if spec.SLOTS_PER_ETH1_VOTING_PERIOD > 16:
return
# expected_votes = 0
# assert len(state.eth1_data_votes) == expected_votes
offset_block = build_empty_block(spec, state, slot=spec.SLOTS_PER_ETH1_VOTING_PERIOD - 1)
sign_block(spec, state, offset_block)
state_transition_and_sign_block(spec, state, offset_block)
yield 'pre', state
# blocks = []
# for _ in range(spec.SLOTS_PER_ETH1_VOTING_PERIOD - 1):
# block = build_empty_block_for_next_slot(spec, state)
# state_transition_and_sign_block(spec, state, block)
# expected_votes += 1
# assert len(state.eth1_data_votes) == expected_votes
# blocks.append(block)
a = b'\xaa' * 32
b = b'\xbb' * 32
c = b'\xcc' * 32
# block = build_empty_block_for_next_slot(spec, state)
# blocks.append(block)
blocks = []
# state_transition_and_sign_block(spec, state, block)
for i in range(0, spec.SLOTS_PER_ETH1_VOTING_PERIOD):
block = build_empty_block_for_next_slot(spec, state)
# wait for over 50% for A, then start voting B
block.body.eth1_data.block_hash = b if i * 2 > spec.SLOTS_PER_ETH1_VOTING_PERIOD else a
sign_block(spec, state, block)
state_transition_and_sign_block(spec, state, block)
blocks.append(block)
# yield 'blocks', [block]
# yield 'post', state
assert len(state.eth1_data_votes) == spec.SLOTS_PER_ETH1_VOTING_PERIOD
assert state.eth1_data.block_hash == a
# assert state.slot % spec.SLOTS_PER_ETH1_VOTING_PERIOD == 0
# assert len(state.eth1_data_votes) == 1
# transition to next eth1 voting period
block = build_empty_block_for_next_slot(spec, state)
block.body.eth1_data.block_hash = c
sign_block(spec, state, block)
state_transition_and_sign_block(spec, state, block)
blocks.append(block)
yield 'blocks', blocks
yield 'post', state
assert state.eth1_data.block_hash == a
assert state.slot % spec.SLOTS_PER_ETH1_VOTING_PERIOD == 0
assert len(state.eth1_data_votes) == 1
assert state.eth1_data_votes[0].block_hash == c
@with_all_phases
@spec_state_test
def test_eth1_data_votes_no_consensus(spec, state):
# Don't run when it will take very, very long to simulate. Minimal configuration suffices.
if spec.SLOTS_PER_ETH1_VOTING_PERIOD > 16:
return
offset_block = build_empty_block(spec, state, slot=spec.SLOTS_PER_ETH1_VOTING_PERIOD - 1)
sign_block(spec, state, offset_block)
state_transition_and_sign_block(spec, state, offset_block)
yield 'pre', state
a = b'\xaa' * 32
b = b'\xbb' * 32
blocks = []
for i in range(0, spec.SLOTS_PER_ETH1_VOTING_PERIOD):
block = build_empty_block_for_next_slot(spec, state)
# wait for precisely 50% for A, then start voting B for other 50%
block.body.eth1_data.block_hash = b if i * 2 >= spec.SLOTS_PER_ETH1_VOTING_PERIOD else a
sign_block(spec, state, block)
state_transition_and_sign_block(spec, state, block)
blocks.append(block)
assert len(state.eth1_data_votes) == spec.SLOTS_PER_ETH1_VOTING_PERIOD
assert state.eth1_data.block_hash == b'\x00' * 32
yield 'blocks', blocks
yield 'post', state