From 17f64540359c410b1fddcf35051ac3439e831dd2 Mon Sep 17 00:00:00 2001 From: Mikhail Kalinin Date: Fri, 18 Oct 2024 13:52:11 +0600 Subject: [PATCH 1/6] Add tests for process_registry_updates --- specs/electra/beacon-chain.md | 8 +- .../test_process_registry_updates.py | 6 +- .../test_process_registry_updates.py | 92 +++++++++++++++++++ 3 files changed, 101 insertions(+), 5 deletions(-) create mode 100644 tests/core/pyspec/eth2spec/test/electra/epoch_processing/test_process_registry_updates.py diff --git a/specs/electra/beacon-chain.md b/specs/electra/beacon-chain.md index 0c56491907..0d6fc0b4e3 100644 --- a/specs/electra/beacon-chain.md +++ b/specs/electra/beacon-chain.md @@ -778,23 +778,25 @@ def process_epoch(state: BeaconState) -> None: #### Modified `process_registry_updates` -*Note*: The function `process_registry_updates` is modified to use the updated definition of `initiate_validator_exit` +*Note*: The function `process_registry_updates` is modified to +use the updated definitions of `initiate_validator_exit` and `is_eligible_for_activation_queue` and changes how the activation epochs are computed for eligible validators. ```python def process_registry_updates(state: BeaconState) -> None: # Process activation eligibility and ejections for index, validator in enumerate(state.validators): - if is_eligible_for_activation_queue(validator): + if is_eligible_for_activation_queue(validator): # [Modified in Electra:EIP7251] validator.activation_eligibility_epoch = get_current_epoch(state) + 1 if ( is_active_validator(validator, get_current_epoch(state)) and validator.effective_balance <= EJECTION_BALANCE ): - initiate_validator_exit(state, ValidatorIndex(index)) + initiate_validator_exit(state, ValidatorIndex(index)) # [Modified in Electra:EIP7251] # Activate all eligible validators + # [Modified in Electra:EIP7251] activation_epoch = compute_activation_exit_epoch(get_current_epoch(state)) for validator in state.validators: if is_eligible_for_activation(state, validator): diff --git a/tests/core/pyspec/eth2spec/test/deneb/epoch_processing/test_process_registry_updates.py b/tests/core/pyspec/eth2spec/test/deneb/epoch_processing/test_process_registry_updates.py index 9d5a2e5d9c..0914bc1fb9 100644 --- a/tests/core/pyspec/eth2spec/test/deneb/epoch_processing/test_process_registry_updates.py +++ b/tests/core/pyspec/eth2spec/test/deneb/epoch_processing/test_process_registry_updates.py @@ -23,6 +23,8 @@ def run_test_activation_churn_limit(spec, state): validator_count_0 = len(state.validators) + balance = spec.MIN_ACTIVATION_BALANCE if is_post_electra(spec) else spec.MAX_EFFECTIVE_BALANCE + for i in range(mock_activations): index = validator_count_0 + i validator = spec.Validator( @@ -32,10 +34,10 @@ def run_test_activation_churn_limit(spec, state): activation_epoch=spec.FAR_FUTURE_EPOCH, exit_epoch=spec.FAR_FUTURE_EPOCH, withdrawable_epoch=spec.FAR_FUTURE_EPOCH, - effective_balance=spec.MAX_EFFECTIVE_BALANCE, + effective_balance=balance, ) state.validators.append(validator) - state.balances.append(spec.MAX_EFFECTIVE_BALANCE) + state.balances.append(balance) state.previous_epoch_participation.append(spec.ParticipationFlags(0b0000_0000)) state.current_epoch_participation.append(spec.ParticipationFlags(0b0000_0000)) state.inactivity_scores.append(0) diff --git a/tests/core/pyspec/eth2spec/test/electra/epoch_processing/test_process_registry_updates.py b/tests/core/pyspec/eth2spec/test/electra/epoch_processing/test_process_registry_updates.py new file mode 100644 index 0000000000..ce5915269a --- /dev/null +++ b/tests/core/pyspec/eth2spec/test/electra/epoch_processing/test_process_registry_updates.py @@ -0,0 +1,92 @@ +from eth2spec.test.helpers.deposits import mock_deposit +from eth2spec.test.helpers.state import next_epoch +from eth2spec.test.context import spec_state_test, with_electra_and_later +from eth2spec.test.helpers.epoch_processing import run_epoch_processing_with +from eth2spec.test.helpers.withdrawals import ( + set_eth1_withdrawal_credential_with_balance, + set_compounding_withdrawal_credential_with_balance +) + + +def run_test_activation_queue_eligibility(spec, state, validator_index, balance): + # move past first two irregular epochs wrt finality + next_epoch(spec, state) + next_epoch(spec, state) + + state.balances[validator_index] = balance + state.validators[validator_index].effective_balance = balance + + # ready for entrance into activation queue + mock_deposit(spec, state, validator_index) + + yield from run_epoch_processing_with(spec, state, 'process_registry_updates') + + # validator moved into activation queue if eligible + validator = state.validators[validator_index] + if validator.effective_balance < spec.MIN_ACTIVATION_BALANCE: + assert validator.activation_eligibility_epoch == spec.FAR_FUTURE_EPOCH + else: + assert validator.activation_eligibility_epoch < spec.FAR_FUTURE_EPOCH + + +@with_electra_and_later +@spec_state_test +def test_activation_queue_eligibility__less_than_min_activation_balance(spec, state): + # move past first two irregular epochs wrt finality + next_epoch(spec, state) + next_epoch(spec, state) + + index = 3 + balance = spec.MIN_ACTIVATION_BALANCE - spec.EFFECTIVE_BALANCE_INCREMENT + yield from run_test_activation_queue_eligibility(spec, state, index, balance) + + +@with_electra_and_later +@spec_state_test +def test_activation_queue_eligibility__min_activation_balance(spec, state): + # move past first two irregular epochs wrt finality + next_epoch(spec, state) + next_epoch(spec, state) + + index = 5 + balance = spec.MIN_ACTIVATION_BALANCE + yield from run_test_activation_queue_eligibility(spec, state, index, balance) + + +@with_electra_and_later +@spec_state_test +def test_activation_queue_eligibility__min_activation_balance_eth1_creds(spec, state): + # move past first two irregular epochs wrt finality + next_epoch(spec, state) + next_epoch(spec, state) + + index = 7 + balance = spec.MIN_ACTIVATION_BALANCE + set_eth1_withdrawal_credential_with_balance(spec, state, index) + yield from run_test_activation_queue_eligibility(spec, state, index, balance) + + +@with_electra_and_later +@spec_state_test +def test_activation_queue_eligibility__min_activation_balance_compounding_creds(spec, state): + # move past first two irregular epochs wrt finality + next_epoch(spec, state) + next_epoch(spec, state) + + index = 11 + balance = spec.MIN_ACTIVATION_BALANCE + set_compounding_withdrawal_credential_with_balance(spec, state, index) + yield from run_test_activation_queue_eligibility(spec, state, index, balance) + + +@with_electra_and_later +@spec_state_test +def test_activation_queue_eligibility__greater_than_min_activation_balance(spec, state): + # move past first two irregular epochs wrt finality + next_epoch(spec, state) + next_epoch(spec, state) + + index = 13 + balance = spec.MIN_ACTIVATION_BALANCE + spec.EFFECTIVE_BALANCE_INCREMENT + set_compounding_withdrawal_credential_with_balance(spec, state, index) + yield from run_test_activation_queue_eligibility(spec, state, index, balance) From 2a06d9165dee10de96b9cb0d7ffcba5898301aa6 Mon Sep 17 00:00:00 2001 From: Mikhail Kalinin Date: Fri, 18 Oct 2024 14:04:55 +0600 Subject: [PATCH 2/6] Add more process_pending_consolidations tests --- .../test_process_pending_consolidations.py | 64 +++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/tests/core/pyspec/eth2spec/test/electra/epoch_processing/test_process_pending_consolidations.py b/tests/core/pyspec/eth2spec/test/electra/epoch_processing/test_process_pending_consolidations.py index 322224b78e..8da4028452 100644 --- a/tests/core/pyspec/eth2spec/test/electra/epoch_processing/test_process_pending_consolidations.py +++ b/tests/core/pyspec/eth2spec/test/electra/epoch_processing/test_process_pending_consolidations.py @@ -302,3 +302,67 @@ def test_pending_consolidation_with_pending_deposit(spec, state): # Pending deposit to the source was not processed. # It should only be processed in the next epoch transition assert state.pending_deposits == [pending_deposit] + + +@with_electra_and_later +@spec_state_test +def test_pending_consolidation_source_balance_less_than_effective(spec, state): + current_epoch = spec.get_current_epoch(state) + source_index = spec.get_active_validator_indices(state, current_epoch)[0] + target_index = spec.get_active_validator_indices(state, current_epoch)[1] + # append pending consolidation + state.pending_consolidations.append( + spec.PendingConsolidation(source_index=source_index, target_index=target_index) + ) + # Set withdrawable epoch to current epoch to allow processing + state.validators[source_index].withdrawable_epoch = current_epoch + # Set the target withdrawal credential to eth1 + eth1_withdrawal_credential = ( + spec.ETH1_ADDRESS_WITHDRAWAL_PREFIX + b"\x00" * 11 + b"\x11" * 20 + ) + state.validators[target_index].withdrawal_credentials = eth1_withdrawal_credential + # Set the source balance to be less than effective_balance + pre_balance_source = state.validators[source_index].effective_balance - spec.EFFECTIVE_BALANCE_INCREMENT // 8 + state.balances[source_index] = pre_balance_source + + pre_balance_target = state.balances[target_index] + + yield from run_epoch_processing_with(spec, state, "process_pending_consolidations") + + # Pending consolidation was successfully processed + assert state.balances[target_index] == pre_balance_target + pre_balance_source + assert state.balances[source_index] == 0 + assert state.pending_consolidations == [] + + +@with_electra_and_later +@spec_state_test +def test_pending_consolidation_source_balance_greater_than_effective(spec, state): + current_epoch = spec.get_current_epoch(state) + source_index = spec.get_active_validator_indices(state, current_epoch)[0] + target_index = spec.get_active_validator_indices(state, current_epoch)[1] + # append pending consolidation + state.pending_consolidations.append( + spec.PendingConsolidation(source_index=source_index, target_index=target_index) + ) + # Set withdrawable epoch to current epoch to allow processing + state.validators[source_index].withdrawable_epoch = current_epoch + # Set the target withdrawal credential to eth1 + eth1_withdrawal_credential = ( + spec.ETH1_ADDRESS_WITHDRAWAL_PREFIX + b"\x00" * 11 + b"\x11" * 20 + ) + state.validators[target_index].withdrawal_credentials = eth1_withdrawal_credential + # Set the source balance to be greater than effective_balance + pre_balance_source = state.validators[source_index].effective_balance + spec.EFFECTIVE_BALANCE_INCREMENT // 8 + state.balances[source_index] = pre_balance_source + + pre_balance_target = state.balances[target_index] + + yield from run_epoch_processing_with(spec, state, "process_pending_consolidations") + + # Pending consolidation was successfully processed + assert state.balances[target_index] == ( + pre_balance_target + spec.get_max_effective_balance(state.validators[source_index])) + assert state.balances[source_index] == ( + pre_balance_source - spec.get_max_effective_balance(state.validators[source_index])) + assert state.pending_consolidations == [] From 84d7ba25b69a3921b927acddcfada39519a1d209 Mon Sep 17 00:00:00 2001 From: Mikhail Kalinin Date: Fri, 18 Oct 2024 14:21:47 +0600 Subject: [PATCH 3/6] Fix linter --- .../electra/epoch_processing/test_process_registry_updates.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/core/pyspec/eth2spec/test/electra/epoch_processing/test_process_registry_updates.py b/tests/core/pyspec/eth2spec/test/electra/epoch_processing/test_process_registry_updates.py index ce5915269a..1f2666402e 100644 --- a/tests/core/pyspec/eth2spec/test/electra/epoch_processing/test_process_registry_updates.py +++ b/tests/core/pyspec/eth2spec/test/electra/epoch_processing/test_process_registry_updates.py @@ -18,7 +18,7 @@ def run_test_activation_queue_eligibility(spec, state, validator_index, balance) # ready for entrance into activation queue mock_deposit(spec, state, validator_index) - + yield from run_epoch_processing_with(spec, state, 'process_registry_updates') # validator moved into activation queue if eligible From a2f9b887ef214b1835733af8ce3c4b4e0e168c08 Mon Sep 17 00:00:00 2001 From: Mikhail Kalinin Date: Fri, 18 Oct 2024 15:51:18 +0600 Subject: [PATCH 4/6] Add more pending deposit tests --- .../test_process_pending_deposits.py | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/tests/core/pyspec/eth2spec/test/electra/epoch_processing/pending_deposits/test_process_pending_deposits.py b/tests/core/pyspec/eth2spec/test/electra/epoch_processing/pending_deposits/test_process_pending_deposits.py index e1f2544020..ee9ceccee7 100644 --- a/tests/core/pyspec/eth2spec/test/electra/epoch_processing/pending_deposits/test_process_pending_deposits.py +++ b/tests/core/pyspec/eth2spec/test/electra/epoch_processing/pending_deposits/test_process_pending_deposits.py @@ -2,6 +2,12 @@ from eth2spec.test.context import ( spec_state_test, with_electra_and_later, + with_presets, + spec_test, + single_phase, + with_custom_state, + scaled_churn_balances_exceed_activation_exit_churn_limit, + default_activation_threshold, ) from eth2spec.test.helpers.deposits import prepare_pending_deposit from eth2spec.test.helpers.state import ( @@ -9,6 +15,7 @@ advance_finality_to, set_full_participation, ) +from eth2spec.test.helpers.constants import MINIMAL def run_process_pending_deposits(spec, state): @@ -488,3 +495,26 @@ def test_process_pending_deposits_withdrawable_validator_not_churned(spec, state assert state.pending_deposits == [ prepare_pending_deposit(spec, validator_index=1, amount=amount) ] + + +@with_electra_and_later +@with_presets([MINIMAL], "need sufficient consolidation churn limit") +@with_custom_state( + balances_fn=scaled_churn_balances_exceed_activation_exit_churn_limit, + threshold_fn=default_activation_threshold, +) +@spec_test +@single_phase +def test_process_pending_deposits_scaled_churn(spec, state): + index = 0 + amount = spec.get_activation_exit_churn_limit(state) + state.pending_deposits.append( + prepare_pending_deposit(spec, index, amount) + ) + 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 == [] From aa5ebb3825400f6844b82d350732316bb5fbb81c Mon Sep 17 00:00:00 2001 From: Mikhail Kalinin Date: Sun, 20 Oct 2024 09:45:27 +0600 Subject: [PATCH 5/6] Apply suggestions by @jtraglia --- .../test_process_pending_consolidations.py | 18 ++++++++++------- .../test_process_registry_updates.py | 20 ------------------- tests/generators/epoch_processing/main.py | 1 + 3 files changed, 12 insertions(+), 27 deletions(-) diff --git a/tests/core/pyspec/eth2spec/test/electra/epoch_processing/test_process_pending_consolidations.py b/tests/core/pyspec/eth2spec/test/electra/epoch_processing/test_process_pending_consolidations.py index 8da4028452..1aca175896 100644 --- a/tests/core/pyspec/eth2spec/test/electra/epoch_processing/test_process_pending_consolidations.py +++ b/tests/core/pyspec/eth2spec/test/electra/epoch_processing/test_process_pending_consolidations.py @@ -306,7 +306,7 @@ def test_pending_consolidation_with_pending_deposit(spec, state): @with_electra_and_later @spec_state_test -def test_pending_consolidation_source_balance_less_than_effective(spec, state): +def test_pending_consolidation_source_balance_less_than_max_effective(spec, state): current_epoch = spec.get_current_epoch(state) source_index = spec.get_active_validator_indices(state, current_epoch)[0] target_index = spec.get_active_validator_indices(state, current_epoch)[1] @@ -327,6 +327,8 @@ def test_pending_consolidation_source_balance_less_than_effective(spec, state): pre_balance_target = state.balances[target_index] + assert state.balances[source_index] < spec.get_max_effective_balance(state.validators[source_index]) + yield from run_epoch_processing_with(spec, state, "process_pending_consolidations") # Pending consolidation was successfully processed @@ -337,7 +339,7 @@ def test_pending_consolidation_source_balance_less_than_effective(spec, state): @with_electra_and_later @spec_state_test -def test_pending_consolidation_source_balance_greater_than_effective(spec, state): +def test_pending_consolidation_source_balance_greater_than_max_effective(spec, state): current_epoch = spec.get_current_epoch(state) source_index = spec.get_active_validator_indices(state, current_epoch)[0] target_index = spec.get_active_validator_indices(state, current_epoch)[1] @@ -353,16 +355,18 @@ def test_pending_consolidation_source_balance_greater_than_effective(spec, state ) state.validators[target_index].withdrawal_credentials = eth1_withdrawal_credential # Set the source balance to be greater than effective_balance - pre_balance_source = state.validators[source_index].effective_balance + spec.EFFECTIVE_BALANCE_INCREMENT // 8 + excess_source_balance = spec.EFFECTIVE_BALANCE_INCREMENT // 8 + pre_balance_source = state.validators[source_index].effective_balance + excess_source_balance state.balances[source_index] = pre_balance_source pre_balance_target = state.balances[target_index] + source_max_effective_balance = spec.get_max_effective_balance(state.validators[source_index]) + assert state.balances[source_index] > source_max_effective_balance + yield from run_epoch_processing_with(spec, state, "process_pending_consolidations") # Pending consolidation was successfully processed - assert state.balances[target_index] == ( - pre_balance_target + spec.get_max_effective_balance(state.validators[source_index])) - assert state.balances[source_index] == ( - pre_balance_source - spec.get_max_effective_balance(state.validators[source_index])) + assert state.balances[target_index] == pre_balance_target + source_max_effective_balance + assert state.balances[source_index] == excess_source_balance assert state.pending_consolidations == [] diff --git a/tests/core/pyspec/eth2spec/test/electra/epoch_processing/test_process_registry_updates.py b/tests/core/pyspec/eth2spec/test/electra/epoch_processing/test_process_registry_updates.py index 1f2666402e..df7764befd 100644 --- a/tests/core/pyspec/eth2spec/test/electra/epoch_processing/test_process_registry_updates.py +++ b/tests/core/pyspec/eth2spec/test/electra/epoch_processing/test_process_registry_updates.py @@ -32,10 +32,6 @@ def run_test_activation_queue_eligibility(spec, state, validator_index, balance) @with_electra_and_later @spec_state_test def test_activation_queue_eligibility__less_than_min_activation_balance(spec, state): - # move past first two irregular epochs wrt finality - next_epoch(spec, state) - next_epoch(spec, state) - index = 3 balance = spec.MIN_ACTIVATION_BALANCE - spec.EFFECTIVE_BALANCE_INCREMENT yield from run_test_activation_queue_eligibility(spec, state, index, balance) @@ -44,10 +40,6 @@ def test_activation_queue_eligibility__less_than_min_activation_balance(spec, st @with_electra_and_later @spec_state_test def test_activation_queue_eligibility__min_activation_balance(spec, state): - # move past first two irregular epochs wrt finality - next_epoch(spec, state) - next_epoch(spec, state) - index = 5 balance = spec.MIN_ACTIVATION_BALANCE yield from run_test_activation_queue_eligibility(spec, state, index, balance) @@ -56,10 +48,6 @@ def test_activation_queue_eligibility__min_activation_balance(spec, state): @with_electra_and_later @spec_state_test def test_activation_queue_eligibility__min_activation_balance_eth1_creds(spec, state): - # move past first two irregular epochs wrt finality - next_epoch(spec, state) - next_epoch(spec, state) - index = 7 balance = spec.MIN_ACTIVATION_BALANCE set_eth1_withdrawal_credential_with_balance(spec, state, index) @@ -69,10 +57,6 @@ def test_activation_queue_eligibility__min_activation_balance_eth1_creds(spec, s @with_electra_and_later @spec_state_test def test_activation_queue_eligibility__min_activation_balance_compounding_creds(spec, state): - # move past first two irregular epochs wrt finality - next_epoch(spec, state) - next_epoch(spec, state) - index = 11 balance = spec.MIN_ACTIVATION_BALANCE set_compounding_withdrawal_credential_with_balance(spec, state, index) @@ -82,10 +66,6 @@ def test_activation_queue_eligibility__min_activation_balance_compounding_creds( @with_electra_and_later @spec_state_test def test_activation_queue_eligibility__greater_than_min_activation_balance(spec, state): - # move past first two irregular epochs wrt finality - next_epoch(spec, state) - next_epoch(spec, state) - index = 13 balance = spec.MIN_ACTIVATION_BALANCE + spec.EFFECTIVE_BALANCE_INCREMENT set_compounding_withdrawal_credential_with_balance(spec, state, index) diff --git a/tests/generators/epoch_processing/main.py b/tests/generators/epoch_processing/main.py index 4c848a9d12..62653e2fe8 100644 --- a/tests/generators/epoch_processing/main.py +++ b/tests/generators/epoch_processing/main.py @@ -40,6 +40,7 @@ _new_electra_mods_1 = {key: 'eth2spec.test.electra.epoch_processing.test_process_' + key for key in [ 'effective_balance_updates', 'pending_consolidations', + 'registry_updates', ]} # This is a trick to allow tests be split into multiple files and use the same test format. _new_electra_mods_2 = {key: 'eth2spec.test.electra.epoch_processing.' + key for key in [ From 44c1c3141f2d97c8570bf0b63e358b0a17231f69 Mon Sep 17 00:00:00 2001 From: Mikhail Kalinin Date: Mon, 21 Oct 2024 13:17:59 +0600 Subject: [PATCH 6/6] Add consolidation tests for comp creds --- .../test_process_pending_consolidations.py | 82 +++++++++++++++++-- 1 file changed, 73 insertions(+), 9 deletions(-) diff --git a/tests/core/pyspec/eth2spec/test/electra/epoch_processing/test_process_pending_consolidations.py b/tests/core/pyspec/eth2spec/test/electra/epoch_processing/test_process_pending_consolidations.py index 1aca175896..b061efee7b 100644 --- a/tests/core/pyspec/eth2spec/test/electra/epoch_processing/test_process_pending_consolidations.py +++ b/tests/core/pyspec/eth2spec/test/electra/epoch_processing/test_process_pending_consolidations.py @@ -9,6 +9,10 @@ from eth2spec.test.helpers.state import ( next_epoch_with_full_participation, ) +from eth2spec.test.helpers.withdrawals import ( + set_eth1_withdrawal_credential_with_balance, + set_compounding_withdrawal_credential_with_balance, +) # *********************** # * CONSOLIDATION TESTS * @@ -316,11 +320,9 @@ def test_pending_consolidation_source_balance_less_than_max_effective(spec, stat ) # Set withdrawable epoch to current epoch to allow processing state.validators[source_index].withdrawable_epoch = current_epoch - # Set the target withdrawal credential to eth1 - eth1_withdrawal_credential = ( - spec.ETH1_ADDRESS_WITHDRAWAL_PREFIX + b"\x00" * 11 + b"\x11" * 20 - ) - state.validators[target_index].withdrawal_credentials = eth1_withdrawal_credential + # Set source and target withdrawal credential to eth1 + set_eth1_withdrawal_credential_with_balance(spec, state, source_index) + set_eth1_withdrawal_credential_with_balance(spec, state, target_index) # Set the source balance to be less than effective_balance pre_balance_source = state.validators[source_index].effective_balance - spec.EFFECTIVE_BALANCE_INCREMENT // 8 state.balances[source_index] = pre_balance_source @@ -349,11 +351,73 @@ def test_pending_consolidation_source_balance_greater_than_max_effective(spec, s ) # Set withdrawable epoch to current epoch to allow processing state.validators[source_index].withdrawable_epoch = current_epoch - # Set the target withdrawal credential to eth1 - eth1_withdrawal_credential = ( - spec.ETH1_ADDRESS_WITHDRAWAL_PREFIX + b"\x00" * 11 + b"\x11" * 20 + # Set source and target withdrawal credential to eth1 + set_eth1_withdrawal_credential_with_balance(spec, state, source_index) + set_eth1_withdrawal_credential_with_balance(spec, state, target_index) + # Set the source balance to be greater than effective_balance + excess_source_balance = spec.EFFECTIVE_BALANCE_INCREMENT // 8 + pre_balance_source = state.validators[source_index].effective_balance + excess_source_balance + state.balances[source_index] = pre_balance_source + + pre_balance_target = state.balances[target_index] + + source_max_effective_balance = spec.get_max_effective_balance(state.validators[source_index]) + assert state.balances[source_index] > source_max_effective_balance + + yield from run_epoch_processing_with(spec, state, "process_pending_consolidations") + + # Pending consolidation was successfully processed + assert state.balances[target_index] == pre_balance_target + source_max_effective_balance + assert state.balances[source_index] == excess_source_balance + assert state.pending_consolidations == [] + + +@with_electra_and_later +@spec_state_test +def test_pending_consolidation_source_balance_less_than_max_effective_compounding(spec, state): + current_epoch = spec.get_current_epoch(state) + source_index = spec.get_active_validator_indices(state, current_epoch)[0] + target_index = spec.get_active_validator_indices(state, current_epoch)[1] + # append pending consolidation + state.pending_consolidations.append( + spec.PendingConsolidation(source_index=source_index, target_index=target_index) ) - state.validators[target_index].withdrawal_credentials = eth1_withdrawal_credential + # Set withdrawable epoch to current epoch to allow processing + state.validators[source_index].withdrawable_epoch = current_epoch + # Set source and target withdrawal credential to compounding + set_compounding_withdrawal_credential_with_balance(spec, state, source_index) + set_compounding_withdrawal_credential_with_balance(spec, state, target_index) + # Set the source balance to be less than effective_balance + pre_balance_source = state.validators[source_index].effective_balance - spec.EFFECTIVE_BALANCE_INCREMENT // 8 + state.balances[source_index] = pre_balance_source + + pre_balance_target = state.balances[target_index] + + assert state.balances[source_index] < spec.get_max_effective_balance(state.validators[source_index]) + + yield from run_epoch_processing_with(spec, state, "process_pending_consolidations") + + # Pending consolidation was successfully processed + assert state.balances[target_index] == pre_balance_target + pre_balance_source + assert state.balances[source_index] == 0 + assert state.pending_consolidations == [] + + +@with_electra_and_later +@spec_state_test +def test_pending_consolidation_source_balance_greater_than_max_effective_compounding(spec, state): + current_epoch = spec.get_current_epoch(state) + source_index = spec.get_active_validator_indices(state, current_epoch)[0] + target_index = spec.get_active_validator_indices(state, current_epoch)[1] + # append pending consolidation + state.pending_consolidations.append( + spec.PendingConsolidation(source_index=source_index, target_index=target_index) + ) + # Set withdrawable epoch to current epoch to allow processing + state.validators[source_index].withdrawable_epoch = current_epoch + # Set source and target withdrawal credential to compounding + set_compounding_withdrawal_credential_with_balance(spec, state, source_index) + set_compounding_withdrawal_credential_with_balance(spec, state, target_index) # Set the source balance to be greater than effective_balance excess_source_balance = spec.EFFECTIVE_BALANCE_INCREMENT // 8 pre_balance_source = state.validators[source_index].effective_balance + excess_source_balance