Skip to content

Add a new consolidation test & two new pending deposit tests #4109

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

Merged
merged 5 commits into from
Jan 30, 2025
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
2 changes: 1 addition & 1 deletion tests/core/pyspec/eth2spec/test/context.py
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ def scaled_churn_balances_exceed_activation_churn_limit(spec: Spec):
def scaled_churn_balances_exceed_activation_exit_churn_limit(spec: Spec):
"""
Helper method to create enough validators to scale the churn limit.
(The number of validators is double the amount need for the max activation/exit churn limit)
(The number of validators is double the amount need for the max activation/exit churn limit)
Usage: `@with_custom_state(balances_fn=scaled_churn_balances_exceed_activation_churn_limit, ...)`
"""
num_validators = (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -367,6 +367,61 @@ def test_consolidation_churn_limit_balance(spec, state):
assert state.validators[source_index].exit_epoch == expected_exit_epoch


@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_basic_consolidation_source_has_less_than_max_effective_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]
target_index = spec.get_active_validator_indices(state, current_epoch)[1]

# Set source to eth1 credentials
source_address = b"\x22" * 20
set_eth1_withdrawal_credential_with_balance(
spec, state, source_index, address=source_address
)

# Lower the source validator's effective balance
source_effective_balance = spec.MAX_EFFECTIVE_BALANCE - spec.EFFECTIVE_BALANCE_INCREMENT
state.validators[source_index].effective_balance = source_effective_balance

# Make consolidation with source address
consolidation = spec.ConsolidationRequest(
source_address=source_address,
source_pubkey=state.validators[source_index].pubkey,
target_pubkey=state.validators[target_index].pubkey,
)

# Set target to compounding credentials
set_compounding_withdrawal_credential(spec, state, target_index)

# Set earliest consolidation epoch to the expected exit epoch
expected_exit_epoch = spec.compute_activation_exit_epoch(current_epoch)
state.earliest_consolidation_epoch = expected_exit_epoch
consolidation_churn_limit = spec.get_consolidation_churn_limit(state)
# Set the consolidation balance to consume equal to churn limit
state.consolidation_balance_to_consume = consolidation_churn_limit

yield from run_consolidation_processing(spec, state, consolidation)

# Check consolidation churn is decremented correctly
assert (
state.consolidation_balance_to_consume
== consolidation_churn_limit - source_effective_balance
)
# Check exit epoch
assert state.validators[source_index].exit_epoch == expected_exit_epoch


