Merge pull request #3112 from ethereum/double-bls-changes
Add more double/duplicate operations tests
This commit is contained in:
commit
c345f3063a
|
@ -21,9 +21,13 @@ from eth2spec.test.helpers.withdrawals import (
|
||||||
from eth2spec.test.helpers.voluntary_exits import prepare_signed_exits
|
from eth2spec.test.helpers.voluntary_exits import prepare_signed_exits
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# BLSToExecutionChange
|
||||||
|
#
|
||||||
|
|
||||||
@with_phases([CAPELLA])
|
@with_phases([CAPELLA])
|
||||||
@spec_state_test
|
@spec_state_test
|
||||||
def test_successful_bls_change(spec, state):
|
def test_success_bls_change(spec, state):
|
||||||
index = 0
|
index = 0
|
||||||
signed_address_change = get_signed_address_change(spec, state, validator_index=index)
|
signed_address_change = get_signed_address_change(spec, state, validator_index=index)
|
||||||
pre_credentials = state.validators[index].withdrawal_credentials
|
pre_credentials = state.validators[index].withdrawal_credentials
|
||||||
|
@ -44,6 +48,82 @@ def test_successful_bls_change(spec, state):
|
||||||
assert post_credentials[12:] == signed_address_change.message.to_execution_address
|
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])
|
@with_phases([CAPELLA])
|
||||||
@spec_state_test
|
@spec_state_test
|
||||||
def test_full_withdrawal_in_epoch_transition(spec, state):
|
def test_full_withdrawal_in_epoch_transition(spec, state):
|
||||||
|
@ -112,35 +192,6 @@ def test_many_partial_withdrawals_in_epoch_transition(spec, state):
|
||||||
assert len(spec.get_expected_withdrawals(state)) == 1
|
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):
|
def _perform_valid_withdrawal(spec, state):
|
||||||
fully_withdrawable_indices, partial_withdrawals_indices = prepare_expected_withdrawals(
|
fully_withdrawable_indices, partial_withdrawals_indices = prepare_expected_withdrawals(
|
||||||
spec, state, num_partial_withdrawals=spec.MAX_WITHDRAWALS_PER_PAYLOAD * 4,
|
spec, state, num_partial_withdrawals=spec.MAX_WITHDRAWALS_PER_PAYLOAD * 4,
|
||||||
|
|
|
@ -2,7 +2,7 @@ from eth2spec.utils import bls
|
||||||
from eth2spec.test.helpers.keys import pubkeys, privkeys, pubkey_to_privkey
|
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:
|
if validator_index is None:
|
||||||
validator_index = 0
|
validator_index = 0
|
||||||
|
|
||||||
|
@ -13,11 +13,14 @@ def get_signed_address_change(spec, state, validator_index=None, withdrawal_pubk
|
||||||
else:
|
else:
|
||||||
withdrawal_privkey = pubkey_to_privkey[withdrawal_pubkey]
|
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)
|
domain = spec.get_domain(state, spec.DOMAIN_BLS_TO_EXECUTION_CHANGE)
|
||||||
address_change = spec.BLSToExecutionChange(
|
address_change = spec.BLSToExecutionChange(
|
||||||
validator_index=validator_index,
|
validator_index=validator_index,
|
||||||
from_bls_pubkey=withdrawal_pubkey,
|
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)
|
signing_root = spec.compute_signing_root(address_change, domain)
|
||||||
|
|
|
@ -433,7 +433,7 @@ def test_proposer_slashing(spec, state):
|
||||||
|
|
||||||
@with_all_phases
|
@with_all_phases
|
||||||
@spec_state_test
|
@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)
|
proposer_slashing = get_valid_proposer_slashing(spec, state, signed_1=True, signed_2=True)
|
||||||
slashed_index = proposer_slashing.signed_header_1.message.proposer_index
|
slashed_index = proposer_slashing.signed_header_1.message.proposer_index
|
||||||
assert not state.validators[slashed_index].slashed
|
assert not state.validators[slashed_index].slashed
|
||||||
|
@ -450,7 +450,7 @@ def test_double_same_proposer_slashings_same_block(spec, state):
|
||||||
|
|
||||||
@with_all_phases
|
@with_all_phases
|
||||||
@spec_state_test
|
@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]
|
slashed_index = spec.get_active_validator_indices(state, spec.get_current_epoch(state))[-1]
|
||||||
|
|
||||||
# Same validator, but different slashable offences in the same block
|
# Same validator, but different slashable offences in the same block
|
||||||
|
@ -549,7 +549,7 @@ def test_attester_slashing(spec, state):
|
||||||
|
|
||||||
@with_all_phases
|
@with_all_phases
|
||||||
@spec_state_test
|
@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:
|
if spec.MAX_ATTESTER_SLASHINGS < 2:
|
||||||
return dump_skipping_message("Skip test if config cannot handle multiple AttesterSlashings per block")
|
return dump_skipping_message("Skip test if config cannot handle multiple AttesterSlashings per block")
|
||||||
|
|
||||||
|
@ -744,6 +744,27 @@ def test_deposit_in_block(spec, state):
|
||||||
assert state.validators[validator_index].pubkey == pubkeys[validator_index]
|
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
|
@with_all_phases
|
||||||
@spec_state_test
|
@spec_state_test
|
||||||
def test_deposit_top_up(spec, state):
|
def test_deposit_top_up(spec, state):
|
||||||
|
@ -831,6 +852,49 @@ def test_attestation(spec, state):
|
||||||
assert spec.hash_tree_root(state.previous_epoch_participation) == pre_current_epoch_participation_root
|
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,
|
# After SHARDING is enabled, a committee is computed for SHARD_COMMITTEE_PERIOD slots ago,
|
||||||
# exceeding the minimal-config randao mixes memory size.
|
# exceeding the minimal-config randao mixes memory size.
|
||||||
# Applies to all voluntary-exit sanity block tests.
|
# Applies to all voluntary-exit sanity block tests.
|
||||||
|
@ -866,7 +930,7 @@ def test_voluntary_exit(spec, state):
|
||||||
|
|
||||||
@with_all_phases
|
@with_all_phases
|
||||||
@spec_state_test
|
@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]
|
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
|
# move state forward SHARD_COMMITTEE_PERIOD epochs to allow for exit
|
||||||
|
|
Loading…
Reference in New Issue