Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

eip7251: Add missed exit checks to consolidation processing #4000

Merged
merged 1 commit into from
Nov 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions specs/electra/beacon-chain.md
Original file line number Diff line number Diff line change
Expand Up @@ -1626,6 +1626,12 @@ def process_consolidation_request(
return
if target_validator.exit_epoch != FAR_FUTURE_EPOCH:
return
# Verify the source has been active long enough
if current_epoch < source_validator.activation_epoch + SHARD_COMMITTEE_PERIOD:
return
# Verify the source has no pending withdrawals in the queue
if get_pending_balance_to_withdraw(state, source_index) > 0:
return

# Initiate source validator exit and append pending consolidation
source_validator.exit_epoch = compute_consolidation_epoch_and_update_churn(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@
@spec_test
@single_phase
def test_basic_consolidation_in_current_consolidation_epoch(spec, state):
# move state forward SHARD_COMMITTEE_PERIOD epochs to allow for consolidation
state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH
# This state has 256 validators each with 32 ETH in MINIMAL preset, 128 ETH consolidation churn
current_epoch = spec.get_current_epoch(state)
source_index = spec.get_active_validator_indices(state, current_epoch)[0]
Expand Down Expand Up @@ -75,6 +77,8 @@ def test_basic_consolidation_in_current_consolidation_epoch(spec, state):
@spec_test
@single_phase
def test_basic_consolidation_with_excess_target_balance(spec, state):
# move state forward SHARD_COMMITTEE_PERIOD epochs to allow for consolidation
state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH
# This state has 256 validators each with 32 ETH in MINIMAL preset, 128 ETH consolidation churn
current_epoch = spec.get_current_epoch(state)
source_index = spec.get_active_validator_indices(state, current_epoch)[0]
Expand Down Expand Up @@ -125,6 +129,8 @@ def test_basic_consolidation_with_excess_target_balance(spec, state):
@spec_test
@single_phase
def test_basic_consolidation_with_excess_target_balance_and_compounding_credentials(spec, state):
# move state forward SHARD_COMMITTEE_PERIOD epochs to allow for consolidation
state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH
# This state has 256 validators each with 32 ETH in MINIMAL preset, 128 ETH consolidation churn
current_epoch = spec.get_current_epoch(state)
source_index = spec.get_active_validator_indices(state, current_epoch)[0]
Expand Down Expand Up @@ -175,6 +181,8 @@ def test_basic_consolidation_with_excess_target_balance_and_compounding_credenti
@spec_test
@single_phase
def test_basic_consolidation_in_new_consolidation_epoch(spec, state):
# move state forward SHARD_COMMITTEE_PERIOD epochs to allow for consolidation
state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH
# This state has 256 validators each with 32 ETH in MINIMAL preset, 128 ETH consolidation churn
# Set consolidation balance to consume to some arbitrary nonzero value below the churn limit
state.consolidation_balance_to_consume = spec.EFFECTIVE_BALANCE_INCREMENT
Expand Down Expand Up @@ -220,6 +228,8 @@ def test_basic_consolidation_in_new_consolidation_epoch(spec, state):
@spec_test
@single_phase
def test_basic_consolidation_with_preexisting_churn(spec, state):
# move state forward SHARD_COMMITTEE_PERIOD epochs to allow for consolidation
state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH
# This state has 256 validators each with 32 ETH in MINIMAL preset, 128 ETH consolidation churn
current_epoch = spec.get_current_epoch(state)
source_index = spec.get_active_validator_indices(state, current_epoch)[0]
Expand Down Expand Up @@ -267,6 +277,8 @@ def test_basic_consolidation_with_preexisting_churn(spec, state):
@spec_test
@single_phase
def test_basic_consolidation_with_insufficient_preexisting_churn(spec, state):
# move state forward SHARD_COMMITTEE_PERIOD epochs to allow for consolidation
state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH
# This state has 256 validators each with 32 ETH in MINIMAL preset, 128 ETH consolidation churn
current_epoch = spec.get_current_epoch(state)
source_index = spec.get_active_validator_indices(state, current_epoch)[0]
Expand Down Expand Up @@ -318,6 +330,8 @@ def test_basic_consolidation_with_insufficient_preexisting_churn(spec, state):
@spec_test
@single_phase
def test_basic_consolidation_with_compounding_credentials(spec, state):
# move state forward SHARD_COMMITTEE_PERIOD epochs to allow for consolidation
state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH
# This state has 256 validators each with 32 ETH in MINIMAL preset, 128 ETH consolidation churn
current_epoch = spec.get_current_epoch(state)
source_index = spec.get_active_validator_indices(state, current_epoch)[0]
Expand Down Expand Up @@ -363,6 +377,8 @@ def test_basic_consolidation_with_compounding_credentials(spec, state):
@spec_test
@single_phase
def test_consolidation_churn_limit_balance(spec, state):
# move state forward SHARD_COMMITTEE_PERIOD epochs to allow for consolidation
state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH
# This state has 256 validators each with 32 ETH in MINIMAL preset, 128 ETH consolidation churn
current_epoch = spec.get_current_epoch(state)
source_index = spec.get_active_validator_indices(state, current_epoch)[0]
Expand Down Expand Up @@ -411,6 +427,8 @@ def test_consolidation_churn_limit_balance(spec, state):
@spec_test
@single_phase
def test_consolidation_balance_larger_than_churn_limit(spec, state):
# move state forward SHARD_COMMITTEE_PERIOD epochs to allow for consolidation
state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH
# This state has 256 validators each with 32 ETH in MINIMAL preset, 128 ETH consolidation churn
current_epoch = spec.get_current_epoch(state)
source_index = spec.get_active_validator_indices(state, current_epoch)[0]
Expand Down Expand Up @@ -458,6 +476,8 @@ def test_consolidation_balance_larger_than_churn_limit(spec, state):
@spec_test
@single_phase
def test_consolidation_balance_through_two_churn_epochs(spec, state):
# move state forward SHARD_COMMITTEE_PERIOD epochs to allow for consolidation
state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH
# This state has 256 validators each with 32 ETH in MINIMAL preset, 128 ETH consolidation churn
current_epoch = spec.get_current_epoch(state)
source_index = spec.get_active_validator_indices(state, current_epoch)[0]
Expand Down Expand Up @@ -498,6 +518,8 @@ def test_consolidation_balance_through_two_churn_epochs(spec, state):
@with_electra_and_later
@spec_state_test
def test_basic_switch_to_compounding(spec, state):
# move state forward SHARD_COMMITTEE_PERIOD epochs to allow for consolidation
state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH
current_epoch = spec.get_current_epoch(state)
source_index = spec.get_active_validator_indices(state, current_epoch)[0]

Expand Down Expand Up @@ -583,6 +605,9 @@ def test_switch_to_compounding_with_pending_consolidations_at_limit(spec, state)
@spec_test
@single_phase
def test_incorrect_exceed_pending_consolidations_limit(spec, state):
# move state forward SHARD_COMMITTEE_PERIOD epochs to allow for consolidation
state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH

state.pending_consolidations = [
spec.PendingConsolidation(source_index=0, target_index=1)
] * spec.PENDING_CONSOLIDATIONS_LIMIT
Expand Down Expand Up @@ -614,6 +639,9 @@ def test_incorrect_exceed_pending_consolidations_limit(spec, state):
@spec_state_test
@single_phase
def test_incorrect_not_enough_consolidation_churn_available(spec, state):
# move state forward SHARD_COMMITTEE_PERIOD epochs to allow for consolidation
state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH

state.pending_consolidations = [
spec.PendingConsolidation(source_index=0, target_index=1)
]
Expand Down Expand Up @@ -651,6 +679,8 @@ def test_incorrect_not_enough_consolidation_churn_available(spec, state):
@spec_test
@single_phase
def test_incorrect_exited_source(spec, state):
# move state forward SHARD_COMMITTEE_PERIOD epochs to allow for consolidation
state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH
# Set up an otherwise correct consolidation
current_epoch = spec.get_current_epoch(state)
source_index = spec.get_active_validator_indices(state, current_epoch)[0]
Expand Down Expand Up @@ -686,6 +716,8 @@ def test_incorrect_exited_source(spec, state):
@spec_test
@single_phase
def test_incorrect_exited_target(spec, state):
# move state forward SHARD_COMMITTEE_PERIOD epochs to allow for consolidation
state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH
# Set up an otherwise correct consolidation
current_epoch = spec.get_current_epoch(state)
source_index = spec.get_active_validator_indices(state, current_epoch)[0]
Expand Down Expand Up @@ -720,6 +752,8 @@ def test_incorrect_exited_target(spec, state):
@spec_test
@single_phase
def test_incorrect_inactive_source(spec, state):
# move state forward SHARD_COMMITTEE_PERIOD epochs to allow for consolidation
state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH
# Set up an otherwise correct consolidation
current_epoch = spec.get_current_epoch(state)
source_index = spec.get_active_validator_indices(state, current_epoch)[0]
Expand Down Expand Up @@ -755,6 +789,8 @@ def test_incorrect_inactive_source(spec, state):
@spec_test
@single_phase
def test_incorrect_inactive_target(spec, state):
# move state forward SHARD_COMMITTEE_PERIOD epochs to allow for consolidation
state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH
# Set up an otherwise correct consolidation
current_epoch = spec.get_current_epoch(state)
source_index = spec.get_active_validator_indices(state, current_epoch)[0]
Expand Down Expand Up @@ -790,6 +826,8 @@ def test_incorrect_inactive_target(spec, state):
@spec_test
@single_phase
def test_incorrect_no_source_execution_withdrawal_credential(spec, state):
# move state forward SHARD_COMMITTEE_PERIOD epochs to allow for consolidation
state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH
# Set up a correct consolidation, but source does not have
# an execution withdrawal credential
current_epoch = spec.get_current_epoch(state)
Expand Down Expand Up @@ -820,6 +858,8 @@ def test_incorrect_no_source_execution_withdrawal_credential(spec, state):
@spec_test
@single_phase
def test_incorrect_no_target_execution_withdrawal_credential(spec, state):
# move state forward SHARD_COMMITTEE_PERIOD epochs to allow for consolidation
state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH
# Set up a correct consolidation, but target does not have
# an execution withdrawal credential
current_epoch = spec.get_current_epoch(state)
Expand Down Expand Up @@ -852,6 +892,8 @@ def test_incorrect_no_target_execution_withdrawal_credential(spec, state):
@spec_test
@single_phase
def test_incorrect_incorrect_source_address(spec, state):
# move state forward SHARD_COMMITTEE_PERIOD epochs to allow for consolidation
state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH
# Set up an otherwise correct consolidation
current_epoch = spec.get_current_epoch(state)
source_index = spec.get_active_validator_indices(state, current_epoch)[0]
Expand Down Expand Up @@ -885,6 +927,8 @@ def test_incorrect_incorrect_source_address(spec, state):
@spec_test
@single_phase
def test_incorrect_unknown_source_pubkey(spec, state):
# move state forward SHARD_COMMITTEE_PERIOD epochs to allow for consolidation
state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH
# Set up an otherwise correct consolidation
current_epoch = spec.get_current_epoch(state)
source_index = spec.get_active_validator_indices(state, current_epoch)[0]
Expand Down Expand Up @@ -918,6 +962,8 @@ def test_incorrect_unknown_source_pubkey(spec, state):
@spec_test
@single_phase
def test_incorrect_unknown_target_pubkey(spec, state):
# move state forward SHARD_COMMITTEE_PERIOD epochs to allow for consolidation
state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH
# Set up an otherwise correct consolidation
current_epoch = spec.get_current_epoch(state)
source_index = spec.get_active_validator_indices(state, current_epoch)[0]
Expand All @@ -942,6 +988,80 @@ def test_incorrect_unknown_target_pubkey(spec, state):
)


@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_incorrect_source_has_pending_withdrawal(spec, state):
# move state forward SHARD_COMMITTEE_PERIOD epochs to allow for consolidation
state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH
# Set up an otherwise correct consolidation
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]
source_address = b"\x22" * 20
excess_balance = spec.EFFECTIVE_BALANCE_INCREMENT // 4
set_eth1_withdrawal_credential_with_balance(
spec, state, source_index, address=source_address, balance=spec.MIN_ACTIVATION_BALANCE + excess_balance
)
consolidation = spec.ConsolidationRequest(
source_address=source_address,
source_pubkey=state.validators[source_index].pubkey,
target_pubkey=state.validators[target_index].pubkey,
)
set_eth1_withdrawal_credential_with_balance(spec, state, target_index)