@with_electra_and_later
@with_presets([MINIMAL], "need sufficient consolidation churn limit")
@with_custom_state(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,7 @@ def test_incorrect_withdrawal_credential_prefix(spec, state):

@with_electra_and_later
@spec_state_test
def test_on_withdrawal_request_initiated_validator(spec, state):
def test_on_withdrawal_request_initiated_exit_validator(spec, state):
rng = random.Random(1342)
# move state forward SHARD_COMMITTEE_PERIOD epochs to allow for exit
state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH
Expand Down Expand Up @@ -766,9 +766,7 @@ def test_insufficient_effective_balance(spec, state):
address = b"\x22" * 20
amount = spec.EFFECTIVE_BALANCE_INCREMENT
# Make effective balance insufficient
state.validators[
validator_index
].effective_balance -= spec.EFFECTIVE_BALANCE_INCREMENT
state.validators[validator_index].effective_balance -= spec.EFFECTIVE_BALANCE_INCREMENT
# Make sure validator has enough balance to withdraw
state.balances[validator_index] += spec.EFFECTIVE_BALANCE_INCREMENT

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
def test_apply_pending_deposit_under_min_activation(spec, state):
# fresh deposit = next validator index = validator appended to registry
validator_index = len(state.validators)
# effective balance will be 1 EFFECTIVE_BALANCE_INCREMENT smaller because of this small decrement.
# effective balance will be 1 EFFECTIVE_BALANCE_INCREMENT smaller because of this small decrement
amount = spec.MIN_ACTIVATION_BALANCE - 1
pending_deposit = prepare_pending_deposit(spec, validator_index, amount, signed=True)

Expand Down Expand Up @@ -47,6 +47,22 @@ def test_apply_pending_deposit_over_min_activation(spec, state):
yield from run_pending_deposit_applying(spec, state, pending_deposit, validator_index)


@with_electra_and_later
@spec_state_test
def test_apply_pending_deposit_over_min_activation_next_increment(spec, state):
# fresh deposit = next validator index = validator appended to registry
validator_index = len(state.validators)
# set deposit amount to the next effective balance increment over the limit
# the validator's effective balance should be set to pre-electra MAX_EFFECTIVE_BALANCE
amount = spec.MAX_EFFECTIVE_BALANCE + spec.EFFECTIVE_BALANCE_INCREMENT
pending_deposit = prepare_pending_deposit(spec, validator_index, amount, signed=True)

yield from run_pending_deposit_applying(spec, state, pending_deposit, validator_index)

# check validator's effective balance
assert state.validators[validator_index].effective_balance == spec.MAX_EFFECTIVE_BALANCE


@with_electra_and_later
@spec_state_test
def test_apply_pending_deposit_eth1_withdrawal_credentials(spec, state):
Expand Down Expand Up @@ -79,7 +95,7 @@ def test_apply_pending_deposit_compounding_withdrawal_credentials_under_max(spec
+ b'\x00' * 11 # specified 0s
+ b'\x59' * 20 # a 20-byte eth1 address
)
# effective balance will be 1 EFFECTIVE_BALANCE_INCREMENT smaller because of this small decrement.
# effective balance will be 1 EFFECTIVE_BALANCE_INCREMENT smaller because of this small decrement
amount = spec.MAX_EFFECTIVE_BALANCE_ELECTRA - 1
pending_deposit = prepare_pending_deposit(
spec,
Expand All @@ -102,7 +118,7 @@ def test_apply_pending_deposit_compounding_withdrawal_credentials_max(spec, stat
+ b'\x00' * 11 # specified 0s
+ b'\x59' * 20 # a 20-byte eth1 address
)
# effective balance will be exactly the same as balance.
# effective balance will be exactly the same as balance
amount = spec.MAX_EFFECTIVE_BALANCE_ELECTRA
pending_deposit = prepare_pending_deposit(
spec,
Expand Down Expand Up @@ -138,6 +154,33 @@ def test_apply_pending_deposit_compounding_withdrawal_credentials_over_max(spec,
yield from run_pending_deposit_applying(spec, state, pending_deposit, validator_index)


@with_electra_and_later
@spec_state_test
def test_apply_pending_deposit_compounding_withdrawal_credentials_over_max_next_increment(spec, state):
# fresh deposit = next validator index = validator appended to registry
validator_index = len(state.validators)
withdrawal_credentials = (
spec.COMPOUNDING_WITHDRAWAL_PREFIX
+ b'\x00' * 11 # specified 0s
+ b'\x59' * 20 # a 20-byte eth1 address
)
# set deposit amount to the next effective balance increment over the limit
# the validator's effective balance should be set to MAX_EFFECTIVE_BALANCE_ELECTRA
amount = spec.MAX_EFFECTIVE_BALANCE_ELECTRA + spec.EFFECTIVE_BALANCE_INCREMENT
pending_deposit = prepare_pending_deposit(
spec,
validator_index,
amount,
withdrawal_credentials=withdrawal_credentials,
signed=True,
)

yield from run_pending_deposit_applying(spec, state, pending_deposit, validator_index)

# check validator's effective balance
assert state.validators[validator_index].effective_balance == spec.MAX_EFFECTIVE_BALANCE_ELECTRA


@with_electra_and_later
@spec_state_test
def test_apply_pending_deposit_non_versioned_withdrawal_credentials(spec, state):
Expand Down Expand Up @@ -347,7 +390,7 @@ def test_apply_pending_deposit_key_validate_invalid_subgroup(spec, state):
validator_index = len(state.validators)
amount = spec.MIN_ACTIVATION_BALANCE

# All-zero pubkey would not pass `bls.KeyValidate`, but `apply_pending_deposit` would not throw exception.
# All-zero pubkey would not pass `bls.KeyValidate`, but `apply_pending_deposit` would not throw exception
pubkey = b'\x00' * 48

pending_deposit = prepare_pending_deposit(spec, validator_index, amount, pubkey=pubkey, signed=True)
Expand All @@ -362,8 +405,8 @@ def test_apply_pending_deposit_key_validate_invalid_decompression(spec, state):
validator_index = len(state.validators)
amount = spec.MIN_ACTIVATION_BALANCE

# `deserialization_fails_infinity_with_true_b_flag` BLS G1 deserialization test case.
# This pubkey would not pass `bls.KeyValidate`, but `apply_pending_deposit` would not throw exception.
# `deserialization_fails_infinity_with_true_b_flag` BLS G1 deserialization test case
# This pubkey would not pass `bls.KeyValidate`, but `apply_pending_deposit` would not throw exception
pubkey_hex = 'c01000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'
pubkey = bytes.fromhex(pubkey_hex)

Expand Down Expand Up @@ -393,9 +436,9 @@ def test_apply_pending_deposit_ineffective_deposit_with_bad_fork_version(spec, s
@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`.
# It's an ineffective deposit because it fails at BLS sig verification.
# NOTE: it was effective in Altair.
# Since deposits are valid across forks, the domain is always set with `GENESIS_FORK_VERSION`
# It's an ineffective deposit because it fails at BLS sig verification
# NOTE: it was effective in Altair
assert state.fork.previous_version != state.fork.current_version

validator_index = len(state.validators)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -438,12 +438,12 @@ def test_process_pending_deposits_multiple_pending_one_skipped(spec, state):
@with_electra_and_later
@spec_state_test
def test_process_pending_deposits_mixture_of_skipped_and_above_churn(spec, state):
amount01 = spec.EFFECTIVE_BALANCE_INCREMENT
amount1 = 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(
prepare_pending_deposit(spec, validator_index=i, amount=amount01)
prepare_pending_deposit(spec, validator_index=i, amount=amount1)
)
state.pending_deposits.append(
prepare_pending_deposit(spec, validator_index=2, amount=amount2)
Expand All @@ -455,18 +455,18 @@ def test_process_pending_deposits_mixture_of_skipped_and_above_churn(spec, state
yield from run_process_pending_deposits(spec, state)

# First deposit is processed
assert state.balances[0] == pre_balances[0] + amount01
assert state.balances[0] == pre_balances[0] + amount1
# Second deposit is postponed, third is above churn
for i in [1, 2]:
assert state.balances[i] == pre_balances[i]
# First deposit consumes some deposit balance
# Deposit is not processed
wanted_balance = spec.get_activation_exit_churn_limit(state) - amount01
wanted_balance = spec.get_activation_exit_churn_limit(state) - amount1
assert state.deposit_balance_to_consume == wanted_balance
# second and third deposit still in the queue
assert state.pending_deposits == [
prepare_pending_deposit(spec, validator_index=2, amount=amount2),
prepare_pending_deposit(spec, validator_index=1, amount=amount01)
prepare_pending_deposit(spec, validator_index=1, amount=amount1)
]


Expand Down