From 2017b6126514bc0c873630d654e7951e8fb9c347 Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Tue, 22 Mar 2022 13:37:17 -0600 Subject: [PATCH] test address_change --- specs/capella/beacon-chain.md | 2 +- .../test_process_bls_to_execution_change.py | 175 ++++++++++++++++-- .../pyspec/eth2spec/test/helpers/genesis.py | 7 +- 3 files changed, 164 insertions(+), 20 deletions(-) diff --git a/specs/capella/beacon-chain.md b/specs/capella/beacon-chain.md index 443051114..a749aec26 100644 --- a/specs/capella/beacon-chain.md +++ b/specs/capella/beacon-chain.md @@ -421,7 +421,7 @@ def process_bls_to_execution_change(state: BeaconState, validator.withdrawal_credentials = ( ETH1_ADDRESS_WITHDRAWAL_PREFIX - + 0x00 * 11 + + (0x00).to_bytes(11, 'little') + address_change.to_execution_address ) ``` diff --git a/tests/core/pyspec/eth2spec/test/capella/block_processing/test_process_bls_to_execution_change.py b/tests/core/pyspec/eth2spec/test/capella/block_processing/test_process_bls_to_execution_change.py index 1a7fbfa81..01ed7b8f1 100644 --- a/tests/core/pyspec/eth2spec/test/capella/block_processing/test_process_bls_to_execution_change.py +++ b/tests/core/pyspec/eth2spec/test/capella/block_processing/test_process_bls_to_execution_change.py @@ -1,10 +1,10 @@ -from eth2spec.test.helpers.execution_payload import ( - build_empty_execution_payload, -) +from eth2spec.utils import bls +from eth2spec.test.helpers.keys import pubkeys, privkeys, pubkey_to_privkey from eth2spec.test.context import spec_state_test, expect_assertion_error, with_capella_and_later -def run_bls_to_execution_change_processing(spec, state, address_change, valid=True): + +def run_bls_to_execution_change_processing(spec, state, signed_address_change, valid=True): """ Run ``process_bls_to_execution_change``, yielding: - pre-state ('pre') @@ -15,33 +15,176 @@ def run_bls_to_execution_change_processing(spec, state, address_change, valid=Tr # yield pre-state yield 'pre', state - yield 'address_change', address_change + yield 'address_change', signed_address_change # If the address_change is invalid, processing is aborted, and there is no post-state. if not valid: - expect_assertion_error(lambda: spec.process_bls_to_execution_change(state, attestation)) + expect_assertion_error(lambda: spec.process_bls_to_execution_change(state, signed_address_change)) yield 'post', None return # process address change - spec.process_bls_to_execution_change(state, attestation) + spec.process_bls_to_execution_change(state, signed_address_change) # Make sure the address change has been processed - assert state.withdrawal_credentials[:1] == ETH1_ADDRESS_WITHDRAWAL_PREFIX - assert state.withdrawal_credentials[1:12] == b'\x00' * 11 - assert state.withdrawal_credentials[12:] == address_change.to_execution_address + validator_index = signed_address_change.message.validator_index + validator = state.validators[validator_index] + assert validator.withdrawal_credentials[:1] == spec.ETH1_ADDRESS_WITHDRAWAL_PREFIX + assert validator.withdrawal_credentials[1:12] == b'\x00' * 11 + assert validator.withdrawal_credentials[12:] == signed_address_change.message.to_execution_address # yield post-state yield 'post', state -@with_capella_and_later -@spec_state_test -def test_success(spec, state): +def get_signed_address_change(spec, state, validator_index=None, withdrawal_pubkey=None): + if validator_index is None: + validator_index = 0 + + if withdrawal_pubkey is None: + key_index = -1 - validator_index + withdrawal_pubkey = pubkeys[key_index] + withdrawal_privkey = privkeys[key_index] + else: + withdrawal_privkey = pubkey_to_privkey[withdrawal_pubkey] + + domain = spec.get_domain(state, spec.DOMAIN_BLS_TO_EXECUTION_CHANGE) address_change = spec.BLSToExecutionChange( - validator_index=0, - from_bls_pubkey=TEST, + validator_index=validator_index, + from_bls_pubkey=withdrawal_pubkey, to_execution_address=b'\x42' * 20, ) - yield from run_bls_to_execution_change_processing(spec, state, address_change) + signing_root = spec.compute_signing_root(address_change, domain) + return spec.SignedBLSToExecutionChange( + message=address_change, + signature=bls.Sign(withdrawal_privkey, signing_root), + ) + + +@with_capella_and_later +@spec_state_test +def test_success(spec, state): + signed_address_change = get_signed_address_change(spec, state) + yield from run_bls_to_execution_change_processing(spec, state, signed_address_change) + + +@with_capella_and_later +@spec_state_test +def test_success_not_activated(spec, state): + validator_index = 3 + validator = state.validators[validator_index] + validator.activation_eligibility_epoch += 4 + validator.activation_epoch = spec.FAR_FUTURE_EPOCH + + assert not spec.is_active_validator(validator, spec.get_current_epoch(state)) + + signed_address_change = get_signed_address_change(spec, state) + yield from run_bls_to_execution_change_processing(spec, state, signed_address_change) + + assert not spec.is_fully_withdrawable_validator(state.validators[validator_index], spec.get_current_epoch(state)) + + +@with_capella_and_later +@spec_state_test +def test_success_in_activation_queue(spec, state): + validator_index = 3 + validator = state.validators[validator_index] + validator.activation_eligibility_epoch = spec.get_current_epoch(state) + validator.activation_epoch += 4 + + assert not spec.is_active_validator(validator, spec.get_current_epoch(state)) + + signed_address_change = get_signed_address_change(spec, state) + yield from run_bls_to_execution_change_processing(spec, state, signed_address_change) + + assert not spec.is_fully_withdrawable_validator(state.validators[validator_index], spec.get_current_epoch(state)) + + +@with_capella_and_later +@spec_state_test +def test_success_in_exit_queue(spec, state): + validator_index = 3 + spec.initiate_validator_exit(state, validator_index) + + assert spec.is_active_validator(state.validators[validator_index], spec.get_current_epoch(state)) + assert spec.get_current_epoch(state) < state.validators[validator_index].exit_epoch + + signed_address_change = get_signed_address_change(spec, state, validator_index=validator_index) + yield from run_bls_to_execution_change_processing(spec, state, signed_address_change) + + +@with_capella_and_later +@spec_state_test +def test_success_exited(spec, state): + validator_index = 4 + validator = state.validators[validator_index] + validator.exit_epoch = spec.get_current_epoch(state) + + assert not spec.is_active_validator(validator, spec.get_current_epoch(state)) + + signed_address_change = get_signed_address_change(spec, state, validator_index=validator_index) + yield from run_bls_to_execution_change_processing(spec, state, signed_address_change) + + assert not spec.is_fully_withdrawable_validator(state.validators[validator_index], spec.get_current_epoch(state)) + + +@with_capella_and_later +@spec_state_test +def test_success_withdrawable(spec, state): + validator_index = 4 + validator = state.validators[validator_index] + validator.exit_epoch = spec.get_current_epoch(state) + validator.withdrawable_epoch = spec.get_current_epoch(state) + + assert not spec.is_active_validator(validator, spec.get_current_epoch(state)) + + signed_address_change = get_signed_address_change(spec, state, validator_index=validator_index) + yield from run_bls_to_execution_change_processing(spec, state, signed_address_change) + + assert spec.is_fully_withdrawable_validator(state.validators[validator_index], spec.get_current_epoch(state)) + + +@with_capella_and_later +@spec_state_test +def test_fail_val_index_out_of_range(spec, state): + # Create for one validator beyond the validator list length + signed_address_change = get_signed_address_change(spec, state, validator_index=len(state.validators)) + + yield from run_bls_to_execution_change_processing(spec, state, signed_address_change, valid=False) + + +@with_capella_and_later +@spec_state_test +def test_fail_already_0x01(spec, state): + # Create for one validator beyond the validator list length + validator_index = len(state.validators) // 2 + validator = state.validators[validator_index] + validator.withdrawal_credentials = b'\x01' + b'\x00' * 11 + b'\x23' * 20 + signed_address_change = get_signed_address_change(spec, state, validator_index=validator_index) + + yield from run_bls_to_execution_change_processing(spec, state, signed_address_change, valid=False) + + +@with_capella_and_later +@spec_state_test +def test_fail_incorrect_from_bls_pubkey(spec, state): + # Create for one validator beyond the validator list length + validator_index = 2 + signed_address_change = get_signed_address_change( + spec, state, + validator_index=validator_index, + withdrawal_pubkey=pubkeys[0], + ) + + yield from run_bls_to_execution_change_processing(spec, state, signed_address_change, valid=False) + + +@with_capella_and_later +@spec_state_test +def test_fail_bad_signature(spec, state): + signed_address_change = get_signed_address_change(spec, state) + # Mutate sigature + signed_address_change.signature = spec.BLSSignature(b'\x42' * 96) + + yield from run_bls_to_execution_change_processing(spec, state, signed_address_change, valid=False) diff --git a/tests/core/pyspec/eth2spec/test/helpers/genesis.py b/tests/core/pyspec/eth2spec/test/helpers/genesis.py index 1ca408598..83994c409 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/genesis.py +++ b/tests/core/pyspec/eth2spec/test/helpers/genesis.py @@ -6,11 +6,12 @@ from eth2spec.test.helpers.keys import pubkeys def build_mock_validator(spec, i: int, balance: int): - pubkey = pubkeys[i] + active_pubkey = pubkeys[i] + withdrawal_pubkey = pubkeys[-1 - i] # insecurely use pubkey as withdrawal key as well - withdrawal_credentials = spec.BLS_WITHDRAWAL_PREFIX + spec.hash(pubkey)[1:] + withdrawal_credentials = spec.BLS_WITHDRAWAL_PREFIX + spec.hash(withdrawal_pubkey)[1:] validator = spec.Validator( - pubkey=pubkeys[i], + pubkey=active_pubkey, withdrawal_credentials=withdrawal_credentials, activation_eligibility_epoch=spec.FAR_FUTURE_EPOCH, activation_epoch=spec.FAR_FUTURE_EPOCH,