# Create pending withdrawal
pending_withdrawal = spec.PendingPartialWithdrawal(
index=0, amount=excess_balance, withdrawable_epoch=current_epoch
)
state.pending_partial_withdrawals.append(pending_withdrawal)

# Check the return condition
assert spec.get_pending_balance_to_withdraw(state, source_index) > 0

yield from run_consolidation_processing(
spec, state, consolidation, success=False
)


@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_incorrect_source_not_active_long_enough(spec, state):
# Set up an otherwise correct consolidation
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]
source_address = b"\x22" * 20
excess_balance = spec.EFFECTIVE_BALANCE_INCREMENT // 4
set_eth1_withdrawal_credential_with_balance(
spec, state, source_index, address=source_address, balance=spec.MIN_ACTIVATION_BALANCE + excess_balance
)
consolidation = spec.ConsolidationRequest(
source_address=source_address,
source_pubkey=state.validators[source_index].pubkey,
target_pubkey=state.validators[target_index].pubkey,
)
set_eth1_withdrawal_credential_with_balance(spec, state, target_index)

# Check the return condition
assert current_epoch < state.validators[source_index].activation_epoch + spec.config.SHARD_COMMITTEE_PERIOD

yield from run_consolidation_processing(
spec, state, consolidation, success=False
)


@with_electra_and_later
@spec_state_test
def test_switch_to_compounding_exited_source(spec, state):
Expand Down