From ad8f54ff7db197160449cb4c9271ca5ebaaa689d Mon Sep 17 00:00:00 2001 From: Mikhail Kalinin Date: Tue, 27 Aug 2024 17:26:54 +0600 Subject: [PATCH] Update pending deposits tests --- .../test_process_deposit_request.py | 4 +- .../test_apply_pending_deposit.py | 26 +- .../test_process_pending_deposits.py | 828 ++++-------------- .../pyspec/eth2spec/test/helpers/deposits.py | 91 +- .../pyspec/eth2spec/test/helpers/state.py | 5 + 5 files changed, 220 insertions(+), 734 deletions(-) diff --git a/tests/core/pyspec/eth2spec/test/electra/block_processing/test_process_deposit_request.py b/tests/core/pyspec/eth2spec/test/electra/block_processing/test_process_deposit_request.py index 1e7812903..220abc80f 100644 --- a/tests/core/pyspec/eth2spec/test/electra/block_processing/test_process_deposit_request.py +++ b/tests/core/pyspec/eth2spec/test/electra/block_processing/test_process_deposit_request.py @@ -189,7 +189,7 @@ def test_process_deposit_request_switch_to_compounding_normal(spec, state): + b'\x00' * 11 # specified 0s + b'\x59' * 20 # a 20-byte eth1 address ) - + yield from _run_deposit_request_switching_to_compounding( spec, state, @@ -219,7 +219,7 @@ def test_process_deposit_request_switch_to_compounding_with_excess(spec, state): ) state.balances[validator_index] = initial_balance state.validators[validator_index].effective_balance = initial_effective_balance - + yield from _run_deposit_request_switching_to_compounding( spec, state, diff --git a/tests/core/pyspec/eth2spec/test/electra/epoch_processing/test_apply_pending_deposit.py b/tests/core/pyspec/eth2spec/test/electra/epoch_processing/test_apply_pending_deposit.py index d2f15b0d9..cc3c2205a 100644 --- a/tests/core/pyspec/eth2spec/test/electra/epoch_processing/test_apply_pending_deposit.py +++ b/tests/core/pyspec/eth2spec/test/electra/epoch_processing/test_apply_pending_deposit.py @@ -334,6 +334,7 @@ def test_apply_pending_deposit_incorrect_withdrawal_credentials_top_up(spec, sta @with_electra_and_later @spec_state_test +@always_bls def test_apply_pending_deposit_key_validate_invalid_subgroup(spec, state): validator_index = len(state.validators) amount = spec.MIN_ACTIVATION_BALANCE @@ -348,6 +349,7 @@ def test_apply_pending_deposit_key_validate_invalid_subgroup(spec, state): @with_electra_and_later @spec_state_test +@always_bls def test_apply_pending_deposit_key_validate_invalid_decompression(spec, state): validator_index = len(state.validators) amount = spec.MIN_ACTIVATION_BALANCE @@ -366,13 +368,13 @@ def test_apply_pending_deposit_key_validate_invalid_decompression(spec, state): @spec_state_test @always_bls def test_apply_pending_deposit_ineffective_deposit_with_bad_fork_version(spec, state): - validator_index=len(state.validators) - fork_version=spec.Version('0xAaBbCcDd') + validator_index = len(state.validators) + fork_version = spec.Version('0xAaBbCcDd') pending_deposit = prepare_pending_deposit( spec, validator_index=validator_index, amount=spec.MIN_ACTIVATION_BALANCE, - fork_version=fork_version, + fork_version=fork_version, signed=True ) @@ -388,13 +390,13 @@ def test_apply_pending_deposit_with_previous_fork_version(spec, state): # NOTE: it was effective in Altair. assert state.fork.previous_version != state.fork.current_version - validator_index=len(state.validators) - fork_version=state.fork.previous_version + validator_index = len(state.validators) + fork_version = state.fork.previous_version pending_deposit = prepare_pending_deposit( spec, validator_index=validator_index, amount=spec.MIN_ACTIVATION_BALANCE, - fork_version=fork_version, + fork_version=fork_version, signed=True ) @@ -405,13 +407,13 @@ def test_apply_pending_deposit_with_previous_fork_version(spec, state): @spec_state_test @always_bls def test_ineffective_deposit_with_current_fork_version(spec, state): - validator_index=len(state.validators) - fork_version=state.fork.current_version + validator_index = len(state.validators) + fork_version = state.fork.current_version pending_deposit = prepare_pending_deposit( spec, validator_index=validator_index, amount=spec.MIN_ACTIVATION_BALANCE, - fork_version=fork_version, + fork_version=fork_version, signed=True ) @@ -424,13 +426,13 @@ def test_ineffective_deposit_with_current_fork_version(spec, state): def test_apply_pending_deposit_effective_deposit_with_genesis_fork_version(spec, state): assert spec.config.GENESIS_FORK_VERSION not in (state.fork.previous_version, state.fork.current_version) - validator_index=len(state.validators) - fork_version=state.fork.previous_version + validator_index = len(state.validators) + fork_version = spec.config.GENESIS_FORK_VERSION pending_deposit = prepare_pending_deposit( spec, validator_index=validator_index, amount=spec.MIN_ACTIVATION_BALANCE, - fork_version=spec.config.GENESIS_FORK_VERSION, + fork_version=fork_version, signed=True ) diff --git a/tests/core/pyspec/eth2spec/test/electra/epoch_processing/test_process_pending_deposits.py b/tests/core/pyspec/eth2spec/test/electra/epoch_processing/test_process_pending_deposits.py index 8f27c7db1..cc78e39d5 100644 --- a/tests/core/pyspec/eth2spec/test/electra/epoch_processing/test_process_pending_deposits.py +++ b/tests/core/pyspec/eth2spec/test/electra/epoch_processing/test_process_pending_deposits.py @@ -1,16 +1,14 @@ from eth2spec.test.helpers.epoch_processing import run_epoch_processing_with from eth2spec.test.context import ( spec_state_test, - always_bls, with_electra_and_later, ) -from eth2spec.test.helpers.deposits import ( - build_pending_deposit, - build_pending_deposit_top_up, +from eth2spec.test.helpers.deposits import prepare_pending_deposit +from eth2spec.test.helpers.state import ( + next_epoch_with_full_participation, + advance_finality_to, + set_full_participation, ) -from eth2spec.test.helpers.state import next_epoch_via_block - -from eth2spec.test.helpers.keys import pubkeys def run_process_pending_deposits(spec, state): @@ -18,365 +16,213 @@ def run_process_pending_deposits(spec, state): spec, state, 'process_pending_deposits') -@with_electra_and_later -@spec_state_test -def test_pending_deposit_under_max(spec, state): - # pick an amount that adds to less than churn limit - amount = 100 - undermax = spec.MAX_PENDING_DEPOSITS_PER_EPOCH_PROCESSING - 1 - for i in range(undermax): - print(i) - state.pending_deposits.append( - spec.PendingDeposit( - pubkey=state.validators[i].pubkey, - withdrawal_credentials=( - state.validators[i].withdrawal_credentials - ), - amount=amount, - slot=spec.GENESIS_SLOT, - ) +def _ensure_enough_churn_to_process_deposits(spec, state): + state.deposit_balance_to_consume = sum(d.amount for d in state.pending_deposits) + + +def _prepare_eth1_bridge_deprecation(spec, state, eth1_bridge_flags): + new_pending_deposits = [] + validator_index_base = len(state.validators) + deposit_request_slot = spec.Slot(1) + for index, eth1_bridge in enumerate(eth1_bridge_flags): + validator_index = validator_index_base + index + slot = spec.GENESIS_SLOT if eth1_bridge else deposit_request_slot + pending_deposit = prepare_pending_deposit( + spec, + validator_index=validator_index, + amount=spec.MIN_ACTIVATION_BALANCE, + signed=True, + slot=slot, ) - assert len(state.pending_deposits) == undermax, \ - "pending deposits is not undermax" - yield from run_process_pending_deposits(spec, state) - assert len(state.pending_deposits) == 0 - assert state.balances[0] == amount + spec.MIN_ACTIVATION_BALANCE - assert state.balances[undermax - 1] == amount + spec.MIN_ACTIVATION_BALANCE - assert state.balances[undermax] == spec.MIN_ACTIVATION_BALANCE + new_pending_deposits.append(pending_deposit) - -@with_electra_and_later -@spec_state_test -def test_pending_deposit_max(spec, state): - # pick an amount that adds to less than churn limit - amount = 100 - max = spec.MAX_PENDING_DEPOSITS_PER_EPOCH_PROCESSING - for i in range(max): - state.pending_deposits.append( - spec.PendingDeposit( - pubkey=state.validators[i].pubkey, - withdrawal_credentials=( - state.validators[i].withdrawal_credentials - ), - amount=amount, - slot=spec.GENESIS_SLOT, + # Eth1 bridge deposits instantly yield new validator records + if eth1_bridge: + spec.add_validator_to_registry( + state, + pending_deposit.pubkey, + pending_deposit.withdrawal_credentials, + spec.Gwei(0) ) - ) - assert len(state.pending_deposits) == max, \ - "pending deposits is not max" - yield from run_process_pending_deposits(spec, state) - assert len(state.pending_deposits) == 0 - assert state.balances[0] == amount + spec.MIN_ACTIVATION_BALANCE - assert state.balances[max - 1] == amount + spec.MIN_ACTIVATION_BALANCE - assert state.balances[max] == spec.MIN_ACTIVATION_BALANCE + state.eth1_deposit_index += 1 + + # Advance state to make pending deposits finalized + advance_finality_to(spec, state, spec.compute_epoch_at_slot(deposit_request_slot) + 1) + + # Add pending deposits + for pending_deposit in new_pending_deposits: + state.pending_deposits.append(pending_deposit) + + # Ensure there is enough churn to process them all + _ensure_enough_churn_to_process_deposits(spec, state) + + return state, new_pending_deposits + + +def _check_pending_deposits_induced_new_validators(spec, state, pre_validator_count, applied_pending_deposits): + assert pre_validator_count + len(applied_pending_deposits) == len(state.validators) + + eth1_bridge_deposits = [d for d in applied_pending_deposits if d.slot == spec.GENESIS_SLOT] + deposit_requests = [d for d in applied_pending_deposits if d.slot > spec.GENESIS_SLOT] + + # Eth1 bridge deposits should induce new validators in the first place + for index, deposit in enumerate(eth1_bridge_deposits): + validator_index = pre_validator_count + index + validator = state.validators[validator_index] + assert state.balances[validator_index] == deposit.amount + assert validator.pubkey == deposit.pubkey + # Effective balance is updated after pending deposits by process_effective_balance_updates + assert validator.effective_balance == spec.Gwei(0) + assert validator.withdrawal_credentials == deposit.withdrawal_credentials + + # then deposit requests go + for index, deposit in enumerate(deposit_requests): + validator_index = pre_validator_count + len(eth1_bridge_deposits) + index + validator = state.validators[validator_index] + assert state.balances[validator_index] == deposit.amount + assert validator.pubkey == deposit.pubkey + assert validator.withdrawal_credentials == deposit.withdrawal_credentials + # Validators induced from deposit requests get instant update of the EB + assert validator.effective_balance == deposit.amount @with_electra_and_later @spec_state_test -def test_pending_deposit_over_max(spec, state): - # pick an amount that adds to less than churn limit - amount = 100 - overmax = spec.MAX_PENDING_DEPOSITS_PER_EPOCH_PROCESSING + 1 - for i in range(overmax): - state.pending_deposits.append( - spec.PendingDeposit( - pubkey=state.validators[i].pubkey, - withdrawal_credentials=( - state.validators[i].withdrawal_credentials - ), - amount=amount, - slot=spec.GENESIS_SLOT, - ) - ) - assert len(state.pending_deposits) == overmax, \ - "pending deposits is not overmax" - yield from run_process_pending_deposits(spec, state) - assert len(state.pending_deposits) == 1 - assert state.balances[overmax - 1] == spec.MIN_ACTIVATION_BALANCE + amount - - -@with_electra_and_later -@spec_state_test -def test_new_deposit_eth1_withdrawal_credentials(spec, state): - state.validators[0].withdrawal_credentials = ( - spec.ETH1_ADDRESS_WITHDRAWAL_PREFIX - + b'\x00' * 11 # specified 0s - + b'\x59' * 20 # a 20-byte eth1 address - ) - amount = spec.MAX_EFFECTIVE_BALANCE - - state.pending_deposits.append(spec.PendingDeposit( - pubkey=state.validators[0].pubkey, - withdrawal_credentials=state.validators[0].withdrawal_credentials, - amount=amount, - slot=1, - )) - - yield from run_process_pending_deposits(spec, state) - - -@with_electra_and_later -@spec_state_test -def test_new_deposit_non_versioned_withdrawal_credentials(spec, state): - state.validators[0].withdrawal_credentials = ( - b'\xFF' # Non specified withdrawal credentials version - + b'\x02' * 31 # Garabage bytes - ) - amount = spec.MAX_EFFECTIVE_BALANCE - state.pending_deposits.append(spec.PendingDeposit( - pubkey=state.validators[0].pubkey, - withdrawal_credentials=state.validators[0].withdrawal_credentials, - amount=amount, - slot=1, - )) - - yield from run_process_pending_deposits(spec, state) - - -@with_electra_and_later -@spec_state_test -def test_pending_deposit_eth1_bridge_pending(spec, state): - amount = spec.MIN_ACTIVATION_BALANCE +def test_process_pending_deposits_eth1_bridge_transition_pending(spec, state): # There are pending Eth1 bridge deposits # state.eth1_deposit_index < state.deposit_requests_start_index - state.deposit_requests_start_index = state.eth1_deposit_index + 1 - index = 0 - withdrawal_credentials = ( - spec.ETH1_ADDRESS_WITHDRAWAL_PREFIX + - spec.hash(pubkeys[index])[1:] - ) - pd = build_pending_deposit(spec, index, - amount=amount, - withdrawal_credentials=withdrawal_credentials, - signed=True, - slot=1) - state.pending_deposits.append(pd) - # set deposit_balance_to_consume to some initial amount - state.deposit_balance_to_consume = amount + pre_validator_count = len(state.validators) + state.eth1_data.deposit_count = len(state.validators) + 3 + state.deposit_requests_start_index = state.eth1_data.deposit_count + + state, new_pending_deposits = _prepare_eth1_bridge_deprecation(spec, state, [True, True, False]) + assert state.eth1_deposit_index < state.deposit_requests_start_index + yield from run_process_pending_deposits(spec, state) + + # Eth1 bridge deposits were applied + _check_pending_deposits_induced_new_validators(spec, state, pre_validator_count, new_pending_deposits[:2]) + # deposit request was postponed and not processed + assert state.pending_deposits == new_pending_deposits[2:] # deposit_balance_to_consume was reset to 0 assert state.deposit_balance_to_consume == 0 - # deposit was postponed and not processed - assert len(state.pending_deposits) == 1 @with_electra_and_later @spec_state_test -def test_pending_deposit_eth1_bridge_not_applied(spec, state): - amount = spec.MIN_ACTIVATION_BALANCE - # deposit is not finalized yet, so it is postponed - state.pending_deposits.append(spec.PendingDeposit( - pubkey=state.validators[0].pubkey, - withdrawal_credentials=state.validators[0].withdrawal_credentials, - amount=amount, - slot=1, - )) - # set deposit_requests_start_index to something high - state.deposit_requests_start_index = 100000000000000000 - # set deposit_balance_to_consume to some initial amount - state.deposit_balance_to_consume = amount +def test_process_pending_deposits_eth1_bridge_transition_not_applied(spec, state): + # There are pending Eth1 bridge deposits + # state.eth1_deposit_index < state.deposit_requests_start_index + pre_validator_count = len(state.validators) + state.eth1_data.deposit_count = len(state.validators) + 3 + state.deposit_requests_start_index = state.eth1_data.deposit_count + + state, new_pending_deposits = _prepare_eth1_bridge_deprecation(spec, state, [False, True, True]) + assert state.eth1_deposit_index < state.deposit_requests_start_index + yield from run_process_pending_deposits(spec, state) + + # no pending deposit was processed, however Eth1 bridge deposits induced new validators + assert pre_validator_count + 2 == len(state.validators) + assert state.pending_deposits == new_pending_deposits # deposit_balance_to_consume was reset to 0 assert state.deposit_balance_to_consume == 0 - # deposit was postponed and not processed - assert len(state.pending_deposits) == 1 @with_electra_and_later @spec_state_test -def test_pending_deposit_no_eth1_bridge_pending(spec, state): - amount = spec.MIN_ACTIVATION_BALANCE - # there is no pending eth1 bridge deposits +def test_process_pending_deposits_eth1_bridge_transition_complete(spec, state): + # There is no pending Eth1 bridge deposits # state.eth1_deposit_index == state.deposit_requests_start_index - state.deposit_requests_start_index = state.eth1_deposit_index - index = 0 - withdrawal_credentials = ( - spec.ETH1_ADDRESS_WITHDRAWAL_PREFIX + - spec.hash(pubkeys[index])[1:] - ) - pd = build_pending_deposit(spec, index, - amount=amount, - withdrawal_credentials=withdrawal_credentials, - signed=True) - state.pending_deposits.append(pd) - # set deposit_balance_to_consume to some initial amount - state.deposit_balance_to_consume = amount + pre_validator_count = len(state.validators) + state.eth1_data.deposit_count = len(state.validators) + 2 + state.deposit_requests_start_index = state.eth1_data.deposit_count + + state, new_pending_deposits = _prepare_eth1_bridge_deprecation(spec, state, [True, False, True]) + assert state.eth1_deposit_index == state.deposit_requests_start_index + yield from run_process_pending_deposits(spec, state) + + # all deposits were applied + assert state.pending_deposits == [] + _check_pending_deposits_induced_new_validators(spec, state, pre_validator_count, new_pending_deposits) # deposit_balance_to_consume was reset to 0 assert state.deposit_balance_to_consume == 0 - # all pending deposits processed - assert len(state.pending_deposits) == 0 @with_electra_and_later @spec_state_test -def test_pending_deposit_not_finalized(spec, state): - amount = spec.MIN_ACTIVATION_BALANCE - # set slot to something not finalized - # deposit is not finalized yet, so it is postponed - state.pending_deposits.append(spec.PendingDeposit( - pubkey=state.validators[0].pubkey, - withdrawal_credentials=state.validators[0].withdrawal_credentials, - amount=amount, - slot=spec.get_current_epoch(state) + 1, - )) - # skip the bridge validation +def test_process_pending_deposits_not_finalized(spec, state): + # complete eth1 bridge transition state.deposit_requests_start_index = 0 - # set deposit_balance_to_consume to some initial amount - state.deposit_balance_to_consume = amount + # advance state three epochs into the future + for _ in range(0, 3): + next_epoch_with_full_participation(spec, state) + # create pending deposits + pre_validator_count = len(state.validators) + for index in range(0, 2): + state.pending_deposits.append( + prepare_pending_deposit( + spec, + validator_index=pre_validator_count + index, + amount=spec.MIN_ACTIVATION_BALANCE, + signed=True, + slot=state.slot + index + ) + ) + new_pending_deposits = state.pending_deposits.copy() + + # finalize a slot before the slot of the first deposit + advance_finality_to(spec, state, spec.get_current_epoch(state) - 1) + + # process pending deposits + # the slot of the first deposit will be finalized before the call to process_pending_deposits + set_full_participation(spec, state) + _ensure_enough_churn_to_process_deposits(spec, state) + yield from run_process_pending_deposits(spec, state) + # deposit_balance_to_consume was reset to 0 assert state.deposit_balance_to_consume == 0 - # deposit was postponed and not processed - assert len(state.pending_deposits) == 1 + # second deposit was not processed as it hasn't been finalized + assert state.pending_deposits == new_pending_deposits[1:] + _check_pending_deposits_induced_new_validators(spec, state, pre_validator_count, new_pending_deposits[:1]) @with_electra_and_later @spec_state_test def test_process_pending_deposits_limit_is_reached(spec, state): - amount = 5000 - cumulative_amount = 0 # set pending deposits to the maximum - for i in range(spec.MAX_PENDING_DEPOSITS_PER_EPOCH_PROCESSING+1): + amount = spec.EFFECTIVE_BALANCE_INCREMENT * 1 + for i in range(spec.MAX_PENDING_DEPOSITS_PER_EPOCH_PROCESSING + 2): wc = state.validators[i].withdrawal_credentials - pd = build_pending_deposit(spec, i, - amount=amount, - withdrawal_credentials=wc, - signed=True) + pd = prepare_pending_deposit(spec, i, amount, withdrawal_credentials=wc, signed=True) state.pending_deposits.append(pd) - cumulative_amount += amount - # churn limit was not reached - assert cumulative_amount < spec.get_activation_exit_churn_limit(state) + new_pending_deposits = state.pending_deposits.copy() + + # process pending deposits + pre_balances = state.balances.copy() + _ensure_enough_churn_to_process_deposits(spec, state) + yield from run_process_pending_deposits(spec, state) + + # deposit_balance_to_consume was reset to 0 + assert state.deposit_balance_to_consume == 0 # no deposits above limit were processed - assert len(state.pending_deposits) == 1 + assert state.pending_deposits == new_pending_deposits[spec.MAX_PENDING_DEPOSITS_PER_EPOCH_PROCESSING:] + for i in range(spec.MAX_PENDING_DEPOSITS_PER_EPOCH_PROCESSING): + assert state.balances[i] == pre_balances[i] + amount + for i in range(spec.MAX_PENDING_DEPOSITS_PER_EPOCH_PROCESSING, spec.MAX_PENDING_DEPOSITS_PER_EPOCH_PROCESSING + 2): + assert state.balances[i] == pre_balances[i] @with_electra_and_later @spec_state_test -def test_pending_deposit_validator_withdrawn(spec, state): - amount = spec.MIN_ACTIVATION_BALANCE - index = 0 - withdrawal_credentials = ( - spec.ETH1_ADDRESS_WITHDRAWAL_PREFIX + - spec.hash(pubkeys[index])[1:] - ) - compounding_credentials = ( - spec.COMPOUNDING_WITHDRAWAL_PREFIX + - spec.hash(pubkeys[index])[1:] - ) - # advance the state - next_epoch_via_block(spec, state) - state.validators[index].withdrawal_credentials = withdrawal_credentials - previous_epoch = spec.get_current_epoch(state) - 1 - # set validator to be exited by current epoch - state.validators[index].exit_epoch = previous_epoch - # set validator to be withdrawable by current epoch - state.validators[index].withdrawable_epoch = previous_epoch - # set withdrawal credentials to compounding but should not switch since - # validator is already withdrawing - pd = build_pending_deposit(spec, index, - amount=amount, - withdrawal_credentials=compounding_credentials, - signed=True) - state.pending_deposits.append(pd) - # skip the bridge validation - state.deposit_requests_start_index = 0 - # set deposit_balance_to_consume to some initial amount - state.deposit_balance_to_consume = amount - # reset balance for assert - state.balances[0] = 0 - old_validator_count = len(state.validators) - yield from run_process_pending_deposits(spec, state) - btc = state.deposit_balance_to_consume - # deposit_balance_to_consume was reset to 0 - assert btc == 0 - # deposit was processed - assert state.pending_deposits == [] - # balance increases because of withdraw - assert state.balances[0] == amount - # churn limit was not reached - assert not amount > spec.get_activation_exit_churn_limit(state) - # validator count should stay the same - assert len(state.validators) == old_validator_count - - -@with_electra_and_later -@spec_state_test -def test_pending_deposit_validator_exiting_but_not_withdrawn(spec, state): - amount = spec.MIN_ACTIVATION_BALANCE - hash = spec.hash(state.validators[0].pubkey)[1:] - withdrawal_credentials = spec.ETH1_ADDRESS_WITHDRAWAL_PREFIX + hash - # advance the state - next_epoch_via_block(spec, state) - state.validators[0].withdrawal_credentials = withdrawal_credentials - # set validator to be withdrawable by current epoch - state.validators[0].exit_epoch = spec.get_current_epoch(state) - 1 - state.validators[0].withdrawable_epoch = spec.FAR_FUTURE_EPOCH - state.pending_deposits.append(spec.PendingDeposit( - pubkey=state.validators[0].pubkey, - withdrawal_credentials=state.validators[0].withdrawal_credentials, - amount=amount, - slot=spec.GENESIS_SLOT, - )) - # skip the bridge validation - state.deposit_requests_start_index = 0 - # set deposit_balance_to_consume to some initial amount - state.deposit_balance_to_consume = amount - - yield from run_process_pending_deposits(spec, state) - # deposit_balance_to_consume was reset to 0 - assert state.deposit_balance_to_consume == 0 - # deposit was postponed and not processed - assert len(state.pending_deposits) == 1 - - -@with_electra_and_later -@spec_state_test -def test_pending_deposit_not_in_validator_set(spec, state): - index = 2000 - amount = spec.MIN_ACTIVATION_BALANCE - wc = ( - spec.ETH1_ADDRESS_WITHDRAWAL_PREFIX + - spec.hash(pubkeys[index])[1:] - ) - pd = build_pending_deposit(spec, index, - amount=amount, - withdrawal_credentials=wc, - signed=True) - - state.pending_deposits.append(pd) - old_length = len(state.validators) - yield from run_process_pending_deposits(spec, state) - # new validator activated - assert len(state.validators) == old_length + 1 - - -@with_electra_and_later -@spec_state_test -def test_pending_deposit_min_activation_balance(spec, state): - index = 0 - amount = spec.MIN_ACTIVATION_BALANCE - state.pending_deposits.append( - build_pending_deposit_top_up(spec, state, index, amount) - ) - pre_balance = state.balances[index] - - yield from run_process_pending_deposits(spec, state) - - assert state.balances[index] == pre_balance + amount - # No leftover deposit balance to consume - assert state.deposit_balance_to_consume == 0 - assert state.pending_deposits == [] - - -@with_electra_and_later -@spec_state_test -def test_pending_deposit_balance_equal_churn(spec, state): +def test_process_pending_deposits_balance_equal_churn(spec, state): index = 0 amount = spec.get_activation_exit_churn_limit(state) state.pending_deposits.append( - build_pending_deposit_top_up(spec, state, index, amount) + prepare_pending_deposit(spec, index, amount) ) pre_balance = state.balances[index] @@ -389,110 +235,11 @@ def test_pending_deposit_balance_equal_churn(spec, state): @with_electra_and_later @spec_state_test -def test_pending_deposit_balance_equal_churn_with_compounding(spec, state): - index = 0 - withdrawal_credentials = ( - spec.ETH1_ADDRESS_WITHDRAWAL_PREFIX + - spec.hash(pubkeys[index])[1:] - ) - compounding_credentials = ( - spec.COMPOUNDING_WITHDRAWAL_PREFIX + - spec.hash(pubkeys[index])[1:] - ) - amount = spec.get_activation_exit_churn_limit(state) - state.validators[index].withdrawal_credentials = withdrawal_credentials - - # set withdrawal credentials to compounding but should not switch since - # validator is already withdrawing - pd = build_pending_deposit(spec, index, - amount=amount, - withdrawal_credentials=compounding_credentials, - signed=True) - state.pending_deposits.append(pd) - pre_balance = state.balances[index] - - yield from run_process_pending_deposits(spec, state) - - assert state.balances[index] == pre_balance + amount - assert state.deposit_balance_to_consume == 0 - assert state.pending_deposits == [] - current_credentials = state.validators[0].withdrawal_credentials - # validator is not exited, so it should not switch to compounding - assert current_credentials == withdrawal_credentials - - -@with_electra_and_later -@spec_state_test -def test_top_up__zero_balance(spec, state): - validator_index = 0 - amount = spec.MAX_EFFECTIVE_BALANCE // 4 - - initial_balance = 0 - initial_effective_balance = 0 - state.balances[validator_index] = initial_balance - val = state.validators[validator_index] - val.effective_balance = initial_effective_balance - wc = val.withdrawal_credentials - pd = build_pending_deposit(spec, validator_index, - amount=amount, - withdrawal_credentials=wc, - signed=True) - state.pending_deposits.append(pd) - - yield from run_process_pending_deposits(spec, state) - - deposits_len = len(state.pending_deposits) - assert state.pending_deposits[deposits_len - 1].amount == amount - # unchanged effective balance - assert val.effective_balance == initial_effective_balance - - -@with_electra_and_later -@spec_state_test -def test_incorrect_sig_top_up(spec, state): - validator_index = 0 - amount = spec.MAX_EFFECTIVE_BALANCE // 4 - - val = state.validators[validator_index] - wc = val.withdrawal_credentials - pd = build_pending_deposit(spec, validator_index, - amount=amount, - withdrawal_credentials=wc, - signed=False) - state.pending_deposits.append(pd) - - yield from run_process_pending_deposits(spec, state) - - -@with_electra_and_later -@spec_state_test -def test_incorrect_withdrawal_credentials_top_up(spec, state): - validator_index = 0 - amount = spec.MAX_EFFECTIVE_BALANCE // 4 - - initial_balance = 0 - initial_effective_balance = 0 - state.balances[validator_index] = initial_balance - val = state.validators[validator_index] - val.effective_balance = initial_effective_balance - wc = spec.BLS_WITHDRAWAL_PREFIX + spec.hash(b"junk")[1:] - - pd = build_pending_deposit(spec, validator_index, - amount=amount, - withdrawal_credentials=wc, - signed=True) - state.pending_deposits.append(pd) - - yield from run_process_pending_deposits(spec, state) - - -@with_electra_and_later -@spec_state_test -def test_pending_deposit_balance_above_churn(spec, state): +def test_process_pending_deposits_balance_above_churn(spec, state): index = 0 amount = spec.get_activation_exit_churn_limit(state) + 1 state.pending_deposits.append( - build_pending_deposit_top_up(spec, state, index, amount) + prepare_pending_deposit(spec, index, amount) ) pre_balance = state.balances[index] @@ -505,61 +252,18 @@ def test_pending_deposit_balance_above_churn(spec, state): assert state.deposit_balance_to_consume == wantedBalanceToConsume # deposit is still in the queue assert state.pending_deposits == [ - build_pending_deposit_top_up(spec, state, index, amount) + prepare_pending_deposit(spec, index, amount) ] @with_electra_and_later @spec_state_test -def test_top_up__max_effective_balance(spec, state): - validator_index = 0 - amount = spec.MAX_EFFECTIVE_BALANCE // 4 - wc = state.validators[validator_index].withdrawal_credentials - pd = build_pending_deposit(spec, validator_index, - amount=amount, - withdrawal_credentials=wc, - signed=True) - state.pending_deposits.append(pd) - - state.balances[validator_index] = spec.MAX_EFFECTIVE_BALANCE - state.validators[validator_index].effective_balance = spec.MAX_EFFECTIVE_BALANCE - - yield from run_process_pending_deposits(spec, state) - - assert state.validators[validator_index].effective_balance == spec.MAX_EFFECTIVE_BALANCE - - -@with_electra_and_later -@spec_state_test -def test_top_up__less_effective_balance(spec, state): - validator_index = 0 - amount = spec.MAX_EFFECTIVE_BALANCE // 4 - wc = state.validators[validator_index].withdrawal_credentials - pd = build_pending_deposit(spec, validator_index, - amount=amount, - withdrawal_credentials=wc, - signed=True) - state.pending_deposits.append(pd) - - initial_balance = spec.MAX_EFFECTIVE_BALANCE - 1000 - initial_effective_balance = spec.MAX_EFFECTIVE_BALANCE - spec.EFFECTIVE_BALANCE_INCREMENT - state.balances[validator_index] = initial_balance - state.validators[validator_index].effective_balance = initial_effective_balance - - yield from run_process_pending_deposits(spec, state) - - # unchanged effective balance - assert state.validators[validator_index].effective_balance == initial_effective_balance - - -@with_electra_and_later -@spec_state_test -def test_pending_deposit_preexisting_churn(spec, state): +def test_process_pending_deposits_preexisting_churn(spec, state): index = 0 - amount = 10**9 + 1 + amount = spec.EFFECTIVE_BALANCE_INCREMENT + 1 state.deposit_balance_to_consume = 2 * amount state.pending_deposits.append( - build_pending_deposit_top_up(spec, state, index, amount) + prepare_pending_deposit(spec, index, amount) ) pre_balance = state.balances[index] @@ -575,15 +279,13 @@ def test_pending_deposit_preexisting_churn(spec, state): @with_electra_and_later @spec_state_test -def test_multiple_pending_deposits_below_churn(spec, state): - amount = 10**9 +def test_process_pending_deposits_multiple_pending_deposits_below_churn(spec, state): + amount = spec.EFFECTIVE_BALANCE_INCREMENT state.pending_deposits.append( - build_pending_deposit_top_up(spec, state, - validator_index=0, amount=amount) + prepare_pending_deposit(spec, validator_index=0, amount=amount) ) state.pending_deposits.append( - build_pending_deposit_top_up(spec, state, - validator_index=1, amount=amount) + prepare_pending_deposit(spec, validator_index=1, amount=amount) ) pre_balances = state.balances.copy() @@ -598,13 +300,12 @@ def test_multiple_pending_deposits_below_churn(spec, state): @with_electra_and_later @spec_state_test -def test_multiple_pending_deposits_above_churn(spec, state): +def test_process_pending_deposits_multiple_pending_deposits_above_churn(spec, state): # set third deposit to be over the churn amount = (spec.get_activation_exit_churn_limit(state) // 3) + 1 for i in [0, 1, 2]: state.pending_deposits.append( - build_pending_deposit_top_up(spec, state, - validator_index=i, amount=amount) + prepare_pending_deposit(spec, validator_index=i, amount=amount) ) pre_balances = state.balances.copy() @@ -621,19 +322,17 @@ def test_multiple_pending_deposits_above_churn(spec, state): ) # third deposit is still in the queue assert state.pending_deposits == [ - build_pending_deposit_top_up(spec, state, - validator_index=2, amount=amount) + prepare_pending_deposit(spec, validator_index=2, amount=amount) ] @with_electra_and_later @spec_state_test -def test_skipped_deposit_exiting_validator(spec, state): +def test_process_pending_deposits_skipped_deposit_exiting_validator(spec, state): index = 0 amount = spec.MIN_ACTIVATION_BALANCE state.pending_deposits.append( - build_pending_deposit_top_up(spec, state, - validator_index=index, amount=amount) + prepare_pending_deposit(spec, validator_index=index, amount=amount) ) pre_pending_deposits = state.pending_deposits.copy() pre_balance = state.balances[index] @@ -652,13 +351,12 @@ def test_skipped_deposit_exiting_validator(spec, state): @with_electra_and_later @spec_state_test -def test_multiple_skipped_deposits_exiting_validators(spec, state): +def test_process_pending_deposits_multiple_skipped_deposits_exiting_validators(spec, state): amount = spec.EFFECTIVE_BALANCE_INCREMENT for i in [0, 1, 2]: # Append pending deposit for validator i state.pending_deposits.append( - build_pending_deposit_top_up(spec, state, - validator_index=i, amount=amount) + prepare_pending_deposit(spec, validator_index=i, amount=amount) ) # Initiate the exit of validator i @@ -678,12 +376,11 @@ def test_multiple_skipped_deposits_exiting_validators(spec, state): @with_electra_and_later @spec_state_test -def test_multiple_pending_one_skipped(spec, state): +def test_process_pending_deposits_multiple_pending_one_skipped(spec, state): amount = spec.EFFECTIVE_BALANCE_INCREMENT for i in [0, 1, 2]: state.pending_deposits.append( - build_pending_deposit_top_up(spec, state, - validator_index=i, amount=amount) + prepare_pending_deposit(spec, validator_index=i, amount=amount) ) pre_balances = state.balances.copy() # Initiate the second validator's exit @@ -699,27 +396,22 @@ def test_multiple_pending_one_skipped(spec, state): assert state.deposit_balance_to_consume == 0 # second deposit is still in the queue assert state.pending_deposits == [ - build_pending_deposit_top_up(spec, state, - validator_index=1, amount=amount) + prepare_pending_deposit(spec, validator_index=1, amount=amount) ] @with_electra_and_later @spec_state_test -def test_mixture_of_skipped_and_above_churn(spec, state): +def test_process_pending_deposits_mixture_of_skipped_and_above_churn(spec, state): amount01 = spec.EFFECTIVE_BALANCE_INCREMENT amount2 = spec.MAX_EFFECTIVE_BALANCE_ELECTRA # First two validators have small deposit, third validators a large one for i in [0, 1]: state.pending_deposits.append( - build_pending_deposit_top_up(spec, state, - validator_index=i, - amount=amount01) + prepare_pending_deposit(spec, validator_index=i, amount=amount01) ) state.pending_deposits.append( - build_pending_deposit_top_up(spec, state, - validator_index=2, - amount=amount2) + prepare_pending_deposit(spec, validator_index=2, amount=amount2) ) pre_balances = state.balances.copy() # Initiate the second validator's exit @@ -738,22 +430,18 @@ def test_mixture_of_skipped_and_above_churn(spec, state): assert state.deposit_balance_to_consume == wanted_balance # second and third deposit still in the queue assert state.pending_deposits == [ - build_pending_deposit_top_up(spec, state, - validator_index=2, amount=amount2), - build_pending_deposit_top_up(spec, state, - validator_index=1, amount=amount01) + prepare_pending_deposit(spec, validator_index=2, amount=amount2), + prepare_pending_deposit(spec, validator_index=1, amount=amount01) ] @with_electra_and_later @spec_state_test -def test_processing_deposit_of_withdrawable_validator(spec, state): +def test_process_pending_deposits_withdrawable_validator(spec, state): index = 0 amount = spec.MIN_ACTIVATION_BALANCE state.pending_deposits.append( - build_pending_deposit_top_up(spec, state, - validator_index=index, - amount=amount) + prepare_pending_deposit(spec, validator_index=index, amount=amount) ) pre_balance = state.balances[index] # Initiate the validator's exit @@ -773,12 +461,11 @@ def test_processing_deposit_of_withdrawable_validator(spec, state): @with_electra_and_later @spec_state_test -def test_processing_deposit_of_withdrawable_validator_not_churned(spec, state): +def test_process_pending_deposits_withdrawable_validator_not_churned(spec, state): amount = spec.MAX_EFFECTIVE_BALANCE_ELECTRA for i in [0, 1]: state.pending_deposits.append( - build_pending_deposit_top_up(spec, state, - validator_index=i, amount=amount) + prepare_pending_deposit(spec, validator_index=i, amount=amount) ) pre_balances = state.balances.copy() # Initiate the first validator's exit @@ -799,140 +486,5 @@ def test_processing_deposit_of_withdrawable_validator_not_churned(spec, state): wanted_limit = spec.get_activation_exit_churn_limit(state) assert state.deposit_balance_to_consume == wanted_limit assert state.pending_deposits == [ - build_pending_deposit_top_up(spec, state, - validator_index=1, amount=amount) + prepare_pending_deposit(spec, validator_index=1, amount=amount) ] - - -@with_electra_and_later -@spec_state_test -@always_bls -def test_correct_sig_but_forked_state(spec, state): - amount = spec.MAX_EFFECTIVE_BALANCE - # deposits will always be valid, regardless of the current fork - state.fork.current_version = spec.Version('0x1234abcd') - index = 0 - withdrawal_credentials = ( - spec.ETH1_ADDRESS_WITHDRAWAL_PREFIX + - spec.hash(pubkeys[index])[1:] - ) - wc = withdrawal_credentials - pd = build_pending_deposit(spec, index, - amount=amount, - withdrawal_credentials=wc, - signed=True) - state.pending_deposits.append(pd) - yield from run_process_pending_deposits(spec, state) - - -@with_electra_and_later -@spec_state_test -def test_key_validate_invalid_subgroup(spec, state): - amount = spec.MAX_EFFECTIVE_BALANCE - - # All-zero pubkey would not pass `bls.KeyValidate`, but `process_deposit` would not throw exception. - pubkey = b'\x00' * 48 - - index = 0 - withdrawal_credentials = ( - spec.ETH1_ADDRESS_WITHDRAWAL_PREFIX + - spec.hash(pubkey)[1:] - ) - wc = withdrawal_credentials - pd = build_pending_deposit(spec, index, - amount=amount, - withdrawal_credentials=wc, - pubkey=pubkey, - signed=True) - state.pending_deposits.append(pd) - yield from run_process_pending_deposits(spec, state) - - -@with_electra_and_later -@spec_state_test -def test_key_validate_invalid_decompression(spec, state): - amount = spec.MAX_EFFECTIVE_BALANCE - - # `deserialization_fails_infinity_with_true_b_flag` BLS G1 deserialization test case. - # This pubkey would not pass `bls.KeyValidate`, but `process_deposit` would not throw exception. - pubkey_hex = 'c01000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' - pubkey = bytes.fromhex(pubkey_hex) - - index = 0 - withdrawal_credentials = ( - spec.ETH1_ADDRESS_WITHDRAWAL_PREFIX + - spec.hash(pubkey)[1:] - ) - wc = withdrawal_credentials - pd = build_pending_deposit(spec, index, - amount=amount, - withdrawal_credentials=wc, - pubkey=pubkey, - signed=True) - state.pending_deposits.append(pd) - yield from run_process_pending_deposits(spec, state) - - -@with_electra_and_later -@spec_state_test -@always_bls -def test_apply_pending_deposit_with_previous_fork_version(spec, state): - # Since deposits are valid across forks, the domain is always set with `GENESIS_FORK_VERSION`. - assert state.fork.previous_version != state.fork.current_version - amount = spec.MAX_EFFECTIVE_BALANCE - index = 0 - withdrawal_credentials = ( - spec.ETH1_ADDRESS_WITHDRAWAL_PREFIX + - spec.hash(pubkeys[index])[1:] - ) - wc = withdrawal_credentials - pd = build_pending_deposit(spec, index, - amount=amount, - withdrawal_credentials=wc, - fork_version=state.fork.previous_version, - signed=True) - state.pending_deposits.append(pd) - yield from run_process_pending_deposits(spec, state) - - -@with_electra_and_later -@spec_state_test -@always_bls -def test_apply_pending_deposit_with_genesis_fork_version(spec, state): - assert spec.config.GENESIS_FORK_VERSION not in (state.fork.previous_version, state.fork.current_version) - - assert state.fork.previous_version != state.fork.current_version - amount = spec.MAX_EFFECTIVE_BALANCE - index = 0 - withdrawal_credentials = ( - spec.ETH1_ADDRESS_WITHDRAWAL_PREFIX + - spec.hash(pubkeys[index])[1:] - ) - wc = withdrawal_credentials - pd = build_pending_deposit(spec, index, - amount=amount, - withdrawal_credentials=wc, - fork_version=spec.GENESIS_FORK_VERSION, - signed=True) - state.pending_deposits.append(pd) - yield from run_process_pending_deposits(spec, state) - - -@with_electra_and_later -@spec_state_test -@always_bls -def test_apply_pending_deposit_with_bad_fork_version(spec, state): - amount = spec.MAX_EFFECTIVE_BALANCE - index = 0 - withdrawal_credentials = ( - spec.ETH1_ADDRESS_WITHDRAWAL_PREFIX + - spec.hash(pubkeys[index])[1:] - ) - wc = withdrawal_credentials - pd = build_pending_deposit(spec, index, - amount=amount, - withdrawal_credentials=wc, - fork_version=spec.Version('0xAaBbCcDd'), - signed=True) - state.pending_deposits.append(pd) - yield from run_process_pending_deposits(spec, state) diff --git a/tests/core/pyspec/eth2spec/test/helpers/deposits.py b/tests/core/pyspec/eth2spec/test/helpers/deposits.py index 0137f96be..f045d1fcd 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/deposits.py +++ b/tests/core/pyspec/eth2spec/test/helpers/deposits.py @@ -35,7 +35,7 @@ def build_deposit_data(spec, pubkey, privkey, amount, withdrawal_credentials, fo return deposit_data -def sign_deposit_data(spec, deposit_data, privkey, fork_version): +def sign_deposit_data(spec, deposit_data, privkey, fork_version=None): deposit_message = spec.DepositMessage( pubkey=deposit_data.pubkey, withdrawal_credentials=deposit_data.withdrawal_credentials, @@ -175,22 +175,6 @@ def prepare_state_and_deposit(spec, state, validator_index, amount, return deposit -def build_deposit_request(spec, - index, - pubkey, - privkey, - amount, - withdrawal_credentials, - signed): - deposit_data = build_deposit_data(spec, pubkey, privkey, amount, withdrawal_credentials, signed=signed) - return spec.DepositRequest( - pubkey=deposit_data.pubkey, - withdrawal_credentials=deposit_data.withdrawal_credentials, - amount=deposit_data.amount, - signature=deposit_data.signature, - index=index) - - def prepare_deposit_request(spec, validator_index, amount, index=None, pubkey=None, @@ -213,71 +197,16 @@ def prepare_deposit_request(spec, validator_index, amount, if withdrawal_credentials is None: withdrawal_credentials = spec.BLS_WITHDRAWAL_PREFIX + spec.hash(pubkey)[1:] - return build_deposit_request( - spec, - index, - pubkey, - privkey, - amount, - withdrawal_credentials, - signed, + deposit_data = build_deposit_data(spec, pubkey, privkey, amount, withdrawal_credentials, signed=signed) + return spec.DepositRequest( + pubkey=deposit_data.pubkey, + withdrawal_credentials=deposit_data.withdrawal_credentials, + amount=deposit_data.amount, + signature=deposit_data.signature, + index=index ) -def build_pending_deposit_top_up(spec, state, validator_index, amount, slot=None): - """ - Create a pending deposit which is a top up to an existing validator - """ - if slot is None: - slot = spec.GENESIS_SLOT - - return spec.PendingDeposit( - pubkey=state.validators[validator_index].pubkey, - withdrawal_credentials=state.validators[validator_index].withdrawal_credentials, - amount=amount, - signature=bls.G2_POINT_AT_INFINITY, - slot=slot, - ) - - -def build_pending_deposit(spec, validator_index, amount, - index=None, - pubkey=None, - privkey=None, - withdrawal_credentials=None, - fork_version=None, - slot=None, - signed=False): - if index is None: - index = validator_index - - if pubkey is None: - pubkey = pubkeys[validator_index] - - if privkey is None: - privkey = privkeys[validator_index] - - if slot is None: - slot = spec.GENESIS_SLOT - - pending_deposit = spec.PendingDeposit( - pubkey=pubkeys[index], - withdrawal_credentials=withdrawal_credentials, - amount=amount, - slot=slot, - ) - if signed: - deposit_data = build_deposit_data(spec, - pubkeys[index], - privkeys[index], - amount, - withdrawal_credentials, - fork_version, - signed=True) - pending_deposit.signature = deposit_data.signature - return pending_deposit - - def prepare_pending_deposit(spec, validator_index, amount, pubkey=None, privkey=None, @@ -450,8 +379,6 @@ def run_deposit_request_processing( pre_balance = get_balance(state, validator_index) pre_effective_balance = state.validators[validator_index].effective_balance - pre_pending_deposits = len(state.pending_deposits) - yield 'pre', state yield 'deposit_request', deposit_request @@ -553,5 +480,5 @@ def run_pending_deposit_applying(spec, state, pending_deposit, validator_index, assert len(state.balances) == pre_validator_count if is_top_up: assert get_balance(state, validator_index) == pre_balance - + assert len(state.pending_deposits) == 0 diff --git a/tests/core/pyspec/eth2spec/test/helpers/state.py b/tests/core/pyspec/eth2spec/test/helpers/state.py index 07e7bfb47..72fca0b14 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/state.py +++ b/tests/core/pyspec/eth2spec/test/helpers/state.py @@ -179,3 +179,8 @@ def has_active_balance_differential(spec, state): def get_validator_index_by_pubkey(state, pubkey): index = next((i for i, validator in enumerate(state.validators) if validator.pubkey == pubkey), None) return index + + +def advance_finality_to(spec, state, epoch): + while state.finalized_checkpoint.epoch < epoch: + next_epoch_with_full_participation(spec, state)