Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
111 changes: 81 additions & 30 deletions tests/core/pyspec/eth2spec/test/capella/sanity/test_blocks.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,13 @@
from eth2spec.test.helpers.voluntary_exits import prepare_signed_exits


#
# BLSToExecutionChange
#

@with_phases([CAPELLA])
@spec_state_test
def test_successful_bls_change(spec, state):
def test_success_bls_change(spec, state):
index = 0
signed_address_change = get_signed_address_change(spec, state, validator_index=index)
pre_credentials = state.validators[index].withdrawal_credentials
Expand All @@ -44,6 +48,82 @@ def test_successful_bls_change(spec, state):
assert post_credentials[12:] == signed_address_change.message.to_execution_address


@with_phases([CAPELLA])
@spec_state_test
def test_success_exit_and_bls_change(spec, state):
# move state forward SHARD_COMMITTEE_PERIOD epochs to allow for exit
state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH

index = 0
signed_address_change = get_signed_address_change(spec, state, validator_index=index)
signed_exit = prepare_signed_exits(spec, state, [index])[0]

yield 'pre', state

block = build_empty_block_for_next_slot(spec, state)
block.body.voluntary_exits.append(signed_exit)
block.body.bls_to_execution_changes.append(signed_address_change)

signed_block = state_transition_and_sign_block(spec, state, block)

yield 'blocks', [signed_block]
yield 'post', state

validator = state.validators[index]
balance = state.balances[index]
current_epoch = spec.get_current_epoch(state)
assert not spec.is_fully_withdrawable_validator(validator, balance, current_epoch)
assert validator.withdrawable_epoch < spec.FAR_FUTURE_EPOCH
assert spec.is_fully_withdrawable_validator(validator, balance, validator.withdrawable_epoch)


@with_phases([CAPELLA])
@spec_state_test
def test_invalid_duplicate_bls_changes_same_block(spec, state):
index = 0
signed_address_change = get_signed_address_change(spec, state, validator_index=index)
yield 'pre', state

block = build_empty_block_for_next_slot(spec, state)

# Double BLSToExecutionChange of the same validator
for _ in range(2):
block.body.bls_to_execution_changes.append(signed_address_change)

signed_block = state_transition_and_sign_block(spec, state, block, expect_fail=True)

yield 'blocks', [signed_block]
yield 'post', None


@with_phases([CAPELLA])
@spec_state_test
def test_invalid_two_bls_changes_of_different_addresses_same_validator_same_block(spec, state):
index = 0

signed_address_change_1 = get_signed_address_change(spec, state, validator_index=index,
to_execution_address=b'\x12' * 20)
signed_address_change_2 = get_signed_address_change(spec, state, validator_index=index,
to_execution_address=b'\x34' * 20)
assert signed_address_change_1 != signed_address_change_2

yield 'pre', state

block = build_empty_block_for_next_slot(spec, state)

block.body.bls_to_execution_changes.append(signed_address_change_1)
block.body.bls_to_execution_changes.append(signed_address_change_2)

signed_block = state_transition_and_sign_block(spec, state, block, expect_fail=True)

yield 'blocks', [signed_block]
yield 'post', None


#
# Withdrawals
#

@with_phases([CAPELLA])
@spec_state_test
def test_full_withdrawal_in_epoch_transition(spec, state):
Expand Down Expand Up @@ -112,35 +192,6 @@ def test_many_partial_withdrawals_in_epoch_transition(spec, state):
assert len(spec.get_expected_withdrawals(state)) == 1


@with_phases([CAPELLA])
@spec_state_test
def test_exit_and_bls_change(spec, state):
# move state forward SHARD_COMMITTEE_PERIOD epochs to allow for exit
state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH

index = 0
signed_address_change = get_signed_address_change(spec, state, validator_index=index)
signed_exit = prepare_signed_exits(spec, state, [index])[0]

yield 'pre', state

block = build_empty_block_for_next_slot(spec, state)
block.body.voluntary_exits.append(signed_exit)
block.body.bls_to_execution_changes.append(signed_address_change)

signed_block = state_transition_and_sign_block(spec, state, block)

yield 'blocks', [signed_block]
yield 'post', state

validator = state.validators[index]
balance = state.balances[index]
current_epoch = spec.get_current_epoch(state)
assert not spec.is_fully_withdrawable_validator(validator, balance, current_epoch)
assert validator.withdrawable_epoch < spec.FAR_FUTURE_EPOCH
assert spec.is_fully_withdrawable_validator(validator, balance, validator.withdrawable_epoch)


def _perform_valid_withdrawal(spec, state):
fully_withdrawable_indices, partial_withdrawals_indices = prepare_expected_withdrawals(
spec, state, num_partial_withdrawals=spec.MAX_WITHDRAWALS_PER_PAYLOAD * 4,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from eth2spec.test.helpers.keys import pubkeys, privkeys, pubkey_to_privkey


def get_signed_address_change(spec, state, validator_index=None, withdrawal_pubkey=None):
def get_signed_address_change(spec, state, validator_index=None, withdrawal_pubkey=None, to_execution_address=None):
if validator_index is None:
validator_index = 0

Expand All @@ -13,11 +13,14 @@ def get_signed_address_change(spec, state, validator_index=None, withdrawal_pubk
else:
withdrawal_privkey = pubkey_to_privkey[withdrawal_pubkey]

if to_execution_address is None:
to_execution_address = b'\x42' * 20

domain = spec.get_domain(state, spec.DOMAIN_BLS_TO_EXECUTION_CHANGE)
address_change = spec.BLSToExecutionChange(
validator_index=validator_index,
from_bls_pubkey=withdrawal_pubkey,
to_execution_address=b'\x42' * 20,
to_execution_address=to_execution_address,
)

signing_root = spec.compute_signing_root(address_change, domain)
Expand Down
72 changes: 68 additions & 4 deletions tests/core/pyspec/eth2spec/test/phase0/sanity/test_blocks.py
Original file line number Diff line number Diff line change
Expand Up @@ -433,7 +433,7 @@ def test_proposer_slashing(spec, state):

@with_all_phases
@spec_state_test
def test_double_same_proposer_slashings_same_block(spec, state):
def test_invalid_duplicate_proposer_slashings_same_block(spec, state):
proposer_slashing = get_valid_proposer_slashing(spec, state, signed_1=True, signed_2=True)
slashed_index = proposer_slashing.signed_header_1.message.proposer_index
assert not state.validators[slashed_index].slashed
Expand All @@ -450,7 +450,7 @@ def test_double_same_proposer_slashings_same_block(spec, state):

@with_all_phases
@spec_state_test
def test_double_similar_proposer_slashings_same_block(spec, state):
def test_invalid_similar_proposer_slashings_same_block(spec, state):
slashed_index = spec.get_active_validator_indices(state, spec.get_current_epoch(state))[-1]

# Same validator, but different slashable offences in the same block
Expand Down Expand Up @@ -549,7 +549,7 @@ def test_attester_slashing(spec, state):

@with_all_phases
@spec_state_test
def test_duplicate_attester_slashing(spec, state):
def test_invalid_duplicate_attester_slashing_same_block(spec, state):
if spec.MAX_ATTESTER_SLASHINGS < 2:
return dump_skipping_message("Skip test if config cannot handle multiple AttesterSlashings per block")

Expand Down Expand Up @@ -744,6 +744,27 @@ def test_deposit_in_block(spec, state):
assert state.validators[validator_index].pubkey == pubkeys[validator_index]


@with_all_phases
@spec_state_test
def test_invalid_duplicate_deposit_same_block(spec, state):
validator_index = len(state.validators)
amount = spec.MAX_EFFECTIVE_BALANCE
deposit = prepare_state_and_deposit(spec, state, validator_index, amount, signed=True)

yield 'pre', state

block = build_empty_block_for_next_slot(spec, state)

# The same deposit of the same validator
for _ in range(2):
block.body.deposits.append(deposit)

signed_block = state_transition_and_sign_block(spec, state, block, expect_fail=True)

yield 'blocks', [signed_block]
yield 'post', None


@with_all_phases
@spec_state_test
def test_deposit_top_up(spec, state):
Expand Down Expand Up @@ -831,6 +852,49 @@ def test_attestation(spec, state):
assert spec.hash_tree_root(state.previous_epoch_participation) == pre_current_epoch_participation_root


@with_all_phases
@spec_state_test
def test_duplicate_attestation_same_block(spec, state):
next_epoch(spec, state)

yield 'pre', state

attestation_block = build_empty_block(spec, state, state.slot + spec.MIN_ATTESTATION_INCLUSION_DELAY)

index = 0

attestation = get_valid_attestation(spec, state, index=index, signed=True)

if not is_post_altair(spec):
pre_current_attestations_len = len(state.current_epoch_attestations)

# Add to state via block transition
for _ in range(2):
attestation_block.body.attestations.append(attestation)
signed_attestation_block = state_transition_and_sign_block(spec, state, attestation_block)

if not is_post_altair(spec):
assert len(state.current_epoch_attestations) == pre_current_attestations_len + 2
# Epoch transition should move to previous_epoch_attestations
pre_current_attestations_root = spec.hash_tree_root(state.current_epoch_attestations)
else:
pre_current_epoch_participation_root = spec.hash_tree_root(state.current_epoch_participation)

epoch_block = build_empty_block(spec, state, state.slot + spec.SLOTS_PER_EPOCH)
signed_epoch_block = state_transition_and_sign_block(spec, state, epoch_block)

yield 'blocks', [signed_attestation_block, signed_epoch_block]
yield 'post', state

if not is_post_altair(spec):
assert len(state.current_epoch_attestations) == 0
assert spec.hash_tree_root(state.previous_epoch_attestations) == pre_current_attestations_root
else:
for index in range(len(state.validators)):
assert state.current_epoch_participation[index] == spec.ParticipationFlags(0b0000_0000)
assert spec.hash_tree_root(state.previous_epoch_participation) == pre_current_epoch_participation_root


# After SHARDING is enabled, a committee is computed for SHARD_COMMITTEE_PERIOD slots ago,
# exceeding the minimal-config randao mixes memory size.
# Applies to all voluntary-exit sanity block tests.
Expand Down Expand Up @@ -866,7 +930,7 @@ def test_voluntary_exit(spec, state):

@with_all_phases
@spec_state_test
def test_double_validator_exit_same_block(spec, state):
def test_invalid_duplicate_validator_exit_same_block(spec, state):
validator_index = spec.get_active_validator_indices(state, spec.get_current_epoch(state))[-1]

# move state forward SHARD_COMMITTEE_PERIOD epochs to allow for exit
Expand Down