mirror of
https://github.com/status-im/eth2.0-specs.git
synced 2025-02-04 14:54:53 +00:00
Merge pull request #3656 from ralexstokes/fix-7251-tests
Fix EIP-7251 tests
This commit is contained in:
commit
77ec547cc7
@ -168,6 +168,19 @@ jobs:
|
||||
command: make citest fork=electra
|
||||
- store_test_results:
|
||||
path: tests/core/pyspec/test-reports
|
||||
test-eip7251:
|
||||
docker:
|
||||
- image: circleci/python:3.9
|
||||
working_directory: ~/specs-repo
|
||||
steps:
|
||||
- restore_cache:
|
||||
key: v3-specs-repo-{{ .Branch }}-{{ .Revision }}
|
||||
- restore_pyspec_cached_venv
|
||||
- run:
|
||||
name: Run py-tests
|
||||
command: make citest fork=eip7251
|
||||
- store_test_results:
|
||||
path: tests/core/pyspec/test-reports
|
||||
test-whisk:
|
||||
docker:
|
||||
- image: circleci/python:3.9
|
||||
@ -317,6 +330,9 @@ workflows:
|
||||
- test-electra:
|
||||
requires:
|
||||
- install_pyspec_test
|
||||
- test-eip7251:
|
||||
requires:
|
||||
- install_pyspec_test
|
||||
- test-whisk:
|
||||
requires:
|
||||
- install_pyspec_test
|
||||
|
2
.github/workflows/run-tests.yml
vendored
2
.github/workflows/run-tests.yml
vendored
@ -71,7 +71,7 @@ jobs:
|
||||
needs: [preclear,lint,codespell,table_of_contents]
|
||||
strategy:
|
||||
matrix:
|
||||
version: ["phase0", "altair", "bellatrix", "capella", "deneb", "electra", "whisk", "eip7594"]
|
||||
version: ["phase0", "altair", "bellatrix", "capella", "deneb", "electra", "eip7251", "whisk", "eip7594"]
|
||||
steps:
|
||||
- name: Checkout this repo
|
||||
uses: actions/checkout@v3.2.0
|
||||
|
2
Makefile
2
Makefile
@ -35,7 +35,7 @@ MARKDOWN_FILES = $(wildcard $(SPEC_DIR)/*/*.md) \
|
||||
$(wildcard $(SPEC_DIR)/_features/*/*/*.md) \
|
||||
$(wildcard $(SSZ_DIR)/*.md)
|
||||
|
||||
ALL_EXECUTABLE_SPEC_NAMES = phase0 altair bellatrix capella deneb electra whisk
|
||||
ALL_EXECUTABLE_SPEC_NAMES = phase0 altair bellatrix capella deneb electra eip7251 whisk
|
||||
# The parameters for commands. Use `foreach` to avoid listing specs again.
|
||||
COVERAGE_SCOPE := $(foreach S,$(ALL_EXECUTABLE_SPEC_NAMES), --cov=eth2spec.$S.$(TEST_PRESET_TYPE))
|
||||
PYLINT_SCOPE := $(foreach S,$(ALL_EXECUTABLE_SPEC_NAMES), ./eth2spec/$S)
|
||||
|
@ -509,7 +509,7 @@ def initiate_validator_exit(state: BeaconState, index: ValidatorIndex) -> None:
|
||||
def switch_to_compounding_validator(state: BeaconState, index: ValidatorIndex) -> None:
|
||||
validator = state.validators[index]
|
||||
if has_eth1_withdrawal_credential(validator):
|
||||
validator.withdrawal_credentials[:1] = COMPOUNDING_WITHDRAWAL_PREFIX
|
||||
validator.withdrawal_credentials = COMPOUNDING_WITHDRAWAL_PREFIX + validator.withdrawal_credentials[1:]
|
||||
queue_excess_active_balance(state, index)
|
||||
```
|
||||
|
||||
@ -1055,7 +1055,7 @@ def process_voluntary_exit(state: BeaconState, signed_voluntary_exit: SignedVolu
|
||||
assert get_current_epoch(state) >= voluntary_exit.epoch
|
||||
# Verify the validator has been active long enough
|
||||
assert get_current_epoch(state) >= validator.activation_epoch + SHARD_COMMITTEE_PERIOD
|
||||
# Only exit validator if it has no pending withdrawals in the queue
|
||||
# [New in EIP-7251] Only exit validator if it has no pending withdrawals in the queue
|
||||
assert get_pending_balance_to_withdraw(state, voluntary_exit.validator_index) == 0 # [New in EIP7251]
|
||||
# Verify signature
|
||||
domain = compute_domain(DOMAIN_VOLUNTARY_EXIT, CAPELLA_FORK_VERSION, state.genesis_validators_root)
|
||||
|
@ -2,6 +2,7 @@ from eth2spec.test.context import (
|
||||
spec_state_test,
|
||||
with_capella_and_later,
|
||||
)
|
||||
from eth2spec.test.helpers.forks import is_post_eip7251
|
||||
from eth2spec.test.helpers.state import next_epoch_via_block
|
||||
from eth2spec.test.helpers.deposits import (
|
||||
prepare_state_and_deposit,
|
||||
@ -30,10 +31,25 @@ def test_success_top_up_to_withdrawn_validator(spec, state):
|
||||
|
||||
yield from run_deposit_processing(spec, state, deposit, validator_index)
|
||||
|
||||
assert state.balances[validator_index] == amount
|
||||
assert state.validators[validator_index].effective_balance == 0
|
||||
if is_post_eip7251(spec):
|
||||
pending_balance_deposits_len = len(state.pending_balance_deposits)
|
||||
pending_balance_deposit = state.pending_balance_deposits[pending_balance_deposits_len - 1]
|
||||
assert pending_balance_deposit.amount == amount
|
||||
assert pending_balance_deposit.index == validator_index
|
||||
else:
|
||||
assert state.balances[validator_index] == amount
|
||||
assert state.validators[validator_index].effective_balance == 0
|
||||
|
||||
validator = state.validators[validator_index]
|
||||
balance = state.balances[validator_index]
|
||||
current_epoch = spec.get_current_epoch(state)
|
||||
assert spec.is_fully_withdrawable_validator(validator, balance, current_epoch)
|
||||
|
||||
if is_post_eip7251(spec):
|
||||
has_execution_withdrawal = spec.has_execution_withdrawal_credential(validator)
|
||||
is_withdrawable = validator.withdrawable_epoch <= current_epoch
|
||||
has_non_zero_balance = pending_balance_deposit.amount > 0
|
||||
# NOTE: directly compute `is_fully_withdrawable_validator` conditions here
|
||||
# to work around how the epoch processing changed balance updates
|
||||
assert has_execution_withdrawal and is_withdrawable and has_non_zero_balance
|
||||
else:
|
||||
assert spec.is_fully_withdrawable_validator(validator, balance, current_epoch)
|
||||
|
@ -19,6 +19,7 @@ from eth2spec.test.helpers.state import (
|
||||
next_slot,
|
||||
)
|
||||
from eth2spec.test.helpers.withdrawals import (
|
||||
get_expected_withdrawals,
|
||||
prepare_expected_withdrawals,
|
||||
set_eth1_withdrawal_credential_with_balance,
|
||||
set_validator_fully_withdrawable,
|
||||
@ -62,7 +63,7 @@ def run_withdrawals_processing(spec, state, execution_payload, num_expected_with
|
||||
- post-state ('post').
|
||||
If ``valid == False``, run expecting ``AssertionError``
|
||||
"""
|
||||
expected_withdrawals = spec.get_expected_withdrawals(state)
|
||||
expected_withdrawals = get_expected_withdrawals(spec, state)
|
||||
assert len(expected_withdrawals) <= spec.MAX_WITHDRAWALS_PER_PAYLOAD
|
||||
if num_expected_withdrawals is not None:
|
||||
assert len(expected_withdrawals) == num_expected_withdrawals
|
||||
@ -87,7 +88,7 @@ def run_withdrawals_processing(spec, state, execution_payload, num_expected_with
|
||||
assert state.next_withdrawal_validator_index == next_withdrawal_validator_index % len(state.validators)
|
||||
elif len(expected_withdrawals) <= spec.MAX_WITHDRAWALS_PER_PAYLOAD:
|
||||
bound = min(spec.MAX_VALIDATORS_PER_WITHDRAWALS_SWEEP, spec.MAX_WITHDRAWALS_PER_PAYLOAD)
|
||||
assert len(spec.get_expected_withdrawals(state)) <= bound
|
||||
assert len(get_expected_withdrawals(spec, state)) <= bound
|
||||
elif len(expected_withdrawals) > spec.MAX_WITHDRAWALS_PER_PAYLOAD:
|
||||
raise ValueError('len(expected_withdrawals) should not be greater than MAX_WITHDRAWALS_PER_PAYLOAD')
|
||||
|
||||
@ -100,7 +101,7 @@ def run_withdrawals_processing(spec, state, execution_payload, num_expected_with
|
||||
@with_capella_and_later
|
||||
@spec_state_test
|
||||
def test_success_zero_expected_withdrawals(spec, state):
|
||||
assert len(spec.get_expected_withdrawals(state)) == 0
|
||||
assert len(get_expected_withdrawals(spec, state)) == 0
|
||||
|
||||
next_slot(spec, state)
|
||||
execution_payload = build_empty_execution_payload(spec, state)
|
||||
|
@ -1,4 +1,5 @@
|
||||
from eth2spec.test.helpers.constants import MINIMAL
|
||||
from eth2spec.test.helpers.forks import is_post_eip7251
|
||||
from eth2spec.test.context import (
|
||||
with_capella_and_later,
|
||||
spec_state_test,
|
||||
@ -20,6 +21,7 @@ from eth2spec.test.helpers.attestations import (
|
||||
next_epoch_with_attestations,
|
||||
)
|
||||
from eth2spec.test.helpers.withdrawals import (
|
||||
get_expected_withdrawals,
|
||||
set_eth1_withdrawal_credential_with_balance,
|
||||
set_validator_fully_withdrawable,
|
||||
set_validator_partially_withdrawable,
|
||||
@ -202,7 +204,7 @@ def test_full_withdrawal_in_epoch_transition(spec, state):
|
||||
index = 0
|
||||
current_epoch = spec.get_current_epoch(state)
|
||||
set_validator_fully_withdrawable(spec, state, index, current_epoch)
|
||||
assert len(spec.get_expected_withdrawals(state)) == 1
|
||||
assert len(get_expected_withdrawals(spec, state)) == 1
|
||||
|
||||
yield 'pre', state
|
||||
|
||||
@ -214,7 +216,7 @@ def test_full_withdrawal_in_epoch_transition(spec, state):
|
||||
yield 'post', state
|
||||
|
||||
assert state.balances[index] == 0
|
||||
assert len(spec.get_expected_withdrawals(state)) == 0
|
||||
assert len(get_expected_withdrawals(spec, state)) == 0
|
||||
|
||||
|
||||
@with_capella_and_later
|
||||
@ -224,7 +226,7 @@ def test_partial_withdrawal_in_epoch_transition(spec, state):
|
||||
set_validator_partially_withdrawable(spec, state, index, excess_balance=1000000000000)
|
||||
pre_balance = state.balances[index]
|
||||
|
||||
assert len(spec.get_expected_withdrawals(state)) == 1
|
||||
assert len(get_expected_withdrawals(spec, state)) == 1
|
||||
|
||||
yield 'pre', state
|
||||
|
||||
@ -238,7 +240,7 @@ def test_partial_withdrawal_in_epoch_transition(spec, state):
|
||||
assert state.balances[index] < pre_balance
|
||||
# Potentially less than due to sync committee penalty
|
||||
assert state.balances[index] <= spec.MAX_EFFECTIVE_BALANCE
|
||||
assert len(spec.get_expected_withdrawals(state)) == 0
|
||||
assert len(get_expected_withdrawals(spec, state)) == 0
|
||||
|
||||
|
||||
@with_capella_and_later
|
||||
@ -250,7 +252,7 @@ def test_many_partial_withdrawals_in_epoch_transition(spec, state):
|
||||
index = (i + state.next_withdrawal_index) % len(state.validators)
|
||||
set_validator_partially_withdrawable(spec, state, index, excess_balance=1000000000000)
|
||||
|
||||
assert len(spec.get_expected_withdrawals(state)) == spec.MAX_WITHDRAWALS_PER_PAYLOAD
|
||||
assert (len(get_expected_withdrawals(spec, state)) == spec.MAX_WITHDRAWALS_PER_PAYLOAD)
|
||||
|
||||
yield 'pre', state
|
||||
|
||||
@ -261,7 +263,7 @@ def test_many_partial_withdrawals_in_epoch_transition(spec, state):
|
||||
yield 'blocks', [signed_block]
|
||||
yield 'post', state
|
||||
|
||||
assert len(spec.get_expected_withdrawals(state)) == 1
|
||||
assert len(get_expected_withdrawals(spec, state)) == 1
|
||||
|
||||
|
||||
def _perform_valid_withdrawal(spec, state):
|
||||
@ -272,7 +274,7 @@ def _perform_valid_withdrawal(spec, state):
|
||||
next_slot(spec, state)
|
||||
pre_next_withdrawal_index = state.next_withdrawal_index
|
||||
|
||||
expected_withdrawals = spec.get_expected_withdrawals(state)
|
||||
expected_withdrawals = get_expected_withdrawals(spec, state)
|
||||
|
||||
pre_state = state.copy()
|
||||
|
||||
@ -357,7 +359,11 @@ def test_top_up_and_partial_withdrawable_validator(spec, state):
|
||||
|
||||
signed_block = state_transition_and_sign_block(spec, state, block)
|
||||
|
||||
yield 'blocks', [signed_block]
|
||||
# ensure we go through an epoch transition, to account for post-EIP-7251 behavior
|
||||
block_in_next_epoch = build_empty_block(spec, state, slot=state.slot + spec.SLOTS_PER_EPOCH)
|
||||
signed_block_in_next_epoch = state_transition_and_sign_block(spec, state, block_in_next_epoch)
|
||||
|
||||
yield 'blocks', [signed_block, signed_block_in_next_epoch]
|
||||
yield 'post', state
|
||||
|
||||
# Since withdrawals happen before deposits, it becomes partially withdrawable after state transition.
|
||||
@ -395,9 +401,13 @@ def test_top_up_to_fully_withdrawn_validator(spec, state):
|
||||
|
||||
signed_block_1 = state_transition_and_sign_block(spec, state, block)
|
||||
|
||||
balance = state.balances[validator_index]
|
||||
if is_post_eip7251(spec):
|
||||
balance += state.pending_balance_deposits[0].amount
|
||||
|
||||
assert spec.is_fully_withdrawable_validator(
|
||||
state.validators[validator_index],
|
||||
state.balances[validator_index],
|
||||
balance,
|
||||
spec.get_current_epoch(state)
|
||||
)
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
from eth2spec.test.helpers.keys import pubkeys
|
||||
from eth2spec.test.helpers.forks import is_post_eip7251
|
||||
from eth2spec.test.helpers.constants import MINIMAL
|
||||
from eth2spec.test.context import (
|
||||
with_deneb_and_later,
|
||||
@ -47,7 +48,9 @@ def run_test_activation_churn_limit(spec, state):
|
||||
# Half should churn in first run of registry update
|
||||
for i in range(mock_activations):
|
||||
index = validator_count_0 + i
|
||||
if index < validator_count_0 + churn_limit_0:
|
||||
# NOTE: activations are gated different after EIP-7251
|
||||
# all eligible validators have been activated
|
||||
if index < validator_count_0 + churn_limit_0 or is_post_eip7251(spec):
|
||||
# The eligible validators within the activation churn limit should have been activated
|
||||
assert state.validators[index].activation_epoch < spec.FAR_FUTURE_EPOCH
|
||||
else:
|
||||
|
@ -4,7 +4,8 @@ from eth2spec.test.context import (
|
||||
with_eip7251_and_later,
|
||||
with_presets,
|
||||
always_bls,
|
||||
spec_test, single_phase,
|
||||
spec_test,
|
||||
single_phase,
|
||||
with_custom_state,
|
||||
scaled_churn_balances_exceed_activation_exit_churn_limit,
|
||||
default_activation_threshold,
|
||||
@ -27,15 +28,13 @@ from eth2spec.test.helpers.withdrawals import (
|
||||
@with_eip7251_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)
|
||||
balances_fn=scaled_churn_balances_exceed_activation_exit_churn_limit,
|
||||
threshold_fn=default_activation_threshold,
|
||||
)
|
||||
@spec_test
|
||||
@single_phase
|
||||
def test_basic_consolidation(spec, state):
|
||||
print(spec.config.PRESET_BASE)
|
||||
def test_basic_consolidation_in_current_consolidation_epoch(spec, state):
|
||||
# This state has 256 validators each with 32 ETH in MINIMAL preset, 128 ETH consolidation churn
|
||||
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
|
||||
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]
|
||||
@ -46,17 +45,30 @@ def test_basic_consolidation(spec, state):
|
||||
set_eth1_withdrawal_credential_with_balance(spec, state, source_index)
|
||||
set_eth1_withdrawal_credential_with_balance(spec, state, target_index)
|
||||
|
||||
signed_consolidation = sign_consolidation(spec, state,
|
||||
spec.Consolidation(
|
||||
epoch=current_epoch,
|
||||
source_index=source_index,
|
||||
target_index=target_index),
|
||||
source_privkey, target_privkey)
|
||||
signed_consolidation = sign_consolidation(
|
||||
spec,
|
||||
state,
|
||||
spec.Consolidation(
|
||||
epoch=current_epoch, source_index=source_index, target_index=target_index
|
||||
),
|
||||
source_privkey,
|
||||
target_privkey,
|
||||
)
|
||||
|
||||
# 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, signed_consolidation)
|
||||
|
||||
expected_exit_epoch = spec.compute_activation_exit_epoch(current_epoch)
|
||||
# Check consolidation churn is decremented correctly
|
||||
assert state.consolidation_balance_to_consume == consolidation_churn_limit - spec.MIN_ACTIVATION_BALANCE
|
||||
assert (
|
||||
state.consolidation_balance_to_consume
|
||||
== consolidation_churn_limit - spec.MIN_ACTIVATION_BALANCE
|
||||
)
|
||||
# Check exit epoch
|
||||
assert state.validators[0].exit_epoch == expected_exit_epoch
|
||||
|
||||
@ -64,7 +76,154 @@ def test_basic_consolidation(spec, state):
|
||||
@with_eip7251_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)
|
||||
balances_fn=scaled_churn_balances_exceed_activation_exit_churn_limit,
|
||||
threshold_fn=default_activation_threshold,
|
||||
)
|
||||
@spec_test
|
||||
@single_phase
|
||||
def test_basic_consolidation_in_new_consolidation_epoch(spec, state):
|
||||
# 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
|
||||
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_privkey = pubkey_to_privkey[state.validators[source_index].pubkey]
|
||||
target_privkey = pubkey_to_privkey[state.validators[target_index].pubkey]
|
||||
|
||||
# Set source and target withdrawal credentials to the same eth1 credential
|
||||
set_eth1_withdrawal_credential_with_balance(spec, state, source_index)
|
||||
set_eth1_withdrawal_credential_with_balance(spec, state, target_index)
|
||||
|
||||
signed_consolidation = sign_consolidation(
|
||||
spec,
|
||||
state,
|
||||
spec.Consolidation(
|
||||
epoch=current_epoch, source_index=source_index, target_index=target_index
|
||||
),
|
||||
source_privkey,
|
||||
target_privkey,
|
||||
)
|
||||
yield from run_consolidation_processing(spec, state, signed_consolidation)
|
||||
|
||||
expected_exit_epoch = spec.compute_activation_exit_epoch(current_epoch)
|
||||
# Check consolidation churn is decremented correctly
|
||||
# consolidation_balance_to_consume is replenished to the churn limit since we move to a new consolidation epoch
|
||||
consolidation_churn_limit = spec.get_consolidation_churn_limit(state)
|
||||
assert (
|
||||
state.consolidation_balance_to_consume
|
||||
== consolidation_churn_limit - spec.MIN_ACTIVATION_BALANCE
|
||||
)
|
||||
# Check exit epochs
|
||||
assert state.validators[0].exit_epoch == expected_exit_epoch
|
||||
|
||||
|
||||
@with_eip7251_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_with_preexisting_churn(spec, state):
|
||||
# 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]
|
||||
source_privkey = pubkey_to_privkey[state.validators[source_index].pubkey]
|
||||
target_privkey = pubkey_to_privkey[state.validators[target_index].pubkey]
|
||||
|
||||
# Set source and target withdrawal credentials to the same eth1 credential
|
||||
set_eth1_withdrawal_credential_with_balance(spec, state, source_index)
|
||||
set_eth1_withdrawal_credential_with_balance(spec, state, target_index)
|
||||
|
||||
signed_consolidation = sign_consolidation(
|
||||
spec,
|
||||
state,
|
||||
spec.Consolidation(
|
||||
epoch=current_epoch, source_index=source_index, target_index=target_index
|
||||
),
|
||||
source_privkey,
|
||||
target_privkey,
|
||||
)
|
||||
|
||||
# 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
|
||||
# Set some nonzero preexisting churn lower than churn limit and sufficient to process the consolidation
|
||||
preexisting_churn = 2 * spec.MIN_ACTIVATION_BALANCE
|
||||
state.consolidation_balance_to_consume = preexisting_churn
|
||||
|
||||
yield from run_consolidation_processing(spec, state, signed_consolidation)
|
||||
|
||||
# Check consolidation churn is decremented correctly
|
||||
assert (
|
||||
state.consolidation_balance_to_consume
|
||||
== preexisting_churn - spec.MIN_ACTIVATION_BALANCE
|
||||
)
|
||||
# Check exit epoch
|
||||
assert state.validators[0].exit_epoch == expected_exit_epoch
|
||||
|
||||
|
||||
@with_eip7251_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_with_insufficient_preexisting_churn(spec, state):
|
||||
# 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]
|
||||
source_privkey = pubkey_to_privkey[state.validators[source_index].pubkey]
|
||||
target_privkey = pubkey_to_privkey[state.validators[target_index].pubkey]
|
||||
|
||||
# Set source and target withdrawal credentials to the same eth1 credential
|
||||
set_eth1_withdrawal_credential_with_balance(spec, state, source_index)
|
||||
set_eth1_withdrawal_credential_with_balance(spec, state, target_index)
|
||||
|
||||
signed_consolidation = sign_consolidation(
|
||||
spec,
|
||||
state,
|
||||
spec.Consolidation(
|
||||
epoch=current_epoch, source_index=source_index, target_index=target_index
|
||||
),
|
||||
source_privkey,
|
||||
target_privkey,
|
||||
)
|
||||
|
||||
# Set earliest consolidation epoch to the first available epoch
|
||||
state.earliest_consolidation_epoch = spec.compute_activation_exit_epoch(
|
||||
current_epoch
|
||||
)
|
||||
# Set preexisting churn lower than required to process the consolidation
|
||||
preexisting_churn = spec.MIN_ACTIVATION_BALANCE - spec.EFFECTIVE_BALANCE_INCREMENT
|
||||
state.consolidation_balance_to_consume = preexisting_churn
|
||||
|
||||
yield from run_consolidation_processing(spec, state, signed_consolidation)
|
||||
|
||||
# It takes one more epoch to process the consolidation due to insufficient churn
|
||||
expected_exit_epoch = spec.compute_activation_exit_epoch(current_epoch) + 1
|
||||
# Check consolidation churn is decremented correctly
|
||||
consolidation_churn_limit = spec.get_consolidation_churn_limit(state)
|
||||
remainder = spec.MIN_ACTIVATION_BALANCE % preexisting_churn
|
||||
assert (
|
||||
state.consolidation_balance_to_consume == consolidation_churn_limit - remainder
|
||||
)
|
||||
# Check exit epoch
|
||||
assert state.validators[0].exit_epoch == expected_exit_epoch
|
||||
|
||||
|
||||
@with_eip7251_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_with_compounding_credential(spec, state):
|
||||
@ -82,17 +241,23 @@ def test_basic_consolidation_with_compounding_credential(spec, state):
|
||||
set_compounding_withdrawal_credential(spec, state, source_index)
|
||||
set_compounding_withdrawal_credential(spec, state, target_index)
|
||||
|
||||
signed_consolidation = sign_consolidation(spec, state,
|
||||
spec.Consolidation(
|
||||
epoch=current_epoch,
|
||||
source_index=source_index,
|
||||
target_index=target_index),
|
||||
source_privkey, target_privkey)
|
||||
signed_consolidation = sign_consolidation(
|
||||
spec,
|
||||
state,
|
||||
spec.Consolidation(
|
||||
epoch=current_epoch, source_index=source_index, target_index=target_index
|
||||
),
|
||||
source_privkey,
|
||||
target_privkey,
|
||||
)
|
||||
yield from run_consolidation_processing(spec, state, signed_consolidation)
|
||||
|
||||
expected_exit_epoch = spec.compute_activation_exit_epoch(current_epoch)
|
||||
# Check consolidation churn is decremented correctly
|
||||
assert state.consolidation_balance_to_consume == consolidation_churn_limit - spec.MIN_ACTIVATION_BALANCE
|
||||
assert (
|
||||
state.consolidation_balance_to_consume
|
||||
== consolidation_churn_limit - spec.MIN_ACTIVATION_BALANCE
|
||||
)
|
||||
# Check exit epoch
|
||||
assert state.validators[0].exit_epoch == expected_exit_epoch
|
||||
|
||||
@ -100,19 +265,21 @@ def test_basic_consolidation_with_compounding_credential(spec, state):
|
||||
@with_eip7251_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)
|
||||
balances_fn=scaled_churn_balances_exceed_activation_exit_churn_limit,
|
||||
threshold_fn=default_activation_threshold,
|
||||
)
|
||||
@spec_test
|
||||
@single_phase
|
||||
def test_consolidation_churn_limit_balance(spec, state):
|
||||
# This state has 256 validators each with 32 ETH in MINIMAL preset, 128 ETH consolidation churn
|
||||
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
|
||||
current_epoch = spec.get_current_epoch(state)
|
||||
|
||||
source_index = spec.get_active_validator_indices(state, current_epoch)[0]
|
||||
# Set source balance to consolidation churn limit
|
||||
state.balances[source_index] = consolidation_churn_limit
|
||||
source_validator = state.validators[source_index]
|
||||
source_validator.effective_balance = consolidation_churn_limit
|
||||
# Churn limit increases due to higher total balance
|
||||
updated_consolidation_churn_limit = spec.get_consolidation_churn_limit(state)
|
||||
target_index = spec.get_active_validator_indices(state, current_epoch)[1]
|
||||
source_privkey = pubkey_to_privkey[state.validators[source_index].pubkey]
|
||||
target_privkey = pubkey_to_privkey[state.validators[target_index].pubkey]
|
||||
@ -121,17 +288,24 @@ def test_consolidation_churn_limit_balance(spec, state):
|
||||
set_compounding_withdrawal_credential(spec, state, source_index)
|
||||
set_compounding_withdrawal_credential(spec, state, target_index)
|
||||
|
||||
signed_consolidation = sign_consolidation(spec, state,
|
||||
spec.Consolidation(
|
||||
epoch=current_epoch,
|
||||
source_index=source_index,
|
||||
target_index=target_index),
|
||||
source_privkey, target_privkey)
|
||||
signed_consolidation = sign_consolidation(
|
||||
spec,
|
||||
state,
|
||||
spec.Consolidation(
|
||||
epoch=current_epoch, source_index=source_index, target_index=target_index
|
||||
),
|
||||
source_privkey,
|
||||
target_privkey,
|
||||
)
|
||||
yield from run_consolidation_processing(spec, state, signed_consolidation)
|
||||
|
||||
# validator's effective balance fits into the churn, exit as soon as possible
|
||||
expected_exit_epoch = spec.compute_activation_exit_epoch(current_epoch)
|
||||
# Check consolidation churn is decremented correctly
|
||||
assert state.consolidation_balance_to_consume == 0
|
||||
assert (
|
||||
state.consolidation_balance_to_consume
|
||||
== updated_consolidation_churn_limit - consolidation_churn_limit
|
||||
)
|
||||
# Check exit epoch
|
||||
assert state.validators[0].exit_epoch == expected_exit_epoch
|
||||
|
||||
@ -139,19 +313,19 @@ def test_consolidation_churn_limit_balance(spec, state):
|
||||
@with_eip7251_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)
|
||||
balances_fn=scaled_churn_balances_exceed_activation_exit_churn_limit,
|
||||
threshold_fn=default_activation_threshold,
|
||||
)
|
||||
@spec_test
|
||||
@single_phase
|
||||
def test_consolidation_balance_larger_than_churn_limit(spec, state):
|
||||
# This state has 256 validators each with 32 ETH in MINIMAL preset, 128 ETH consolidation churn
|
||||
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
|
||||
current_epoch = spec.get_current_epoch(state)
|
||||
|
||||
source_index = spec.get_active_validator_indices(state, current_epoch)[0]
|
||||
# Set source balance higher than consolidation churn limit
|
||||
state.balances[source_index] = consolidation_churn_limit + 1
|
||||
state.validators[source_index].effective_balance = 2 * consolidation_churn_limit
|
||||
target_index = spec.get_active_validator_indices(state, current_epoch)[1]
|
||||
source_privkey = pubkey_to_privkey[state.validators[source_index].pubkey]
|
||||
target_privkey = pubkey_to_privkey[state.validators[target_index].pubkey]
|
||||
@ -160,17 +334,25 @@ def test_consolidation_balance_larger_than_churn_limit(spec, state):
|
||||
set_compounding_withdrawal_credential(spec, state, source_index)
|
||||
set_compounding_withdrawal_credential(spec, state, target_index)
|
||||
|
||||
signed_consolidation = sign_consolidation(spec, state,
|
||||
spec.Consolidation(
|
||||
epoch=current_epoch,
|
||||
source_index=source_index,
|
||||
target_index=target_index),
|
||||
source_privkey, target_privkey)
|
||||
# Consolidation churn limit increases due to higher total balance
|
||||
new_churn_limit = spec.get_consolidation_churn_limit(state)
|
||||
remainder = state.validators[source_index].effective_balance % new_churn_limit
|
||||
expected_balance = new_churn_limit - remainder
|
||||
|
||||
signed_consolidation = sign_consolidation(
|
||||
spec,
|
||||
state,
|
||||
spec.Consolidation(
|
||||
epoch=current_epoch, source_index=source_index, target_index=target_index
|
||||
),
|
||||
source_privkey,
|
||||
target_privkey,
|
||||
)
|
||||
yield from run_consolidation_processing(spec, state, signed_consolidation)
|
||||
|
||||
expected_exit_epoch = spec.compute_activation_exit_epoch(current_epoch) + 1
|
||||
# Check consolidation churn is decremented correctly
|
||||
assert state.consolidation_balance_to_consume == consolidation_churn_limit - 1
|
||||
assert state.consolidation_balance_to_consume == expected_balance
|
||||
# Check exit epoch
|
||||
assert state.validators[0].exit_epoch == expected_exit_epoch
|
||||
|
||||
@ -178,14 +360,14 @@ def test_consolidation_balance_larger_than_churn_limit(spec, state):
|
||||
@with_eip7251_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)
|
||||
balances_fn=scaled_churn_balances_exceed_activation_exit_churn_limit,
|
||||
threshold_fn=default_activation_threshold,
|
||||
)
|
||||
@spec_test
|
||||
@single_phase
|
||||
def test_consolidation_balance_twice_the_churn_limit(spec, state):
|
||||
def test_consolidation_balance_through_two_churn_epochs(spec, state):
|
||||
# This state has 256 validators each with 32 ETH in MINIMAL preset, 128 ETH consolidation churn
|
||||
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
|
||||
current_epoch = spec.get_current_epoch(state)
|
||||
|
||||
source_index = spec.get_active_validator_indices(state, current_epoch)[0]
|
||||
@ -198,27 +380,36 @@ def test_consolidation_balance_twice_the_churn_limit(spec, state):
|
||||
set_compounding_withdrawal_credential(spec, state, target_index)
|
||||
|
||||
# Set source balance higher than consolidation churn limit
|
||||
state.balances[source_index] = 2 * consolidation_churn_limit
|
||||
state.validators[source_index].effective_balance = 3 * consolidation_churn_limit
|
||||
|
||||
signed_consolidation = sign_consolidation(spec, state,
|
||||
spec.Consolidation(
|
||||
epoch=current_epoch,
|
||||
source_index=source_index,
|
||||
target_index=target_index),
|
||||
source_privkey, target_privkey)
|
||||
new_churn_limit = spec.get_consolidation_churn_limit(state)
|
||||
remainder = state.validators[source_index].effective_balance % new_churn_limit
|
||||
expected_balance = new_churn_limit - remainder
|
||||
|
||||
signed_consolidation = sign_consolidation(
|
||||
spec,
|
||||
state,
|
||||
spec.Consolidation(
|
||||
epoch=current_epoch, source_index=source_index, target_index=target_index
|
||||
),
|
||||
source_privkey,
|
||||
target_privkey,
|
||||
)
|
||||
yield from run_consolidation_processing(spec, state, signed_consolidation)
|
||||
|
||||
# when exiting a multiple of the churn limit greater than 1, an extra exit epoch is added
|
||||
expected_exit_epoch = spec.compute_activation_exit_epoch(current_epoch) + 2
|
||||
assert state.validators[0].exit_epoch == expected_exit_epoch
|
||||
# since the earliest exit epoch moves to a new one, consolidation balance is back to full
|
||||
assert state.consolidation_balance_to_consume == consolidation_churn_limit
|
||||
assert state.consolidation_balance_to_consume == expected_balance
|
||||
|
||||
|
||||
@with_eip7251_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)
|
||||
balances_fn=scaled_churn_balances_exceed_activation_exit_churn_limit,
|
||||
threshold_fn=default_activation_threshold,
|
||||
)
|
||||
@spec_test
|
||||
@single_phase
|
||||
def test_multiple_consolidations_below_churn(spec, state):
|
||||
@ -239,12 +430,17 @@ def test_multiple_consolidations_below_churn(spec, state):
|
||||
# Set source and target withdrawal credentials to the same eth1 credential
|
||||
set_eth1_withdrawal_credential_with_balance(spec, state, source_index)
|
||||
set_eth1_withdrawal_credential_with_balance(spec, state, target_index)
|
||||
signed_consolidation = sign_consolidation(spec, state,
|
||||
spec.Consolidation(
|
||||
epoch=current_epoch,
|
||||
source_index=source_index,
|
||||
target_index=target_index),
|
||||
source_privkey, target_privkey)
|
||||
signed_consolidation = sign_consolidation(
|
||||
spec,
|
||||
state,
|
||||
spec.Consolidation(
|
||||
epoch=current_epoch,
|
||||
source_index=source_index,
|
||||
target_index=target_index,
|
||||
),
|
||||
source_privkey,
|
||||
target_privkey,
|
||||
)
|
||||
consolidations.append(signed_consolidation)
|
||||
|
||||
# Now run all the consolidations
|
||||
@ -257,7 +453,10 @@ def test_multiple_consolidations_below_churn(spec, state):
|
||||
|
||||
expected_exit_epoch = spec.compute_activation_exit_epoch(current_epoch)
|
||||
assert state.earliest_consolidation_epoch == expected_exit_epoch
|
||||
assert state.consolidation_balance_to_consume == consolidation_churn_limit - 3 * spec.MIN_ACTIVATION_BALANCE
|
||||
assert (
|
||||
state.consolidation_balance_to_consume
|
||||
== consolidation_churn_limit - 3 * spec.MIN_ACTIVATION_BALANCE
|
||||
)
|
||||
for i in range(3):
|
||||
assert state.validators[2 * i].exit_epoch == expected_exit_epoch
|
||||
|
||||
@ -265,7 +464,9 @@ def test_multiple_consolidations_below_churn(spec, state):
|
||||
@with_eip7251_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)
|
||||
balances_fn=scaled_churn_balances_exceed_activation_exit_churn_limit,
|
||||
threshold_fn=default_activation_threshold,
|
||||
)
|
||||
@spec_test
|
||||
@single_phase
|
||||
def test_multiple_consolidations_equal_churn(spec, state):
|
||||
@ -286,12 +487,17 @@ def test_multiple_consolidations_equal_churn(spec, state):
|
||||
# Set source and target withdrawal credentials to the same eth1 credential
|
||||
set_eth1_withdrawal_credential_with_balance(spec, state, source_index)
|
||||
set_eth1_withdrawal_credential_with_balance(spec, state, target_index)
|
||||
signed_consolidation = sign_consolidation(spec, state,
|
||||
spec.Consolidation(
|
||||
epoch=current_epoch,
|
||||
source_index=source_index,
|
||||
target_index=target_index),
|
||||
source_privkey, target_privkey)
|
||||
signed_consolidation = sign_consolidation(
|
||||
spec,
|
||||
state,
|
||||
spec.Consolidation(
|
||||
epoch=current_epoch,
|
||||
source_index=source_index,
|
||||
target_index=target_index,
|
||||
),
|
||||
source_privkey,
|
||||
target_privkey,
|
||||
)
|
||||
consolidations.append(signed_consolidation)
|
||||
|
||||
# Now run all the consolidations
|
||||
@ -312,7 +518,9 @@ def test_multiple_consolidations_equal_churn(spec, state):
|
||||
@with_eip7251_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)
|
||||
balances_fn=scaled_churn_balances_exceed_activation_exit_churn_limit,
|
||||
threshold_fn=default_activation_threshold,
|
||||
)
|
||||
@spec_test
|
||||
@single_phase
|
||||
def test_multiple_consolidations_above_churn(spec, state):
|
||||
@ -332,12 +540,17 @@ def test_multiple_consolidations_above_churn(spec, state):
|
||||
# Set source and target withdrawal credentials to the same eth1 credential
|
||||
set_eth1_withdrawal_credential_with_balance(spec, state, source_index)
|
||||
set_eth1_withdrawal_credential_with_balance(spec, state, target_index)
|
||||
signed_consolidation = sign_consolidation(spec, state,
|
||||
spec.Consolidation(
|
||||
epoch=current_epoch,
|
||||
source_index=source_index,
|
||||
target_index=target_index),
|
||||
source_privkey, target_privkey)
|
||||
signed_consolidation = sign_consolidation(
|
||||
spec,
|
||||
state,
|
||||
spec.Consolidation(
|
||||
epoch=current_epoch,
|
||||
source_index=source_index,
|
||||
target_index=target_index,
|
||||
),
|
||||
source_privkey,
|
||||
target_privkey,
|
||||
)
|
||||
consolidations.append(signed_consolidation)
|
||||
|
||||
# Now run all the consolidations
|
||||
@ -356,19 +569,25 @@ def test_multiple_consolidations_above_churn(spec, state):
|
||||
set_eth1_withdrawal_credential_with_balance(spec, state, source_index)
|
||||
set_eth1_withdrawal_credential_with_balance(spec, state, target_index)
|
||||
|
||||
signed_consolidation = sign_consolidation(spec, state,
|
||||
spec.Consolidation(
|
||||
epoch=current_epoch,
|
||||
source_index=source_index,
|
||||
target_index=target_index),
|
||||
source_privkey, target_privkey)
|
||||
signed_consolidation = sign_consolidation(
|
||||
spec,
|
||||
state,
|
||||
spec.Consolidation(
|
||||
epoch=current_epoch, source_index=source_index, target_index=target_index
|
||||
),
|
||||
source_privkey,
|
||||
target_privkey,
|
||||
)
|
||||
# This is the interesting part of the test: on a pre-state with full consolidation queue,
|
||||
# when processing an additional consolidation, it results in an exit in a later epoch
|
||||
yield from run_consolidation_processing(spec, state, signed_consolidation)
|
||||
|
||||
expected_exit_epoch = spec.compute_activation_exit_epoch(current_epoch)
|
||||
assert state.earliest_consolidation_epoch == expected_exit_epoch + 1
|
||||
assert state.consolidation_balance_to_consume == consolidation_churn_limit - spec.MIN_ACTIVATION_BALANCE
|
||||
assert (
|
||||
state.consolidation_balance_to_consume
|
||||
== consolidation_churn_limit - spec.MIN_ACTIVATION_BALANCE
|
||||
)
|
||||
assert state.validators[source_index].exit_epoch == expected_exit_epoch + 1
|
||||
for i in range(4):
|
||||
assert state.validators[2 * i].exit_epoch == expected_exit_epoch
|
||||
@ -377,7 +596,9 @@ def test_multiple_consolidations_above_churn(spec, state):
|
||||
@with_eip7251_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)
|
||||
balances_fn=scaled_churn_balances_exceed_activation_exit_churn_limit,
|
||||
threshold_fn=default_activation_threshold,
|
||||
)
|
||||
@spec_test
|
||||
@single_phase
|
||||
def test_multiple_consolidations_equal_twice_churn(spec, state):
|
||||
@ -398,12 +619,17 @@ def test_multiple_consolidations_equal_twice_churn(spec, state):
|
||||
# Set source and target withdrawal credentials to the same eth1 credential
|
||||
set_eth1_withdrawal_credential_with_balance(spec, state, source_index)
|
||||
set_eth1_withdrawal_credential_with_balance(spec, state, target_index)
|
||||
signed_consolidation = sign_consolidation(spec, state,
|
||||
spec.Consolidation(
|
||||
epoch=current_epoch,
|
||||
source_index=source_index,
|
||||
target_index=target_index),
|
||||
source_privkey, target_privkey)
|
||||
signed_consolidation = sign_consolidation(
|
||||
spec,
|
||||
state,
|
||||
spec.Consolidation(
|
||||
epoch=current_epoch,
|
||||
source_index=source_index,
|
||||
target_index=target_index,
|
||||
),
|
||||
source_privkey,
|
||||
target_privkey,
|
||||
)
|
||||
consolidations.append(signed_consolidation)
|
||||
|
||||
# Now run all the consolidations
|
||||
@ -425,6 +651,7 @@ def test_multiple_consolidations_equal_twice_churn(spec, state):
|
||||
|
||||
# Failing tests
|
||||
|
||||
|
||||
@with_eip7251_and_later
|
||||
@spec_state_test
|
||||
def test_invalid_source_equals_target(spec, state):
|
||||
@ -435,31 +662,69 @@ def test_invalid_source_equals_target(spec, state):
|
||||
# Set withdrawal credentials to eth1
|
||||
set_eth1_withdrawal_credential_with_balance(spec, state, validator_index)
|
||||
|
||||
signed_consolidation = sign_consolidation(spec, state,
|
||||
spec.Consolidation(
|
||||
epoch=current_epoch,
|
||||
source_index=validator_index,
|
||||
target_index=validator_index),
|
||||
validator_privkey, validator_privkey)
|
||||
yield from run_consolidation_processing(spec, state, signed_consolidation, valid=False)
|
||||
signed_consolidation = sign_consolidation(
|
||||
spec,
|
||||
state,
|
||||
spec.Consolidation(
|
||||
epoch=current_epoch,
|
||||
source_index=validator_index,
|
||||
target_index=validator_index,
|
||||
),
|
||||
validator_privkey,
|
||||
validator_privkey,
|
||||
)
|
||||
yield from run_consolidation_processing(
|
||||
spec, state, signed_consolidation, valid=False
|
||||
)
|
||||
|
||||
|
||||
@with_eip7251_and_later
|
||||
@spec_state_test
|
||||
def test_invalid_exceed_pending_consolidations_limit(spec, state):
|
||||
state.pending_consolidations = (
|
||||
[spec.PendingConsolidation(source_index=0, target_index=1)] * spec.PENDING_CONSOLIDATIONS_LIMIT
|
||||
)
|
||||
state.pending_consolidations = [
|
||||
spec.PendingConsolidation(source_index=0, target_index=1)
|
||||
] * spec.PENDING_CONSOLIDATIONS_LIMIT
|
||||
current_epoch = spec.get_current_epoch(state)
|
||||
source_privkey = pubkey_to_privkey[state.validators[0].pubkey]
|
||||
target_privkey = pubkey_to_privkey[state.validators[1].pubkey]
|
||||
# Set source and target withdrawal credentials to the same eth1 credential
|
||||
set_eth1_withdrawal_credential_with_balance(spec, state, 0)
|
||||
set_eth1_withdrawal_credential_with_balance(spec, state, 1)
|
||||
signed_consolidation = sign_consolidation(spec, state,
|
||||
spec.Consolidation(epoch=current_epoch, source_index=0, target_index=1),
|
||||
source_privkey, target_privkey)
|
||||
yield from run_consolidation_processing(spec, state, signed_consolidation, valid=False)
|
||||
signed_consolidation = sign_consolidation(
|
||||
spec,
|
||||
state,
|
||||
spec.Consolidation(epoch=current_epoch, source_index=0, target_index=1),
|
||||
source_privkey,
|
||||
target_privkey,
|
||||
)
|
||||
yield from run_consolidation_processing(
|
||||
spec, state, signed_consolidation, valid=False
|
||||
)
|
||||
|
||||
|
||||
@with_eip7251_and_later
|
||||
@spec_state_test
|
||||
def test_invalid_not_enough_consolidation_churn_available(spec, state):
|
||||
state.validators = state.validators[0:2]
|
||||
state.pending_consolidations = [
|
||||
spec.PendingConsolidation(source_index=0, target_index=1)
|
||||
]
|
||||
current_epoch = spec.get_current_epoch(state)
|
||||
source_privkey = pubkey_to_privkey[state.validators[0].pubkey]
|
||||
target_privkey = pubkey_to_privkey[state.validators[1].pubkey]
|
||||
# Set source and target withdrawal credentials to the same eth1 credential
|
||||
set_eth1_withdrawal_credential_with_balance(spec, state, 0)
|
||||
set_eth1_withdrawal_credential_with_balance(spec, state, 1)
|
||||
signed_consolidation = sign_consolidation(
|
||||
spec,
|
||||
state,
|
||||
spec.Consolidation(epoch=current_epoch, source_index=0, target_index=1),
|
||||
source_privkey,
|
||||
target_privkey,
|
||||
)
|
||||
yield from run_consolidation_processing(
|
||||
spec, state, signed_consolidation, valid=False
|
||||
)
|
||||
|
||||
|
||||
@with_eip7251_and_later
|
||||
@ -470,12 +735,18 @@ def test_invalid_exited_source(spec, state):
|
||||
target_privkey = pubkey_to_privkey[state.validators[1].pubkey]
|
||||
set_eth1_withdrawal_credential_with_balance(spec, state, 0)
|
||||
set_eth1_withdrawal_credential_with_balance(spec, state, 1)
|
||||
signed_consolidation = sign_consolidation(spec, state,
|
||||
spec.Consolidation(epoch=current_epoch, source_index=0, target_index=1),
|
||||
source_privkey, target_privkey)
|
||||
signed_consolidation = sign_consolidation(
|
||||
spec,
|
||||
state,
|
||||
spec.Consolidation(epoch=current_epoch, source_index=0, target_index=1),
|
||||
source_privkey,
|
||||
target_privkey,
|
||||
)
|
||||
# exit source
|
||||
spec.initiate_validator_exit(state, 0)
|
||||
yield from run_consolidation_processing(spec, state, signed_consolidation, valid=False)
|
||||
yield from run_consolidation_processing(
|
||||
spec, state, signed_consolidation, valid=False
|
||||
)
|
||||
|
||||
|
||||
@with_eip7251_and_later
|
||||
@ -487,15 +758,18 @@ def test_invalid_exited_target(spec, state):
|
||||
# Set source and target withdrawal credentials to the same eth1 credential
|
||||
set_eth1_withdrawal_credential_with_balance(spec, state, 0)
|
||||
set_eth1_withdrawal_credential_with_balance(spec, state, 1)
|
||||
signed_consolidation = sign_consolidation(spec, state,
|
||||
spec.Consolidation(
|
||||
epoch=current_epoch,
|
||||
source_index=0,
|
||||
target_index=1),
|
||||
source_privkey, target_privkey)
|
||||
signed_consolidation = sign_consolidation(
|
||||
spec,
|
||||
state,
|
||||
spec.Consolidation(epoch=current_epoch, source_index=0, target_index=1),
|
||||
source_privkey,
|
||||
target_privkey,
|
||||
)
|
||||
# exit target
|
||||
spec.initiate_validator_exit(state, 1)
|
||||
yield from run_consolidation_processing(spec, state, signed_consolidation, valid=False)
|
||||
yield from run_consolidation_processing(
|
||||
spec, state, signed_consolidation, valid=False
|
||||
)
|
||||
|
||||
|
||||
@with_eip7251_and_later
|
||||
@ -506,15 +780,18 @@ def test_invalid_inactive_source(spec, state):
|
||||
target_privkey = pubkey_to_privkey[state.validators[1].pubkey]
|
||||
set_eth1_withdrawal_credential_with_balance(spec, state, 0)
|
||||
set_eth1_withdrawal_credential_with_balance(spec, state, 1)
|
||||
signed_consolidation = sign_consolidation(spec, state,
|
||||
spec.Consolidation(
|
||||
epoch=current_epoch,
|
||||
source_index=0,
|
||||
target_index=1),
|
||||
source_privkey, target_privkey)
|
||||
signed_consolidation = sign_consolidation(
|
||||
spec,
|
||||
state,
|
||||
spec.Consolidation(epoch=current_epoch, source_index=0, target_index=1),
|
||||
source_privkey,
|
||||
target_privkey,
|
||||
)
|
||||
# set source validator as not yet activated
|
||||
state.validators[0].activation_epoch = spec.FAR_FUTURE_EPOCH
|
||||
yield from run_consolidation_processing(spec, state, signed_consolidation, valid=False)
|
||||
yield from run_consolidation_processing(
|
||||
spec, state, signed_consolidation, valid=False
|
||||
)
|
||||
|
||||
|
||||
@with_eip7251_and_later
|
||||
@ -526,15 +803,18 @@ def test_invalid_inactive_target(spec, state):
|
||||
# Set source and target withdrawal credentials to the same eth1 credential
|
||||
set_eth1_withdrawal_credential_with_balance(spec, state, 0)
|
||||
set_eth1_withdrawal_credential_with_balance(spec, state, 1)
|
||||
signed_consolidation = sign_consolidation(spec, state,
|
||||
spec.Consolidation(
|
||||
epoch=current_epoch,
|
||||
source_index=0,
|
||||
target_index=1),
|
||||
source_privkey, target_privkey)
|
||||
signed_consolidation = sign_consolidation(
|
||||
spec,
|
||||
state,
|
||||
spec.Consolidation(epoch=current_epoch, source_index=0, target_index=1),
|
||||
source_privkey,
|
||||
target_privkey,
|
||||
)
|
||||
# set target validator as not yet activated
|
||||
state.validators[1].activation_epoch = spec.FAR_FUTURE_EPOCH
|
||||
yield from run_consolidation_processing(spec, state, signed_consolidation, valid=False)
|
||||
yield from run_consolidation_processing(
|
||||
spec, state, signed_consolidation, valid=False
|
||||
)
|
||||
|
||||
|
||||
@with_eip7251_and_later
|
||||
@ -543,13 +823,16 @@ def test_invalid_no_execution_withdrawal_credential(spec, state):
|
||||
current_epoch = spec.get_current_epoch(state)
|
||||
source_privkey = pubkey_to_privkey[state.validators[0].pubkey]
|
||||
target_privkey = pubkey_to_privkey[state.validators[1].pubkey]
|
||||
signed_consolidation = sign_consolidation(spec, state,
|
||||
spec.Consolidation(
|
||||
epoch=current_epoch,
|
||||
source_index=0,
|
||||
target_index=1),
|
||||
source_privkey, target_privkey)
|
||||
yield from run_consolidation_processing(spec, state, signed_consolidation, valid=False)
|
||||
signed_consolidation = sign_consolidation(
|
||||
spec,
|
||||
state,
|
||||
spec.Consolidation(epoch=current_epoch, source_index=0, target_index=1),
|
||||
source_privkey,
|
||||
target_privkey,
|
||||
)
|
||||
yield from run_consolidation_processing(
|
||||
spec, state, signed_consolidation, valid=False
|
||||
)
|
||||
|
||||
|
||||
@with_eip7251_and_later
|
||||
@ -558,16 +841,19 @@ def test_invalid_different_credentials(spec, state):
|
||||
current_epoch = spec.get_current_epoch(state)
|
||||
source_privkey = pubkey_to_privkey[state.validators[0].pubkey]
|
||||
target_privkey = pubkey_to_privkey[state.validators[1].pubkey]
|
||||
signed_consolidation = sign_consolidation(spec, state,
|
||||
spec.Consolidation(
|
||||
epoch=current_epoch,
|
||||
source_index=0,
|
||||
target_index=1),
|
||||
source_privkey, target_privkey)
|
||||
signed_consolidation = sign_consolidation(
|
||||
spec,
|
||||
state,
|
||||
spec.Consolidation(epoch=current_epoch, source_index=0, target_index=1),
|
||||
source_privkey,
|
||||
target_privkey,
|
||||
)
|
||||
# Set source and target withdrawal credentials to different eth1 credentials
|
||||
set_eth1_withdrawal_credential_with_balance(spec, state, 0)
|
||||
set_eth1_withdrawal_credential_with_balance(spec, state, 1, address=b'\x10' * 20)
|
||||
yield from run_consolidation_processing(spec, state, signed_consolidation, valid=False)
|
||||
set_eth1_withdrawal_credential_with_balance(spec, state, 1, address=b"\x10" * 20)
|
||||
yield from run_consolidation_processing(
|
||||
spec, state, signed_consolidation, valid=False
|
||||
)
|
||||
|
||||
|
||||
@with_eip7251_and_later
|
||||
@ -580,15 +866,18 @@ def test_invalid_source_signature(spec, state):
|
||||
# Set source and target withdrawal credentials to the same eth1 credential
|
||||
set_eth1_withdrawal_credential_with_balance(spec, state, 0)
|
||||
set_eth1_withdrawal_credential_with_balance(spec, state, 1)
|
||||
signed_consolidation = sign_consolidation(spec, state,
|
||||
spec.Consolidation(
|
||||
epoch=current_epoch,
|
||||
source_index=0,
|
||||
target_index=1),
|
||||
source_privkey, target_privkey)
|
||||
signed_consolidation = sign_consolidation(
|
||||
spec,
|
||||
state,
|
||||
spec.Consolidation(epoch=current_epoch, source_index=0, target_index=1),
|
||||
source_privkey,
|
||||
target_privkey,
|
||||
)
|
||||
# Change the pubkey of the source validator, invalidating its signature
|
||||
state.validators[0].pubkey = state.validators[1].pubkey
|
||||
yield from run_consolidation_processing(spec, state, signed_consolidation, valid=False)
|
||||
yield from run_consolidation_processing(
|
||||
spec, state, signed_consolidation, valid=False
|
||||
)
|
||||
|
||||
|
||||
@with_eip7251_and_later
|
||||
@ -601,15 +890,18 @@ def test_invalid_target_signature(spec, state):
|
||||
# Set source and target withdrawal credentials to the same eth1 credential
|
||||
set_eth1_withdrawal_credential_with_balance(spec, state, 0)
|
||||
set_eth1_withdrawal_credential_with_balance(spec, state, 1)
|
||||
signed_consolidation = sign_consolidation(spec, state,
|
||||
spec.Consolidation(
|
||||
epoch=current_epoch,
|
||||
source_index=0,
|
||||
target_index=1),
|
||||
source_privkey, target_privkey)
|
||||
signed_consolidation = sign_consolidation(
|
||||
spec,
|
||||
state,
|
||||
spec.Consolidation(epoch=current_epoch, source_index=0, target_index=1),
|
||||
source_privkey,
|
||||
target_privkey,
|
||||
)
|
||||
# Change the pubkey of the target validator, invalidating its signature
|
||||
state.validators[1].pubkey = state.validators[2].pubkey
|
||||
yield from run_consolidation_processing(spec, state, signed_consolidation, valid=False)
|
||||
yield from run_consolidation_processing(
|
||||
spec, state, signed_consolidation, valid=False
|
||||
)
|
||||
|
||||
|
||||
@with_eip7251_and_later
|
||||
@ -622,10 +914,13 @@ def test_invalid_before_specified_epoch(spec, state):
|
||||
set_eth1_withdrawal_credential_with_balance(spec, state, 0)
|
||||
set_eth1_withdrawal_credential_with_balance(spec, state, 1)
|
||||
# set epoch=current_epoch + 1, so it's too early to process it
|
||||
signed_consolidation = sign_consolidation(spec, state,
|
||||
spec.Consolidation(
|
||||
epoch=current_epoch + 1,
|
||||
source_index=0,
|
||||
target_index=1),
|
||||
source_privkey, target_privkey)
|
||||
yield from run_consolidation_processing(spec, state, signed_consolidation, valid=False)
|
||||
signed_consolidation = sign_consolidation(
|
||||
spec,
|
||||
state,
|
||||
spec.Consolidation(epoch=current_epoch + 1, source_index=0, target_index=1),
|
||||
source_privkey,
|
||||
target_privkey,
|
||||
)
|
||||
yield from run_consolidation_processing(
|
||||
spec, state, signed_consolidation, valid=False
|
||||
)
|
||||
|
@ -1,284 +0,0 @@
|
||||
from eth2spec.test.helpers.deposits import (
|
||||
build_deposit,
|
||||
prepare_state_and_deposit,
|
||||
run_deposit_processing_eip7251,
|
||||
run_deposit_processing_eip7251_with_specific_fork_version,
|
||||
sign_deposit_data,
|
||||
)
|
||||
from eth2spec.test.helpers.keys import privkeys, pubkeys
|
||||
|
||||
from eth2spec.test.context import (
|
||||
spec_state_test,
|
||||
with_eip7251_and_later,
|
||||
always_bls,
|
||||
)
|
||||
|
||||
|
||||
@with_eip7251_and_later
|
||||
@spec_state_test
|
||||
def test_new_deposit_under_min_activation_balance(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.
|
||||
amount = spec.MIN_ACTIVATION_BALANCE - 1
|
||||
deposit = prepare_state_and_deposit(spec, state, validator_index, amount, signed=True)
|
||||
|
||||
yield from run_deposit_processing_eip7251(spec, state, deposit, validator_index)
|
||||
|
||||
|
||||
@with_eip7251_and_later
|
||||
@spec_state_test
|
||||
def test_new_deposit_min(spec, state):
|
||||
# fresh deposit = next validator index = validator appended to registry
|
||||
validator_index = len(state.validators)
|
||||
amount = spec.MIN_DEPOSIT_AMOUNT
|
||||
deposit = prepare_state_and_deposit(spec, state, validator_index, amount, signed=True)
|
||||
yield from run_deposit_processing_eip7251(spec, state, deposit, validator_index)
|
||||
|
||||
|
||||
@with_eip7251_and_later
|
||||
@spec_state_test
|
||||
def test_new_deposit_between_min_and_max(spec, state):
|
||||
# fresh deposit = next validator index = validator appended to registry
|
||||
validator_index = len(state.validators)
|
||||
amount = spec.MAX_EFFECTIVE_BALANCE_EIP7251 // 2
|
||||
deposit = prepare_state_and_deposit(spec, state, validator_index, amount, signed=True)
|
||||
yield from run_deposit_processing_eip7251(spec, state, deposit, validator_index)
|
||||
|
||||
|
||||
@with_eip7251_and_later
|
||||
@spec_state_test
|
||||
def test_new_deposit_max(spec, state):
|
||||
# fresh deposit = next validator index = validator appended to registry
|
||||
validator_index = len(state.validators)
|
||||
# effective balance will be exactly the same as balance.
|
||||
amount = spec.MAX_EFFECTIVE_BALANCE_EIP7251
|
||||
deposit = prepare_state_and_deposit(spec, state, validator_index, amount, signed=True)
|
||||
yield from run_deposit_processing_eip7251(spec, state, deposit, validator_index)
|
||||
|
||||
|
||||
@with_eip7251_and_later
|
||||
@spec_state_test
|
||||
def test_new_deposit_over_max(spec, state):
|
||||
# fresh deposit = next validator index = validator appended to registry
|
||||
validator_index = len(state.validators)
|
||||
amount = spec.MAX_EFFECTIVE_BALANCE_EIP7251 + 1
|
||||
deposit = prepare_state_and_deposit(spec, state, validator_index, amount, signed=True)
|
||||
yield from run_deposit_processing_eip7251(spec, state, deposit, validator_index)
|
||||
|
||||
|
||||
# @with_eip7251_and_later
|
||||
# @spec_state_test
|
||||
# def test_top_up__max_effective_balance(spec, state):
|
||||
# validator_index = 0
|
||||
# amount = spec.MAX_EFFECTIVE_BALANCE_EIP7251 // 4
|
||||
# deposit = prepare_state_and_deposit(spec, state, validator_index, amount, signed=True)
|
||||
|
||||
# state.balances[validator_index] = spec.MAX_EFFECTIVE_BALANCE_EIP7251
|
||||
# state.validators[validator_index].effective_balance = spec.MAX_EFFECTIVE_BALANCE_EIP7251
|
||||
|
||||
# yield from run_deposit_processing_eip7251(spec, state, deposit, validator_index)
|
||||
|
||||
# assert state.balances[validator_index] == spec.MAX_EFFECTIVE_BALANCE_EIP7251 + amount
|
||||
# assert state.validators[validator_index].effective_balance == spec.MAX_EFFECTIVE_BALANCE_EIP7251
|
||||
|
||||
@with_eip7251_and_later
|
||||
@spec_state_test
|
||||
@always_bls
|
||||
def test_correct_sig_but_forked_state(spec, state):
|
||||
validator_index = len(state.validators)
|
||||
amount = spec.MAX_EFFECTIVE_BALANCE
|
||||
# deposits will always be valid, regardless of the current fork
|
||||
state.fork.current_version = spec.Version('0x1234abcd')
|
||||
deposit = prepare_state_and_deposit(spec, state, validator_index, amount, signed=True)
|
||||
yield from run_deposit_processing_eip7251(spec, state, deposit, validator_index)
|
||||
|
||||
|
||||
@with_eip7251_and_later
|
||||
@spec_state_test
|
||||
@always_bls
|
||||
def test_incorrect_sig_new_deposit(spec, state):
|
||||
# fresh deposit = next validator index = validator appended to registry
|
||||
validator_index = len(state.validators)
|
||||
amount = spec.MIN_ACTIVATION_BALANCE
|
||||
deposit = prepare_state_and_deposit(spec, state, validator_index, amount)
|
||||
yield from run_deposit_processing_eip7251(spec, state, deposit, validator_index, effective=False)
|
||||
|
||||
|
||||
@with_eip7251_and_later
|
||||
@spec_state_test
|
||||
def test_top_up__max_effective_balance(spec, state):
|
||||
validator_index = 0
|
||||
amount = spec.MAX_EFFECTIVE_BALANCE // 4
|
||||
deposit = prepare_state_and_deposit(spec, state, validator_index, amount, signed=True)
|
||||
|
||||
state.balances[validator_index] = spec.MAX_EFFECTIVE_BALANCE
|
||||
state.validators[validator_index].effective_balance = spec.MAX_EFFECTIVE_BALANCE
|
||||
|
||||
yield from run_deposit_processing_eip7251(spec, state, deposit, validator_index)
|
||||
|
||||
assert state.validators[validator_index].effective_balance == spec.MAX_EFFECTIVE_BALANCE
|
||||
|
||||
|
||||
@with_eip7251_and_later
|
||||
@spec_state_test
|
||||
def test_top_up__less_effective_balance(spec, state):
|
||||
validator_index = 0
|
||||
amount = spec.MAX_EFFECTIVE_BALANCE // 4
|
||||
deposit = prepare_state_and_deposit(spec, state, validator_index, amount, signed=True)
|
||||
|
||||
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_deposit_processing_eip7251(spec, state, deposit, validator_index)
|
||||
|
||||
# unchanged effective balance
|
||||
assert state.validators[validator_index].effective_balance == initial_effective_balance
|
||||
|
||||
|
||||
@with_eip7251_and_later
|
||||
@spec_state_test
|
||||
def test_top_up__zero_balance(spec, state):
|
||||
validator_index = 0
|
||||
amount = spec.MAX_EFFECTIVE_BALANCE // 4
|
||||
deposit = prepare_state_and_deposit(spec, state, validator_index, amount, signed=True)
|
||||
|
||||
initial_balance = 0
|
||||
initial_effective_balance = 0
|
||||
state.balances[validator_index] = initial_balance
|
||||
state.validators[validator_index].effective_balance = initial_effective_balance
|
||||
|
||||
yield from run_deposit_processing_eip7251(spec, state, deposit, validator_index)
|
||||
|
||||
# unchanged effective balance
|
||||
assert state.validators[validator_index].effective_balance == initial_effective_balance
|
||||
|
||||
|
||||
@with_eip7251_and_later
|
||||
@spec_state_test
|
||||
@always_bls
|
||||
def test_incorrect_sig_top_up(spec, state):
|
||||
validator_index = 0
|
||||
amount = spec.MAX_EFFECTIVE_BALANCE // 4
|
||||
deposit = prepare_state_and_deposit(spec, state, validator_index, amount)
|
||||
|
||||
# invalid signatures, in top-ups, are allowed!
|
||||
yield from run_deposit_processing_eip7251(spec, state, deposit, validator_index)
|
||||
|
||||
|
||||
@with_eip7251_and_later
|
||||
@spec_state_test
|
||||
def test_incorrect_withdrawal_credentials_top_up(spec, state):
|
||||
validator_index = 0
|
||||
amount = spec.MAX_EFFECTIVE_BALANCE // 4
|
||||
withdrawal_credentials = spec.BLS_WITHDRAWAL_PREFIX + spec.hash(b"junk")[1:]
|
||||
deposit = prepare_state_and_deposit(
|
||||
spec,
|
||||
state,
|
||||
validator_index,
|
||||
amount,
|
||||
withdrawal_credentials=withdrawal_credentials
|
||||
)
|
||||
|
||||
# inconsistent withdrawal credentials, in top-ups, are allowed!
|
||||
yield from run_deposit_processing_eip7251(spec, state, deposit, validator_index)
|
||||
|
||||
|
||||
@with_eip7251_and_later
|
||||
@spec_state_test
|
||||
def test_invalid_wrong_deposit_for_deposit_count(spec, state):
|
||||
deposit_data_leaves = [spec.DepositData() for _ in range(len(state.validators))]
|
||||
|
||||
# build root for deposit_1
|
||||
index_1 = len(deposit_data_leaves)
|
||||
pubkey_1 = pubkeys[index_1]
|
||||
privkey_1 = privkeys[index_1]
|
||||
_, _, deposit_data_leaves = build_deposit(
|
||||
spec,
|
||||
deposit_data_leaves,
|
||||
pubkey_1,
|
||||
privkey_1,
|
||||
spec.MAX_EFFECTIVE_BALANCE,
|
||||
withdrawal_credentials=b'\x00' * 32,
|
||||
signed=True,
|
||||
)
|
||||
deposit_count_1 = len(deposit_data_leaves)
|
||||
|
||||
# build root for deposit_2
|
||||
index_2 = len(deposit_data_leaves)
|
||||
pubkey_2 = pubkeys[index_2]
|
||||
privkey_2 = privkeys[index_2]
|
||||
deposit_2, root_2, deposit_data_leaves = build_deposit(
|
||||
spec,
|
||||
deposit_data_leaves,
|
||||
pubkey_2,
|
||||
privkey_2,
|
||||
spec.MAX_EFFECTIVE_BALANCE,
|
||||
withdrawal_credentials=b'\x00' * 32,
|
||||
signed=True,
|
||||
)
|
||||
|
||||
# state has root for deposit_2 but is at deposit_count for deposit_1
|
||||
state.eth1_data.deposit_root = root_2
|
||||
state.eth1_data.deposit_count = deposit_count_1
|
||||
|
||||
yield from run_deposit_processing_eip7251(spec, state, deposit_2, index_2, valid=False)
|
||||
|
||||
|
||||
@with_eip7251_and_later
|
||||
@spec_state_test
|
||||
def test_invalid_bad_merkle_proof(spec, state):
|
||||
validator_index = len(state.validators)
|
||||
amount = spec.MAX_EFFECTIVE_BALANCE
|
||||
deposit = prepare_state_and_deposit(spec, state, validator_index, amount)
|
||||
|
||||
# mess up merkle branch
|
||||
deposit.proof[5] = spec.Bytes32()
|
||||
|
||||
sign_deposit_data(spec, deposit.data, privkeys[validator_index])
|
||||
|
||||
yield from run_deposit_processing_eip7251(spec, state, deposit, validator_index, valid=False)
|
||||
|
||||
|
||||
@with_eip7251_and_later
|
||||
@spec_state_test
|
||||
def test_key_validate_invalid_subgroup(spec, state):
|
||||
validator_index = len(state.validators)
|
||||
amount = spec.MAX_EFFECTIVE_BALANCE
|
||||
|
||||
# All-zero pubkey would not pass `bls.KeyValidate`, but `process_deposit` would not throw exception.
|
||||
pubkey = b'\x00' * 48
|
||||
|
||||
deposit = prepare_state_and_deposit(spec, state, validator_index, amount, pubkey=pubkey, signed=True)
|
||||
|
||||
yield from run_deposit_processing_eip7251(spec, state, deposit, validator_index)
|
||||
|
||||
|
||||
@with_eip7251_and_later
|
||||
@spec_state_test
|
||||
def test_key_validate_invalid_decompression(spec, state):
|
||||
validator_index = len(state.validators)
|
||||
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)
|
||||
|
||||
deposit = prepare_state_and_deposit(spec, state, validator_index, amount, pubkey=pubkey, signed=True)
|
||||
|
||||
yield from run_deposit_processing_eip7251(spec, state, deposit, validator_index)
|
||||
|
||||
|
||||
@with_eip7251_and_later
|
||||
@spec_state_test
|
||||
@always_bls
|
||||
def test_ineffective_deposit_with_bad_fork_version(spec, state):
|
||||
yield from run_deposit_processing_eip7251_with_specific_fork_version(
|
||||
spec,
|
||||
state,
|
||||
fork_version=spec.Version('0xAaBbCcDd'),
|
||||
effective=False,
|
||||
)
|
@ -10,6 +10,7 @@ from eth2spec.test.helpers.state import (
|
||||
)
|
||||
from eth2spec.test.helpers.withdrawals import (
|
||||
set_eth1_withdrawal_credential_with_balance,
|
||||
set_compounding_withdrawal_credential,
|
||||
)
|
||||
|
||||
|
||||
@ -19,6 +20,7 @@ from eth2spec.test.helpers.withdrawals import (
|
||||
|
||||
# Modified tests from 7002. Just testing EL-triggered exits, not partial withdrawals
|
||||
|
||||
|
||||
@with_eip7251_and_later
|
||||
@spec_state_test
|
||||
def test_basic_exit(spec, state):
|
||||
@ -28,15 +30,78 @@ def test_basic_exit(spec, state):
|
||||
current_epoch = spec.get_current_epoch(state)
|
||||
validator_index = spec.get_active_validator_indices(state, current_epoch)[0]
|
||||
validator_pubkey = state.validators[validator_index].pubkey
|
||||
address = b'\x22' * 20
|
||||
set_eth1_withdrawal_credential_with_balance(spec, state, validator_index, address=address)
|
||||
address = b"\x22" * 20
|
||||
set_eth1_withdrawal_credential_with_balance(
|
||||
spec, state, validator_index, address=address
|
||||
)
|
||||
execution_layer_withdraw_request = spec.ExecutionLayerWithdrawRequest(
|
||||
source_address=address,
|
||||
validator_pubkey=validator_pubkey,
|
||||
amount=0,
|
||||
amount=spec.FULL_EXIT_REQUEST_AMOUNT,
|
||||
)
|
||||
|
||||
yield from run_execution_layer_withdraw_request_processing(spec, state, execution_layer_withdraw_request)
|
||||
yield from run_execution_layer_withdraw_request_processing(
|
||||
spec, state, execution_layer_withdraw_request
|
||||
)
|
||||
|
||||
|
||||
@with_eip7251_and_later
|
||||
@spec_state_test
|
||||
def test_basic_exit_with_compounding_credentials(spec, state):
|
||||
# move state forward SHARD_COMMITTEE_PERIOD epochs to allow for exit
|
||||
state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH
|
||||
|
||||
current_epoch = spec.get_current_epoch(state)
|
||||
validator_index = spec.get_active_validator_indices(state, current_epoch)[0]
|
||||
validator_pubkey = state.validators[validator_index].pubkey
|
||||
address = b"\x22" * 20
|
||||
set_compounding_withdrawal_credential(spec, state, validator_index, address=address)
|
||||
execution_layer_withdraw_request = spec.ExecutionLayerWithdrawRequest(
|
||||
source_address=address,
|
||||
validator_pubkey=validator_pubkey,
|
||||
amount=spec.FULL_EXIT_REQUEST_AMOUNT,
|
||||
)
|
||||
|
||||
yield from run_execution_layer_withdraw_request_processing(
|
||||
spec, state, execution_layer_withdraw_request
|
||||
)
|
||||
|
||||
|
||||
@with_eip7251_and_later
|
||||
@spec_state_test
|
||||
@with_presets([MINIMAL], "need full partial withdrawal queue")
|
||||
def test_basic_exit_with_full_partial_withdrawal_queue(spec, state):
|
||||
state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH
|
||||
current_epoch = spec.get_current_epoch(state)
|
||||
validator_index = spec.get_active_validator_indices(state, current_epoch)[0]
|
||||
validator_pubkey = state.validators[validator_index].pubkey
|
||||
address = b"\x22" * 20
|
||||
set_eth1_withdrawal_credential_with_balance(
|
||||
spec, state, validator_index, address=address
|
||||
)
|
||||
execution_layer_withdraw_request = spec.ExecutionLayerWithdrawRequest(
|
||||
source_address=address,
|
||||
validator_pubkey=validator_pubkey,
|
||||
amount=spec.FULL_EXIT_REQUEST_AMOUNT,
|
||||
)
|
||||
|
||||
# Fill the partial withdrawal queue to the max (with a different validator index)
|
||||
partial_withdrawal = spec.PendingPartialWithdrawal(
|
||||
index=1, amount=1, withdrawable_epoch=current_epoch
|
||||
)
|
||||
state.pending_partial_withdrawals = [
|
||||
partial_withdrawal
|
||||
] * spec.PENDING_PARTIAL_WITHDRAWALS_LIMIT
|
||||
|
||||
# Exit should still be processed
|
||||
yield from run_execution_layer_withdraw_request_processing(
|
||||
spec,
|
||||
state,
|
||||
execution_layer_withdraw_request,
|
||||
)
|
||||
|
||||
|
||||
# Invalid tests
|
||||
|
||||
|
||||
@with_eip7251_and_later
|
||||
@ -48,13 +113,15 @@ def test_incorrect_source_address(spec, state):
|
||||
current_epoch = spec.get_current_epoch(state)
|
||||
validator_index = spec.get_active_validator_indices(state, current_epoch)[0]
|
||||
validator_pubkey = state.validators[validator_index].pubkey
|
||||
address = b'\x22' * 20
|
||||
incorrect_address = b'\x33' * 20
|
||||
set_eth1_withdrawal_credential_with_balance(spec, state, validator_index, address=address)
|
||||
address = b"\x22" * 20
|
||||
incorrect_address = b"\x33" * 20
|
||||
set_eth1_withdrawal_credential_with_balance(
|
||||
spec, state, validator_index, address=address
|
||||
)
|
||||
execution_layer_withdraw_request = spec.ExecutionLayerWithdrawRequest(
|
||||
source_address=incorrect_address,
|
||||
validator_pubkey=validator_pubkey,
|
||||
amount=0,
|
||||
amount=spec.FULL_EXIT_REQUEST_AMOUNT,
|
||||
)
|
||||
|
||||
yield from run_execution_layer_withdraw_request_processing(
|
||||
@ -71,8 +138,10 @@ def test_incorrect_withdrawal_credential_prefix(spec, state):
|
||||
current_epoch = spec.get_current_epoch(state)
|
||||
validator_index = spec.get_active_validator_indices(state, current_epoch)[0]
|
||||
validator_pubkey = state.validators[validator_index].pubkey
|
||||
address = b'\x22' * 20
|
||||
set_eth1_withdrawal_credential_with_balance(spec, state, validator_index, address=address)
|
||||
address = b"\x22" * 20
|
||||
set_eth1_withdrawal_credential_with_balance(
|
||||
spec, state, validator_index, address=address
|
||||
)
|
||||
# Set incorrect prefix
|
||||
state.validators[validator_index].withdrawal_credentials = (
|
||||
spec.BLS_WITHDRAWAL_PREFIX
|
||||
@ -81,7 +150,7 @@ def test_incorrect_withdrawal_credential_prefix(spec, state):
|
||||
execution_layer_withdraw_request = spec.ExecutionLayerWithdrawRequest(
|
||||
source_address=address,
|
||||
validator_pubkey=validator_pubkey,
|
||||
amount=0,
|
||||
amount=spec.FULL_EXIT_REQUEST_AMOUNT,
|
||||
)
|
||||
|
||||
yield from run_execution_layer_withdraw_request_processing(
|
||||
@ -98,14 +167,16 @@ def test_on_exit_initiated_validator(spec, state):
|
||||
current_epoch = spec.get_current_epoch(state)
|
||||
validator_index = spec.get_active_validator_indices(state, current_epoch)[0]
|
||||
validator_pubkey = state.validators[validator_index].pubkey
|
||||
address = b'\x22' * 20
|
||||
set_eth1_withdrawal_credential_with_balance(spec, state, validator_index, address=address)
|
||||
address = b"\x22" * 20
|
||||
set_eth1_withdrawal_credential_with_balance(
|
||||
spec, state, validator_index, address=address
|
||||
)
|
||||
# Initiate exit earlier
|
||||
spec.initiate_validator_exit(state, validator_index)
|
||||
execution_layer_withdraw_request = spec.ExecutionLayerWithdrawRequest(
|
||||
source_address=address,
|
||||
validator_pubkey=validator_pubkey,
|
||||
amount=0,
|
||||
amount=spec.FULL_EXIT_REQUEST_AMOUNT,
|
||||
)
|
||||
|
||||
yield from run_execution_layer_withdraw_request_processing(
|
||||
@ -119,16 +190,19 @@ def test_activation_epoch_less_than_shard_committee_period(spec, state):
|
||||
current_epoch = spec.get_current_epoch(state)
|
||||
validator_index = spec.get_active_validator_indices(state, current_epoch)[0]
|
||||
validator_pubkey = state.validators[validator_index].pubkey
|
||||
address = b'\x22' * 20
|
||||
set_eth1_withdrawal_credential_with_balance(spec, state, validator_index, address=address)
|
||||
address = b"\x22" * 20
|
||||
set_eth1_withdrawal_credential_with_balance(
|
||||
spec, state, validator_index, address=address
|
||||
)
|
||||
execution_layer_withdraw_request = spec.ExecutionLayerWithdrawRequest(
|
||||
source_address=address,
|
||||
validator_pubkey=validator_pubkey,
|
||||
amount=0,
|
||||
amount=spec.FULL_EXIT_REQUEST_AMOUNT,
|
||||
)
|
||||
|
||||
assert spec.get_current_epoch(state) < (
|
||||
state.validators[validator_index].activation_epoch + spec.config.SHARD_COMMITTEE_PERIOD
|
||||
state.validators[validator_index].activation_epoch
|
||||
+ spec.config.SHARD_COMMITTEE_PERIOD
|
||||
)
|
||||
|
||||
yield from run_execution_layer_withdraw_request_processing(
|
||||
@ -138,24 +212,533 @@ def test_activation_epoch_less_than_shard_committee_period(spec, state):
|
||||
|
||||
# Partial withdrawals tests
|
||||
|
||||
|
||||
@with_eip7251_and_later
|
||||
@spec_state_test
|
||||
@with_presets([MINIMAL])
|
||||
def test_basic_partial_withdrawal_request(spec, state):
|
||||
state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH
|
||||
current_epoch = spec.get_current_epoch(state)
|
||||
validator_index = spec.get_active_validator_indices(state, current_epoch)[0]
|
||||
validator_pubkey = state.validators[validator_index].pubkey
|
||||
address = b"\x22" * 20
|
||||
amount = spec.EFFECTIVE_BALANCE_INCREMENT
|
||||
# Set excess balance exactly to the requested amount
|
||||
state.balances[validator_index] += amount
|
||||
|
||||
set_compounding_withdrawal_credential(spec, state, validator_index, address=address)
|
||||
execution_layer_withdraw_request = spec.ExecutionLayerWithdrawRequest(
|
||||
source_address=address,
|
||||
validator_pubkey=validator_pubkey,
|
||||
amount=amount,
|
||||
)
|
||||
|
||||
yield from run_execution_layer_withdraw_request_processing(
|
||||
spec,
|
||||
state,
|
||||
execution_layer_withdraw_request,
|
||||
)
|
||||
|
||||
# Check that the assigned exit epoch is correct
|
||||
assert state.earliest_exit_epoch == spec.compute_activation_exit_epoch(
|
||||
current_epoch
|
||||
)
|
||||
|
||||
|
||||
@with_eip7251_and_later
|
||||
@spec_state_test
|
||||
@with_presets([MINIMAL])
|
||||
def test_basic_partial_withdrawal_request_higher_excess_balance(spec, state):
|
||||
state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH
|
||||
current_epoch = spec.get_current_epoch(state)
|
||||
validator_index = spec.get_active_validator_indices(state, current_epoch)[0]
|
||||
validator_pubkey = state.validators[validator_index].pubkey
|
||||
address = b"\x22" * 20
|
||||
amount = spec.EFFECTIVE_BALANCE_INCREMENT
|
||||
# Set excess balance higher than requested amount
|
||||
state.balances[validator_index] += 2 * amount
|
||||
|
||||
set_compounding_withdrawal_credential(spec, state, validator_index, address=address)
|
||||
execution_layer_withdraw_request = spec.ExecutionLayerWithdrawRequest(
|
||||
source_address=address,
|
||||
validator_pubkey=validator_pubkey,
|
||||
amount=amount,
|
||||
)
|
||||
|
||||
yield from run_execution_layer_withdraw_request_processing(
|
||||
spec,
|
||||
state,
|
||||
execution_layer_withdraw_request,
|
||||
)
|
||||
|
||||
# Check that the assigned exit epoch is correct
|
||||
assert state.earliest_exit_epoch == spec.compute_activation_exit_epoch(
|
||||
current_epoch
|
||||
)
|
||||
|
||||
|
||||
@with_eip7251_and_later
|
||||
@spec_state_test
|
||||
@with_presets([MINIMAL])
|
||||
def test_basic_partial_withdrawal_request_lower_than_excess_balance(spec, state):
|
||||
state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH
|
||||
current_epoch = spec.get_current_epoch(state)
|
||||
validator_index = spec.get_active_validator_indices(state, current_epoch)[0]
|
||||
validator_pubkey = state.validators[validator_index].pubkey
|
||||
address = b"\x22" * 20
|
||||
excess_balance = spec.EFFECTIVE_BALANCE_INCREMENT
|
||||
amount = 2 * excess_balance
|
||||
# Set excess balance higher than requested amount
|
||||
state.balances[validator_index] += excess_balance
|
||||
|
||||
set_compounding_withdrawal_credential(spec, state, validator_index, address=address)
|
||||
execution_layer_withdraw_request = spec.ExecutionLayerWithdrawRequest(
|
||||
source_address=address,
|
||||
validator_pubkey=validator_pubkey,
|
||||
amount=amount,
|
||||
)
|
||||
|
||||
yield from run_execution_layer_withdraw_request_processing(
|
||||
spec,
|
||||
state,
|
||||
execution_layer_withdraw_request,
|
||||
)
|
||||
|
||||
# Check that the assigned exit epoch is correct
|
||||
assert state.earliest_exit_epoch == spec.compute_activation_exit_epoch(
|
||||
current_epoch
|
||||
)
|
||||
|
||||
|
||||
@with_eip7251_and_later
|
||||
@spec_state_test
|
||||
@with_presets([MINIMAL])
|
||||
def test_partial_withdrawal_request_with_pending_withdrawals(spec, state):
|
||||
state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH
|
||||
current_epoch = spec.get_current_epoch(state)
|
||||
validator_index = spec.get_active_validator_indices(state, current_epoch)[0]
|
||||
validator_pubkey = state.validators[validator_index].pubkey
|
||||
address = b"\x22" * 20
|
||||
amount = spec.EFFECTIVE_BALANCE_INCREMENT
|
||||
|
||||
set_compounding_withdrawal_credential(spec, state, validator_index, address=address)
|
||||
execution_layer_withdraw_request = spec.ExecutionLayerWithdrawRequest(
|
||||
source_address=address,
|
||||
validator_pubkey=validator_pubkey,
|
||||
amount=amount,
|
||||
)
|
||||
|
||||
# Add pending withdrawals
|
||||
partial_withdrawal = spec.PendingPartialWithdrawal(
|
||||
index=validator_index, amount=amount, withdrawable_epoch=current_epoch
|
||||
)
|
||||
state.pending_partial_withdrawals = [partial_withdrawal] * 2
|
||||
|
||||
# Set balance so that the validator still has excess balance even with the pending withdrawals
|
||||
state.balances[validator_index] += 3 * amount
|
||||
|
||||
yield from run_execution_layer_withdraw_request_processing(
|
||||
spec,
|
||||
state,
|
||||
execution_layer_withdraw_request,
|
||||
)
|
||||
|
||||
# Check that the assigned exit epoch is correct
|
||||
assert state.earliest_exit_epoch == spec.compute_activation_exit_epoch(
|
||||
current_epoch
|
||||
)
|
||||
|
||||
|
||||
@with_eip7251_and_later
|
||||
@spec_state_test
|
||||
@with_presets([MINIMAL])
|
||||
def test_partial_withdrawal_request_with_pending_withdrawals_and_high_amount(
|
||||
spec, state
|
||||
):
|
||||
state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH
|
||||
current_epoch = spec.get_current_epoch(state)
|
||||
validator_index = spec.get_active_validator_indices(state, current_epoch)[0]
|
||||
validator_pubkey = state.validators[validator_index].pubkey
|
||||
address = b"\x22" * 20
|
||||
amount = spec.UINT64_MAX
|
||||
|
||||
set_compounding_withdrawal_credential(spec, state, validator_index, address=address)
|
||||
execution_layer_withdraw_request = spec.ExecutionLayerWithdrawRequest(
|
||||
source_address=address,
|
||||
validator_pubkey=validator_pubkey,
|
||||
amount=amount,
|
||||
)
|
||||
|
||||
# Add many pending withdrawals
|
||||
partial_withdrawal = spec.PendingPartialWithdrawal(
|
||||
index=validator_index,
|
||||
amount=spec.EFFECTIVE_BALANCE_INCREMENT,
|
||||
withdrawable_epoch=current_epoch,
|
||||
)
|
||||
state.pending_partial_withdrawals = [partial_withdrawal] * (
|
||||
spec.PENDING_PARTIAL_WITHDRAWALS_LIMIT - 1
|
||||
)
|
||||
|
||||
# Set balance so that the validator still has excess balance even with the pending withdrawals
|
||||
state.balances[validator_index] = spec.MAX_EFFECTIVE_BALANCE_EIP7251
|
||||
|
||||
yield from run_execution_layer_withdraw_request_processing(
|
||||
spec,
|
||||
state,
|
||||
execution_layer_withdraw_request,
|
||||
)
|
||||
|
||||
|
||||
@with_eip7251_and_later
|
||||
@spec_state_test
|
||||
@with_presets([MINIMAL])
|
||||
def test_partial_withdrawal_request_with_high_balance(spec, state):
|
||||
state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH
|
||||
current_epoch = spec.get_current_epoch(state)
|
||||
validator_index = spec.get_active_validator_indices(state, current_epoch)[0]
|
||||
validator_pubkey = state.validators[validator_index].pubkey
|
||||
address = b"\x22" * 20
|
||||
amount = spec.MAX_EFFECTIVE_BALANCE_EIP7251
|
||||
state.balances[validator_index] = 3 * spec.MAX_EFFECTIVE_BALANCE_EIP7251
|
||||
state.validators[validator_index].effective_balance = (
|
||||
spec.MAX_EFFECTIVE_BALANCE_EIP7251
|
||||
)
|
||||
|
||||
set_compounding_withdrawal_credential(spec, state, validator_index, address=address)
|
||||
execution_layer_withdraw_request = spec.ExecutionLayerWithdrawRequest(
|
||||
source_address=address,
|
||||
validator_pubkey=validator_pubkey,
|
||||
amount=amount,
|
||||
)
|
||||
|
||||
churn_limit = spec.get_activation_exit_churn_limit(state)
|
||||
|
||||
yield from run_execution_layer_withdraw_request_processing(
|
||||
spec,
|
||||
state,
|
||||
execution_layer_withdraw_request,
|
||||
)
|
||||
|
||||
# Check that the assigned exit epoch is correct
|
||||
exit_epoch = (
|
||||
spec.compute_activation_exit_epoch(current_epoch) + amount // churn_limit
|
||||
)
|
||||
assert state.earliest_exit_epoch == exit_epoch
|
||||
|
||||
|
||||
@with_eip7251_and_later
|
||||
@spec_state_test
|
||||
@with_presets([MINIMAL])
|
||||
def test_partial_withdrawal_request_with_high_amount(spec, state):
|
||||
state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH
|
||||
current_epoch = spec.get_current_epoch(state)
|
||||
validator_index = spec.get_active_validator_indices(state, current_epoch)[0]
|
||||
validator_pubkey = state.validators[validator_index].pubkey
|
||||
address = b"\x22" * 20
|
||||
# Set high amount requested to withdraw
|
||||
amount = spec.UINT64_MAX
|
||||
# Give the validator some excess balance to withdraw
|
||||
state.balances[validator_index] += 1
|
||||
|
||||
set_compounding_withdrawal_credential(spec, state, validator_index, address=address)
|
||||
execution_layer_withdraw_request = spec.ExecutionLayerWithdrawRequest(
|
||||
source_address=address,
|
||||
validator_pubkey=validator_pubkey,
|
||||
amount=amount,
|
||||
)
|
||||
|
||||
yield from run_execution_layer_withdraw_request_processing(
|
||||
spec,
|
||||
state,
|
||||
execution_layer_withdraw_request,
|
||||
)
|
||||
|
||||
# Check that the assigned exit epoch is correct
|
||||
assert state.earliest_exit_epoch == spec.compute_activation_exit_epoch(
|
||||
current_epoch
|
||||
)
|
||||
|
||||
|
||||
@with_eip7251_and_later
|
||||
@spec_state_test
|
||||
@with_presets([MINIMAL])
|
||||
def test_partial_withdrawal_request_with_low_amount(spec, state):
|
||||
state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH
|
||||
current_epoch = spec.get_current_epoch(state)
|
||||
validator_index = spec.get_active_validator_indices(state, current_epoch)[0]
|
||||
validator_pubkey = state.validators[validator_index].pubkey
|
||||
address = b"\x22" * 20
|
||||
amount = 1
|
||||
# Give the validator some excess balance to withdraw
|
||||
state.balances[validator_index] += amount
|
||||
|
||||
set_compounding_withdrawal_credential(spec, state, validator_index, address=address)
|
||||
execution_layer_withdraw_request = spec.ExecutionLayerWithdrawRequest(
|
||||
source_address=address,
|
||||
validator_pubkey=validator_pubkey,
|
||||
amount=amount,
|
||||
)
|
||||
|
||||
yield from run_execution_layer_withdraw_request_processing(
|
||||
spec,
|
||||
state,
|
||||
execution_layer_withdraw_request,
|
||||
)
|
||||
|
||||
# Check that the assigned exit epoch is correct
|
||||
assert state.earliest_exit_epoch == spec.compute_activation_exit_epoch(
|
||||
current_epoch
|
||||
)
|
||||
|
||||
|
||||
# No-op partial withdrawal tests
|
||||
|
||||
|
||||
@with_eip7251_and_later
|
||||
@spec_state_test
|
||||
@with_presets([MINIMAL], "need full partial withdrawal queue")
|
||||
def test_partial_withdrawal_queue_full(spec, state):
|
||||
state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH
|
||||
current_epoch = spec.get_current_epoch(state)
|
||||
validator_index = spec.get_active_validator_indices(state, current_epoch)[0]
|
||||
validator_pubkey = state.validators[validator_index].pubkey
|
||||
address = b'\x22' * 20
|
||||
set_eth1_withdrawal_credential_with_balance(spec, state, validator_index, address=address)
|
||||
address = b"\x22" * 20
|
||||
amount = spec.EFFECTIVE_BALANCE_INCREMENT
|
||||
# Ensure that the validator has sufficient excess balance
|
||||
state.balances[validator_index] += 2 * amount
|
||||
set_compounding_withdrawal_credential(spec, state, validator_index, address=address)
|
||||
execution_layer_withdraw_request = spec.ExecutionLayerWithdrawRequest(
|
||||
source_address=address,
|
||||
validator_pubkey=validator_pubkey,
|
||||
amount=10 ** 9,
|
||||
amount=amount,
|
||||
)
|
||||
|
||||
# Fill the partial withdrawal queue to the max
|
||||
partial_withdrawal = spec.PendingPartialWithdrawal(
|
||||
index=1, amount=1, withdrawable_epoch=current_epoch
|
||||
)
|
||||
state.pending_partial_withdrawals = [
|
||||
partial_withdrawal
|
||||
] * spec.PENDING_PARTIAL_WITHDRAWALS_LIMIT
|
||||
yield from run_execution_layer_withdraw_request_processing(
|
||||
spec, state, execution_layer_withdraw_request, success=False
|
||||
)
|
||||
|
||||
|
||||
@with_eip7251_and_later
|
||||
@spec_state_test
|
||||
def test_no_compounding_credentials(spec, state):
|
||||
state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH
|
||||
current_epoch = spec.get_current_epoch(state)
|
||||
validator_index = spec.get_active_validator_indices(state, current_epoch)[0]
|
||||
validator_pubkey = state.validators[validator_index].pubkey
|
||||
address = b"\x22" * 20
|
||||
amount = spec.EFFECTIVE_BALANCE_INCREMENT
|
||||
# Ensure that the validator has sufficient excess balance
|
||||
state.balances[validator_index] += 2 * amount
|
||||
|
||||
set_eth1_withdrawal_credential_with_balance(
|
||||
spec, state, validator_index, address=address
|
||||
)
|
||||
execution_layer_withdraw_request = spec.ExecutionLayerWithdrawRequest(
|
||||
source_address=address,
|
||||
validator_pubkey=validator_pubkey,
|
||||
amount=amount,
|
||||
)
|
||||
|
||||
yield from run_execution_layer_withdraw_request_processing(
|
||||
spec,
|
||||
state,
|
||||
execution_layer_withdraw_request,
|
||||
success=False,
|
||||
)
|
||||
|
||||
|
||||
@with_eip7251_and_later
|
||||
@spec_state_test
|
||||
def test_no_excess_balance(spec, state):
|
||||
state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH
|
||||
current_epoch = spec.get_current_epoch(state)
|
||||
validator_index = spec.get_active_validator_indices(state, current_epoch)[0]
|
||||
validator_pubkey = state.validators[validator_index].pubkey
|
||||
address = b"\x22" * 20
|
||||
amount = spec.EFFECTIVE_BALANCE_INCREMENT
|
||||
|
||||
set_compounding_withdrawal_credential(spec, state, validator_index, address=address)
|
||||
execution_layer_withdraw_request = spec.ExecutionLayerWithdrawRequest(
|
||||
source_address=address,
|
||||
validator_pubkey=validator_pubkey,
|
||||
amount=amount,
|
||||
)
|
||||
|
||||
yield from run_execution_layer_withdraw_request_processing(
|
||||
spec, state, execution_layer_withdraw_request, success=False
|
||||
)
|
||||
|
||||
|
||||
@with_eip7251_and_later
|
||||
@spec_state_test
|
||||
def test_pending_withdrawals_consume_all_excess_balance(spec, state):
|
||||
state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH
|
||||
current_epoch = spec.get_current_epoch(state)
|
||||
validator_index = spec.get_active_validator_indices(state, current_epoch)[0]
|
||||
validator_pubkey = state.validators[validator_index].pubkey
|
||||
address = b"\x22" * 20
|
||||
amount = spec.EFFECTIVE_BALANCE_INCREMENT
|
||||
# Add excess balance
|
||||
state.balances[validator_index] += 10 * amount
|
||||
|
||||
set_compounding_withdrawal_credential(spec, state, validator_index, address=address)
|
||||
execution_layer_withdraw_request = spec.ExecutionLayerWithdrawRequest(
|
||||
source_address=address,
|
||||
validator_pubkey=validator_pubkey,
|
||||
amount=amount,
|
||||
)
|
||||
|
||||
# Add pending withdrawals totalling an amount equal to the excess balance
|
||||
partial_withdrawal = spec.PendingPartialWithdrawal(
|
||||
index=validator_index, amount=amount, withdrawable_epoch=current_epoch
|
||||
)
|
||||
state.pending_partial_withdrawals = [partial_withdrawal] * 10
|
||||
|
||||
yield from run_execution_layer_withdraw_request_processing(
|
||||
spec, state, execution_layer_withdraw_request, success=False
|
||||
)
|
||||
|
||||
|
||||
@with_eip7251_and_later
|
||||
@spec_state_test
|
||||
def test_insufficient_effective_balance(spec, state):
|
||||
state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH
|
||||
current_epoch = spec.get_current_epoch(state)
|
||||
validator_index = spec.get_active_validator_indices(state, current_epoch)[0]
|
||||
validator_pubkey = state.validators[validator_index].pubkey
|
||||
address = b"\x22" * 20
|
||||
amount = spec.EFFECTIVE_BALANCE_INCREMENT
|
||||
# Make effective balance insufficient
|
||||
state.validators[
|
||||
validator_index
|
||||
].effective_balance -= spec.EFFECTIVE_BALANCE_INCREMENT
|
||||
|
||||
set_compounding_withdrawal_credential(spec, state, validator_index, address=address)
|
||||
execution_layer_withdraw_request = spec.ExecutionLayerWithdrawRequest(
|
||||
source_address=address,
|
||||
validator_pubkey=validator_pubkey,
|
||||
amount=amount,
|
||||
)
|
||||
|
||||
yield from run_execution_layer_withdraw_request_processing(
|
||||
spec,
|
||||
state,
|
||||
execution_layer_withdraw_request,
|
||||
success=False,
|
||||
)
|
||||
|
||||
|
||||
@with_eip7251_and_later
|
||||
@spec_state_test
|
||||
def test_partial_withdrawal_incorrect_source_address(spec, state):
|
||||
# move state forward SHARD_COMMITTEE_PERIOD epochs to allow for exit
|
||||
state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH
|
||||
|
||||
current_epoch = spec.get_current_epoch(state)
|
||||
validator_index = spec.get_active_validator_indices(state, current_epoch)[0]
|
||||
validator_pubkey = state.validators[validator_index].pubkey
|
||||
address = b"\x22" * 20
|
||||
incorrect_address = b"\x33" * 20
|
||||
amount = spec.EFFECTIVE_BALANCE_INCREMENT
|
||||
state.balances[validator_index] += 2 * amount
|
||||
|
||||
set_compounding_withdrawal_credential(spec, state, validator_index, address=address)
|
||||
execution_layer_withdraw_request = spec.ExecutionLayerWithdrawRequest(
|
||||
source_address=incorrect_address,
|
||||
validator_pubkey=validator_pubkey,
|
||||
amount=amount,
|
||||
)
|
||||
|
||||
yield from run_execution_layer_withdraw_request_processing(
|
||||
spec, state, execution_layer_withdraw_request, success=False
|
||||
)
|
||||
|
||||
|
||||
@with_eip7251_and_later
|
||||
@spec_state_test
|
||||
def test_partial_withdrawal_incorrect_withdrawal_credential_prefix(spec, state):
|
||||
# move state forward SHARD_COMMITTEE_PERIOD epochs to allow for exit
|
||||
state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH
|
||||
|
||||
current_epoch = spec.get_current_epoch(state)
|
||||
validator_index = spec.get_active_validator_indices(state, current_epoch)[0]
|
||||
validator_pubkey = state.validators[validator_index].pubkey
|
||||
address = b"\x22" * 20
|
||||
amount = spec.EFFECTIVE_BALANCE_INCREMENT
|
||||
state.balances[validator_index] += 2 * amount
|
||||
set_compounding_withdrawal_credential(spec, state, validator_index, address=address)
|
||||
# Set incorrect prefix
|
||||
state.validators[validator_index].withdrawal_credentials = (
|
||||
spec.BLS_WITHDRAWAL_PREFIX
|
||||
+ state.validators[validator_index].withdrawal_credentials[1:]
|
||||
)
|
||||
execution_layer_withdraw_request = spec.ExecutionLayerWithdrawRequest(
|
||||
source_address=address,
|
||||
validator_pubkey=validator_pubkey,
|
||||
amount=amount,
|
||||
)
|
||||
|
||||
yield from run_execution_layer_withdraw_request_processing(
|
||||
spec, state, execution_layer_withdraw_request, success=False
|
||||
)
|
||||
|
||||
|
||||
@with_eip7251_and_later
|
||||
@spec_state_test
|
||||
def test_partial_withdrawal_on_exit_initiated_validator(spec, state):
|
||||
# move state forward SHARD_COMMITTEE_PERIOD epochs to allow for exit
|
||||
state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH
|
||||
|
||||
current_epoch = spec.get_current_epoch(state)
|
||||
validator_index = spec.get_active_validator_indices(state, current_epoch)[0]
|
||||
validator_pubkey = state.validators[validator_index].pubkey
|
||||
address = b"\x22" * 20
|
||||
amount = spec.EFFECTIVE_BALANCE_INCREMENT
|
||||
state.balances[validator_index] += 2 * amount
|
||||
set_compounding_withdrawal_credential(spec, state, validator_index, address=address)
|
||||
# Initiate exit earlier
|
||||
spec.initiate_validator_exit(state, validator_index)
|
||||
execution_layer_withdraw_request = spec.ExecutionLayerWithdrawRequest(
|
||||
source_address=address,
|
||||
validator_pubkey=validator_pubkey,
|
||||
amount=amount,
|
||||
)
|
||||
|
||||
yield from run_execution_layer_withdraw_request_processing(
|
||||
spec, state, execution_layer_withdraw_request, success=False
|
||||
)
|
||||
|
||||
|
||||
@with_eip7251_and_later
|
||||
@spec_state_test
|
||||
def test_partial_withdrawal_activation_epoch_less_than_shard_committee_period(
|
||||
spec, state
|
||||
):
|
||||
current_epoch = spec.get_current_epoch(state)
|
||||
validator_index = spec.get_active_validator_indices(state, current_epoch)[0]
|
||||
validator_pubkey = state.validators[validator_index].pubkey
|
||||
address = b"\x22" * 20
|
||||
amount = spec.EFFECTIVE_BALANCE_INCREMENT
|
||||
state.balances[validator_index] += 2 * amount
|
||||
set_compounding_withdrawal_credential(spec, state, validator_index, address=address)
|
||||
execution_layer_withdraw_request = spec.ExecutionLayerWithdrawRequest(
|
||||
source_address=address,
|
||||
validator_pubkey=validator_pubkey,
|
||||
amount=amount,
|
||||
)
|
||||
|
||||
assert spec.get_current_epoch(state) < (
|
||||
state.validators[validator_index].activation_epoch
|
||||
+ spec.config.SHARD_COMMITTEE_PERIOD
|
||||
)
|
||||
|
||||
partial_withdrawal = spec.PendingPartialWithdrawal(index=0, amount=1, withdrawable_epoch=current_epoch)
|
||||
state.pending_partial_withdrawals = [partial_withdrawal] * spec.PENDING_PARTIAL_WITHDRAWALS_LIMIT
|
||||
yield from run_execution_layer_withdraw_request_processing(
|
||||
spec, state, execution_layer_withdraw_request, success=False
|
||||
)
|
||||
@ -165,6 +748,7 @@ def test_partial_withdrawal_queue_full(spec, state):
|
||||
# Run processing
|
||||
#
|
||||
|
||||
|
||||
def run_execution_layer_withdraw_request_processing(
|
||||
spec, state, execution_layer_withdraw_request, valid=True, success=True
|
||||
):
|
||||
@ -176,38 +760,74 @@ def run_execution_layer_withdraw_request_processing(
|
||||
If ``valid == False``, run expecting ``AssertionError``
|
||||
If ``success == False``, it doesn't initiate exit successfully
|
||||
"""
|
||||
validator_index = get_validator_index_by_pubkey(state, execution_layer_withdraw_request.validator_pubkey)
|
||||
validator_index = get_validator_index_by_pubkey(
|
||||
state, execution_layer_withdraw_request.validator_pubkey
|
||||
)
|
||||
|
||||
yield 'pre', state
|
||||
yield 'execution_layer_withdraw_request', execution_layer_withdraw_request
|
||||
yield "pre", state
|
||||
yield "execution_layer_withdraw_request", execution_layer_withdraw_request
|
||||
|
||||
if not valid:
|
||||
expect_assertion_error(
|
||||
lambda: spec.process_execution_layer_withdraw_request(state, execution_layer_withdraw_request))
|
||||
yield 'post', None
|
||||
lambda: spec.process_execution_layer_withdraw_request(
|
||||
state, execution_layer_withdraw_request
|
||||
)
|
||||
)
|
||||
yield "post", None
|
||||
return
|
||||
|
||||
pre_exit_epoch = state.validators[validator_index].exit_epoch
|
||||
pre_pending_partial_withdrawals = state.pending_partial_withdrawals
|
||||
pre_pending_partial_withdrawals = state.pending_partial_withdrawals.copy()
|
||||
pre_balance = state.balances[validator_index]
|
||||
pre_effective_balance = state.validators[validator_index].effective_balance
|
||||
pre_state = state
|
||||
expected_amount_to_withdraw = compute_amount_to_withdraw(
|
||||
spec, state, validator_index, execution_layer_withdraw_request.amount
|
||||
)
|
||||
|
||||
spec.process_execution_layer_withdraw_request(state, execution_layer_withdraw_request)
|
||||
spec.process_execution_layer_withdraw_request(
|
||||
state, execution_layer_withdraw_request
|
||||
)
|
||||
|
||||
yield 'post', state
|
||||
yield "post", state
|
||||
|
||||
if execution_layer_withdraw_request.amount == 0:
|
||||
if success:
|
||||
if not success:
|
||||
# No-op
|
||||
assert pre_state == state
|
||||
else:
|
||||
assert state.balances[validator_index] == pre_balance
|
||||
assert (
|
||||
state.validators[validator_index].effective_balance == pre_effective_balance
|
||||
)
|
||||
# Full exit request
|
||||
if execution_layer_withdraw_request.amount == spec.FULL_EXIT_REQUEST_AMOUNT:
|
||||
assert pre_exit_epoch == spec.FAR_FUTURE_EPOCH
|
||||
assert state.validators[validator_index].exit_epoch < spec.FAR_FUTURE_EPOCH
|
||||
else:
|
||||
assert state.validators[validator_index].exit_epoch == pre_exit_epoch
|
||||
else:
|
||||
if success:
|
||||
assert state.validators[validator_index].exit_epoch == spec.FAR_FUTURE_EPOCH
|
||||
assert state.balances[validator_index] == pre_balance
|
||||
post_length = len(state.pending_partial_withdrawals)
|
||||
assert post_length == len(pre_pending_partial_withdrawals) + 1
|
||||
assert post_length < spec.PENDING_PARTIAL_WITHDRAWALS_LIMIT
|
||||
assert state.pending_partial_withdrawals[post_length - 1].validator_index == validator_index
|
||||
else:
|
||||
assert spec.get_pending_balance_to_withdraw(state, validator_index) == 0
|
||||
assert state.pending_partial_withdrawals == pre_pending_partial_withdrawals
|
||||
# Partial withdrawal request
|
||||
else:
|
||||
assert state.validators[validator_index].exit_epoch == spec.FAR_FUTURE_EPOCH
|
||||
expected_withdrawable_epoch = (
|
||||
state.earliest_exit_epoch
|
||||
+ spec.config.MIN_VALIDATOR_WITHDRAWABILITY_DELAY
|
||||
)
|
||||
expected_partial_withdrawal = spec.PendingPartialWithdrawal(
|
||||
index=validator_index,
|
||||
amount=expected_amount_to_withdraw,
|
||||
withdrawable_epoch=expected_withdrawable_epoch,
|
||||
)
|
||||
assert (
|
||||
state.pending_partial_withdrawals
|
||||
== pre_pending_partial_withdrawals + [expected_partial_withdrawal]
|
||||
)
|
||||
|
||||
|
||||
def compute_amount_to_withdraw(spec, state, index, amount):
|
||||
pending_balance_to_withdraw = spec.get_pending_balance_to_withdraw(state, index)
|
||||
return min(
|
||||
state.balances[index]
|
||||
- spec.MIN_ACTIVATION_BALANCE
|
||||
- pending_balance_to_withdraw,
|
||||
amount,
|
||||
)
|
||||
|
@ -0,0 +1,411 @@
|
||||
from eth2spec.test.helpers.constants import MAINNET
|
||||
from eth2spec.test.context import (
|
||||
spec_state_test,
|
||||
with_eip7251_and_later,
|
||||
with_presets,
|
||||
)
|
||||
from eth2spec.test.helpers.keys import pubkey_to_privkey
|
||||
from eth2spec.test.helpers.voluntary_exits import (
|
||||
run_voluntary_exit_processing,
|
||||
sign_voluntary_exit,
|
||||
)
|
||||
|
||||
# ********************
|
||||
# * EXIT QUEUE TESTS *
|
||||
# ********************
|
||||
|
||||
|
||||
@with_eip7251_and_later
|
||||
@spec_state_test
|
||||
def test_min_balance_exit(spec, state):
|
||||
state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH
|
||||
# This state has 64 validators each with 32 ETH
|
||||
current_epoch = spec.get_current_epoch(state)
|
||||
expected_exit_epoch = spec.compute_activation_exit_epoch(current_epoch)
|
||||
expected_withdrawable_epoch = (
|
||||
expected_exit_epoch + spec.config.MIN_VALIDATOR_WITHDRAWABILITY_DELAY
|
||||
)
|
||||
churn_limit = spec.get_activation_exit_churn_limit(state)
|
||||
# Set the balance to consume equal to churn limit
|
||||
state.exit_balance_to_consume = churn_limit
|
||||
|
||||
validator_index = spec.get_active_validator_indices(
|
||||
state, spec.get_current_epoch(state)
|
||||
)[0]
|
||||
privkey = pubkey_to_privkey[state.validators[validator_index].pubkey]
|
||||
signed_voluntary_exit = sign_voluntary_exit(
|
||||
spec,
|
||||
state,
|
||||
spec.VoluntaryExit(epoch=current_epoch, validator_index=validator_index),
|
||||
privkey,
|
||||
)
|
||||
|
||||
yield from run_voluntary_exit_processing(spec, state, signed_voluntary_exit)
|
||||
|
||||
# Check exit queue churn is set correctly
|
||||
assert state.exit_balance_to_consume == churn_limit - spec.MIN_ACTIVATION_BALANCE
|
||||
# Check exit epoch and withdrawable epoch
|
||||
assert state.validators[0].exit_epoch == expected_exit_epoch
|
||||
assert state.validators[0].withdrawable_epoch == expected_withdrawable_epoch
|
||||
# Check earliest_exit_epoch
|
||||
assert state.earliest_exit_epoch == expected_exit_epoch
|
||||
|
||||
|
||||
@with_eip7251_and_later
|
||||
@spec_state_test
|
||||
def test_min_balance_exits_up_to_churn(spec, state):
|
||||
state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH
|
||||
# This state has 64 validators each with 32 ETH
|
||||
single_validator_balance = spec.MIN_ACTIVATION_BALANCE
|
||||
churn_limit = spec.get_activation_exit_churn_limit(state)
|
||||
# Set the balance to consume equal to churn limit
|
||||
state.exit_balance_to_consume = churn_limit
|
||||
num_to_exit = churn_limit // single_validator_balance
|
||||
|
||||
# Exit all but 1 validators, all fit in the churn limit
|
||||
for i in range(num_to_exit - 1):
|
||||
validator_index = spec.get_active_validator_indices(
|
||||
state, spec.get_current_epoch(state)
|
||||
)[i]
|
||||
spec.initiate_validator_exit(state, validator_index)
|
||||
|
||||
validator_index = spec.get_active_validator_indices(
|
||||
state, spec.get_current_epoch(state)
|
||||
)[num_to_exit]
|
||||
privkey = pubkey_to_privkey[state.validators[validator_index].pubkey]
|
||||
signed_voluntary_exit = sign_voluntary_exit(
|
||||
spec,
|
||||
state,
|
||||
spec.VoluntaryExit(
|
||||
epoch=spec.get_current_epoch(state), validator_index=validator_index
|
||||
),
|
||||
privkey,
|
||||
)
|
||||
yield from run_voluntary_exit_processing(spec, state, signed_voluntary_exit)
|
||||
|
||||
# Last validator also fits in the churn limit
|
||||
expected_exit_epoch = spec.compute_activation_exit_epoch(
|
||||
spec.get_current_epoch(state)
|
||||
)
|
||||
expected_withdrawable_epoch = (
|
||||
expected_exit_epoch + spec.config.MIN_VALIDATOR_WITHDRAWABILITY_DELAY
|
||||
)
|
||||
# Check exit epoch and withdrawable epoch
|
||||
assert state.validators[num_to_exit].exit_epoch == expected_exit_epoch
|
||||
assert (
|
||||
state.validators[num_to_exit].withdrawable_epoch == expected_withdrawable_epoch
|
||||
)
|
||||
# Check exit queue churn is set
|
||||
assert (
|
||||
state.exit_balance_to_consume
|
||||
== churn_limit - single_validator_balance * num_to_exit
|
||||
)
|
||||
# Check earliest_exit_epoch
|
||||
assert state.earliest_exit_epoch == expected_exit_epoch
|
||||
|
||||
|
||||
@with_eip7251_and_later
|
||||
@spec_state_test
|
||||
def test_min_balance_exits_above_churn(spec, state):
|
||||
state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH
|
||||
# This state has 64 validators each with 32 ETH
|
||||
single_validator_balance = spec.MIN_ACTIVATION_BALANCE
|
||||
expected_exit_epoch = spec.compute_activation_exit_epoch(
|
||||
spec.get_current_epoch(state)
|
||||
)
|
||||
expected_withdrawable_epoch = (
|
||||
expected_exit_epoch + spec.config.MIN_VALIDATOR_WITHDRAWABILITY_DELAY
|
||||
)
|
||||
churn_limit = spec.get_activation_exit_churn_limit(state)
|
||||
# Set the balance to consume equal to churn limit
|
||||
state.exit_balance_to_consume = churn_limit
|
||||
num_to_exit = churn_limit // single_validator_balance
|
||||
|
||||
# Exit all but 1 validators, all fit in the churn limit
|
||||
for i in range(num_to_exit):
|
||||
validator_index = spec.get_active_validator_indices(
|
||||
state, spec.get_current_epoch(state)
|
||||
)[i]
|
||||
spec.initiate_validator_exit(state, validator_index)
|
||||
|
||||
# Exit one more validator, not fitting in the churn limit
|
||||
validator_index = spec.get_active_validator_indices(
|
||||
state, spec.get_current_epoch(state)
|
||||
)[num_to_exit]
|
||||
privkey = pubkey_to_privkey[state.validators[validator_index].pubkey]
|
||||
signed_voluntary_exit = sign_voluntary_exit(
|
||||
spec,
|
||||
state,
|
||||
spec.VoluntaryExit(
|
||||
epoch=spec.get_current_epoch(state), validator_index=validator_index
|
||||
),
|
||||
privkey,
|
||||
)
|
||||
yield from run_voluntary_exit_processing(spec, state, signed_voluntary_exit)
|
||||
|
||||
# Check exit epoch and withdrawable epoch. Last validator exits one epoch later
|
||||
assert state.validators[num_to_exit].exit_epoch == expected_exit_epoch + 1
|
||||
assert (
|
||||
state.validators[num_to_exit].withdrawable_epoch
|
||||
== expected_withdrawable_epoch + 1
|
||||
)
|
||||
# Check exit balance to consume is set correctly
|
||||
remainder = (num_to_exit + 1) * single_validator_balance % churn_limit
|
||||
assert state.exit_balance_to_consume == churn_limit - remainder
|
||||
# Check earliest_exit_epoch
|
||||
assert state.earliest_exit_epoch == expected_exit_epoch + 1
|
||||
|
||||
|
||||
@with_eip7251_and_later
|
||||
@spec_state_test
|
||||
@with_presets(
|
||||
[MAINNET],
|
||||
"With CHURN_LIMIT_QUOTIENT=32, can't change validator balance without changing churn_limit",
|
||||
)
|
||||
def test_max_balance_exit(spec, state):
|
||||
state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH
|
||||
current_epoch = spec.get_current_epoch(state)
|
||||
churn_limit = spec.get_activation_exit_churn_limit(state)
|
||||
validator_index = spec.get_active_validator_indices(state, current_epoch)[0]
|
||||
# Set validator effective balance to 2048 ETH
|
||||
to_exit = spec.MAX_EFFECTIVE_BALANCE_EIP7251
|
||||
state.validators[validator_index].effective_balance = to_exit
|
||||
|
||||
privkey = pubkey_to_privkey[state.validators[validator_index].pubkey]
|
||||
signed_voluntary_exit = sign_voluntary_exit(
|
||||
spec,
|
||||
state,
|
||||
spec.VoluntaryExit(epoch=current_epoch, validator_index=validator_index),
|
||||
privkey,
|
||||
)
|
||||
yield from run_voluntary_exit_processing(spec, state, signed_voluntary_exit)
|
||||
|
||||
# Check exit epoch and withdrawable epoch
|
||||
expected_exit_epoch = spec.compute_activation_exit_epoch(
|
||||
spec.get_current_epoch(state)
|
||||
)
|
||||
expected_exit_epoch += to_exit // churn_limit
|
||||
expected_withdrawable_epoch = (
|
||||
expected_exit_epoch + spec.config.MIN_VALIDATOR_WITHDRAWABILITY_DELAY
|
||||
)
|
||||
assert state.validators[validator_index].exit_epoch == expected_exit_epoch
|
||||
assert (
|
||||
state.validators[validator_index].withdrawable_epoch
|
||||
== expected_withdrawable_epoch
|
||||
)
|
||||
# Check exit_balance_to_consume
|
||||
remainder = to_exit % churn_limit
|
||||
assert state.exit_balance_to_consume == churn_limit - remainder
|
||||
# Check earliest_exit_epoch
|
||||
assert state.earliest_exit_epoch == expected_exit_epoch
|
||||
|
||||
|
||||
@with_eip7251_and_later
|
||||
@spec_state_test
|
||||
@with_presets(
|
||||
[MAINNET],
|
||||
"With CHURN_LIMIT_QUOTIENT=32, can't change validator balance without changing churn_limit",
|
||||
)
|
||||
def test_exit_with_balance_equal_to_churn_limit(spec, state):
|
||||
state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH
|
||||
current_epoch = spec.get_current_epoch(state)
|
||||
churn_limit = spec.get_activation_exit_churn_limit(state)
|
||||
validator_index = spec.get_active_validator_indices(state, current_epoch)[0]
|
||||
# Set 0th validator effective balance to churn_limit
|
||||
state.validators[validator_index].effective_balance = churn_limit
|
||||
|
||||
privkey = pubkey_to_privkey[state.validators[validator_index].pubkey]
|
||||
signed_voluntary_exit = sign_voluntary_exit(
|
||||
spec,
|
||||
state,
|
||||
spec.VoluntaryExit(epoch=current_epoch, validator_index=validator_index),
|
||||
privkey,
|
||||
)
|
||||
yield from run_voluntary_exit_processing(spec, state, signed_voluntary_exit)
|
||||
|
||||
# Validator consumes churn limit fully in the current epoch
|
||||
expected_exit_epoch = spec.compute_activation_exit_epoch(
|
||||
spec.get_current_epoch(state)
|
||||
)
|
||||
expected_withdrawable_epoch = (
|
||||
expected_exit_epoch + spec.config.MIN_VALIDATOR_WITHDRAWABILITY_DELAY
|
||||
)
|
||||
assert state.validators[validator_index].exit_epoch == expected_exit_epoch
|
||||
assert (
|
||||
state.validators[validator_index].withdrawable_epoch
|
||||
== expected_withdrawable_epoch
|
||||
)
|
||||
# Check exit_balance_to_consume
|
||||
assert state.exit_balance_to_consume == 0
|
||||
# Check earliest_exit_epoch
|
||||
assert state.earliest_exit_epoch == expected_exit_epoch
|
||||
|
||||
|
||||
@with_eip7251_and_later
|
||||
@spec_state_test
|
||||
@with_presets(
|
||||
[MAINNET],
|
||||
"With CHURN_LIMIT_QUOTIENT=32, can't change validator balance without changing churn_limit",
|
||||
)
|
||||
def test_exit_with_balance_multiple_of_churn_limit(spec, state):
|
||||
state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH
|
||||
current_epoch = spec.get_current_epoch(state)
|
||||
churn_limit = spec.get_activation_exit_churn_limit(state)
|
||||
validator_index = spec.get_active_validator_indices(state, current_epoch)[0]
|
||||
# Set validator effective balance to a multiple of churn_limit
|
||||
epochs_to_consume = 3
|
||||
state.validators[0].effective_balance = epochs_to_consume * churn_limit
|
||||
|
||||
privkey = pubkey_to_privkey[state.validators[validator_index].pubkey]
|
||||
signed_voluntary_exit = sign_voluntary_exit(
|
||||
spec,
|
||||
state,
|
||||
spec.VoluntaryExit(epoch=current_epoch, validator_index=validator_index),
|
||||
privkey,
|
||||
)
|
||||
yield from run_voluntary_exit_processing(spec, state, signed_voluntary_exit)
|
||||
|
||||
# Validator consumes churn limit fully in the next 3 epochs (current included)
|
||||
expected_exit_epoch = (
|
||||
spec.compute_activation_exit_epoch(spec.get_current_epoch(state))
|
||||
+ epochs_to_consume
|
||||
)
|
||||
expected_withdrawable_epoch = (
|
||||
expected_exit_epoch + spec.config.MIN_VALIDATOR_WITHDRAWABILITY_DELAY
|
||||
)
|
||||
assert state.validators[validator_index].exit_epoch == expected_exit_epoch
|
||||
assert (
|
||||
state.validators[validator_index].withdrawable_epoch
|
||||
== expected_withdrawable_epoch
|
||||
)
|
||||
# Check exit_balance_to_consume
|
||||
assert state.exit_balance_to_consume == churn_limit
|
||||
# Check earliest_exit_epoch
|
||||
assert state.earliest_exit_epoch == expected_exit_epoch
|
||||
|
||||
|
||||
@with_eip7251_and_later
|
||||
@spec_state_test
|
||||
@with_presets(
|
||||
[MAINNET],
|
||||
"With CHURN_LIMIT_QUOTIENT=32, can't change validator balance without changing churn_limit",
|
||||
)
|
||||
def test_exit_existing_churn_and_churn_limit_balance(spec, state):
|
||||
state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH
|
||||
current_epoch = spec.get_current_epoch(state)
|
||||
churn_limit = spec.get_activation_exit_churn_limit(state)
|
||||
validator_index = spec.get_active_validator_indices(state, current_epoch)[0]
|
||||
|
||||
# set exit epoch to the first available one and set exit balance to consume to full churn limit
|
||||
earliest_exit_epoch = spec.compute_activation_exit_epoch(current_epoch)
|
||||
state.earliest_exit_epoch = earliest_exit_epoch
|
||||
state.exit_balance_to_consume = churn_limit
|
||||
# consume some churn in exit epoch
|
||||
existing_churn = spec.EFFECTIVE_BALANCE_INCREMENT
|
||||
state.exit_balance_to_consume -= existing_churn
|
||||
# Set validator effective balance to the churn limit
|
||||
state.validators[validator_index].effective_balance = churn_limit
|
||||
|
||||
privkey = pubkey_to_privkey[state.validators[validator_index].pubkey]
|
||||
signed_voluntary_exit = sign_voluntary_exit(
|
||||
spec,
|
||||
state,
|
||||
spec.VoluntaryExit(epoch=current_epoch, validator_index=validator_index),
|
||||
privkey,
|
||||
)
|
||||
yield from run_voluntary_exit_processing(spec, state, signed_voluntary_exit)
|
||||
|
||||
expected_exit_epoch = earliest_exit_epoch + 1
|
||||
expected_withdrawable_epoch = (
|
||||
expected_exit_epoch + spec.config.MIN_VALIDATOR_WITHDRAWABILITY_DELAY
|
||||
)
|
||||
# Check exit epoch
|
||||
assert state.validators[validator_index].exit_epoch == expected_exit_epoch
|
||||
assert (
|
||||
state.validators[validator_index].withdrawable_epoch
|
||||
== expected_withdrawable_epoch
|
||||
)
|
||||
# Check balance consumed in exit epoch is the remainder 1 ETH
|
||||
assert state.exit_balance_to_consume == churn_limit - existing_churn
|
||||
# check earliest exit epoch
|
||||
assert state.earliest_exit_epoch == expected_exit_epoch
|
||||
|
||||
|
||||
@with_eip7251_and_later
|
||||
@spec_state_test
|
||||
@with_presets(
|
||||
[MAINNET],
|
||||
"With CHURN_LIMIT_QUOTIENT=32, can't change validator balance without changing churn_limit",
|
||||
)
|
||||
def test_exit_existing_churn_and_balance_multiple_of_churn_limit(spec, state):
|
||||
state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH
|
||||
current_epoch = spec.get_current_epoch(state)
|
||||
churn_limit = spec.get_activation_exit_churn_limit(state)
|
||||
validator_index = spec.get_active_validator_indices(state, current_epoch)[0]
|
||||
|
||||
# set exit epoch to the first available one and set exit balance to consume to full churn limit
|
||||
earliest_exit_epoch = spec.compute_activation_exit_epoch(current_epoch)
|
||||
state.earliest_exit_epoch = earliest_exit_epoch
|
||||
state.exit_balance_to_consume = churn_limit
|
||||
# consume some churn in exit epoch
|
||||
existing_churn = spec.EFFECTIVE_BALANCE_INCREMENT
|
||||
state.exit_balance_to_consume -= existing_churn
|
||||
|
||||
# Set validator effective balance to a multiple of churn_limit
|
||||
epochs_to_consume = 3
|
||||
state.validators[validator_index].effective_balance = (
|
||||
epochs_to_consume * churn_limit
|
||||
)
|
||||
|
||||
privkey = pubkey_to_privkey[state.validators[validator_index].pubkey]
|
||||
signed_voluntary_exit = sign_voluntary_exit(
|
||||
spec,
|
||||
state,
|
||||
spec.VoluntaryExit(epoch=current_epoch, validator_index=validator_index),
|
||||
privkey,
|
||||
)
|
||||
yield from run_voluntary_exit_processing(spec, state, signed_voluntary_exit)
|
||||
|
||||
# Validator fully consumes epochs_to_consume and gets into the next one
|
||||
expected_exit_epoch = earliest_exit_epoch + epochs_to_consume
|
||||
expected_withdrawable_epoch = (
|
||||
expected_exit_epoch + spec.config.MIN_VALIDATOR_WITHDRAWABILITY_DELAY
|
||||
)
|
||||
assert state.validators[validator_index].exit_epoch == expected_exit_epoch
|
||||
assert (
|
||||
state.validators[validator_index].withdrawable_epoch
|
||||
== expected_withdrawable_epoch
|
||||
)
|
||||
# Check exit_balance_to_consume
|
||||
assert state.exit_balance_to_consume == churn_limit - existing_churn
|
||||
# Check earliest_exit_epoch
|
||||
assert state.earliest_exit_epoch == expected_exit_epoch
|
||||
|
||||
|
||||
@with_eip7251_and_later
|
||||
@spec_state_test
|
||||
def test_invalid_validator_has_pending_withdrawal(spec, state):
|
||||
# move state forward SHARD_COMMITTEE_PERIOD epochs to allow for exit
|
||||
state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH
|
||||
|
||||
current_epoch = spec.get_current_epoch(state)
|
||||
validator_index = spec.get_active_validator_indices(state, current_epoch)[0]
|
||||
privkey = pubkey_to_privkey[state.validators[validator_index].pubkey]
|
||||
|
||||
voluntary_exit = spec.VoluntaryExit(
|
||||
epoch=current_epoch,
|
||||
validator_index=validator_index,
|
||||
)
|
||||
signed_voluntary_exit = sign_voluntary_exit(spec, state, voluntary_exit, privkey)
|
||||
|
||||
state.pending_partial_withdrawals.append(
|
||||
spec.PendingPartialWithdrawal(
|
||||
index=validator_index,
|
||||
amount=1,
|
||||
withdrawable_epoch=spec.compute_activation_exit_epoch(current_epoch),
|
||||
)
|
||||
)
|
||||
|
||||
yield from run_voluntary_exit_processing(
|
||||
spec, state, signed_voluntary_exit, valid=False
|
||||
)
|
@ -1,441 +0,0 @@
|
||||
from eth2spec.test.helpers.constants import (MINIMAL, MAINNET)
|
||||
from eth2spec.test.context import (
|
||||
spec_state_test,
|
||||
with_eip7251_and_later,
|
||||
with_presets,
|
||||
always_bls,
|
||||
spec_test, single_phase,
|
||||
with_custom_state,
|
||||
scaled_churn_balances_min_churn_limit,
|
||||
)
|
||||
from eth2spec.test.helpers.keys import pubkey_to_privkey
|
||||
from eth2spec.test.helpers.voluntary_exits import (
|
||||
run_voluntary_exit_processing,
|
||||
sign_voluntary_exit,
|
||||
)
|
||||
# ********************
|
||||
# * EXIT QUEUE TESTS *
|
||||
# ********************
|
||||
|
||||
|
||||
@with_eip7251_and_later
|
||||
@spec_state_test
|
||||
def test_min_balance_exit(spec, state):
|
||||
# This state has 64 validators each with 32 ETH
|
||||
expected_exit_epoch = spec.compute_activation_exit_epoch(spec.get_current_epoch(state))
|
||||
churn_limit = spec.get_activation_exit_churn_limit(state)
|
||||
# Set the balance to consume equal to churn limit
|
||||
state.exit_balance_to_consume = churn_limit
|
||||
|
||||
yield "pre", state
|
||||
# Exit validators, all which fit in the churn limit
|
||||
spec.initiate_validator_exit(state, 0)
|
||||
yield "post", state
|
||||
|
||||
# Check exit queue churn is set
|
||||
assert state.exit_balance_to_consume == churn_limit - spec.MIN_ACTIVATION_BALANCE
|
||||
# Check exit epoch
|
||||
assert state.validators[0].exit_epoch == expected_exit_epoch
|
||||
|
||||
|
||||
@with_eip7251_and_later
|
||||
@spec_state_test
|
||||
def test_min_balance_exits_up_to_churn(spec, state):
|
||||
# This state has 64 validators each with 32 ETH
|
||||
single_validator_balance = spec.MIN_ACTIVATION_BALANCE
|
||||
expected_exit_epoch = spec.compute_activation_exit_epoch(spec.get_current_epoch(state))
|
||||
churn_limit = spec.get_activation_exit_churn_limit(state)
|
||||
# Set the balance to consume equal to churn limit
|
||||
state.exit_balance_to_consume = churn_limit
|
||||
|
||||
yield "pre", state
|
||||
# Exit validators, all which fit in the churn limit
|
||||
for i in range(churn_limit // spec.MIN_ACTIVATION_BALANCE):
|
||||
validator_index = i
|
||||
spec.initiate_validator_exit(state, validator_index)
|
||||
yield f"post{i}", state
|
||||
# Check exit queue churn is set
|
||||
assert state.exit_balance_to_consume == churn_limit - single_validator_balance * (i + 1)
|
||||
# Check exit epoch
|
||||
assert state.validators[validator_index].exit_epoch == expected_exit_epoch
|
||||
yield "post", state
|
||||
|
||||
|
||||
@with_eip7251_and_later
|
||||
@spec_state_test
|
||||
def test_min_balance_exits_above_churn(spec, state):
|
||||
# This state has 64 validators each with 32 ETH
|
||||
single_validator_balance = spec.MIN_ACTIVATION_BALANCE
|
||||
expected_exit_epoch = spec.compute_activation_exit_epoch(spec.get_current_epoch(state))
|
||||
churn_limit = spec.get_activation_exit_churn_limit(state)
|
||||
# Set the balance to consume equal to churn limit
|
||||
state.exit_balance_to_consume = churn_limit
|
||||
|
||||
yield "pre", state
|
||||
# Exit validators, all which fit in the churn limit
|
||||
for i in range(churn_limit // spec.MIN_ACTIVATION_BALANCE):
|
||||
validator_index = i
|
||||
spec.initiate_validator_exit(state, validator_index)
|
||||
# Check exit queue churn is set
|
||||
assert state.exit_balance_to_consume == churn_limit - single_validator_balance * (i + 1)
|
||||
# Check exit epoch
|
||||
assert state.validators[validator_index].exit_epoch == expected_exit_epoch
|
||||
|
||||
# Exit balance has been fully consumed
|
||||
assert state.exit_balance_to_consume == 0
|
||||
|
||||
# Exit an additional validator, doesn't fit in the churn limit, so exit
|
||||
# epoch is incremented
|
||||
validator_index = churn_limit // spec.MIN_ACTIVATION_BALANCE
|
||||
spec.initiate_validator_exit(state, validator_index)
|
||||
|
||||
yield "post", state
|
||||
# Check exit epoch
|
||||
assert state.validators[validator_index].exit_epoch == expected_exit_epoch + 1
|
||||
# Check exit balance to consume is set
|
||||
assert state.exit_balance_to_consume == churn_limit - single_validator_balance
|
||||
|
||||
|
||||
# @with_eip7251_and_later
|
||||
# @spec_state_test
|
||||
# def test_exit_balance_to_consume_large_validator(spec, state):
|
||||
# # Set 0th validator effective balance to 2048 ETH
|
||||
# state.validators[0].effective_balance = spec.MAX_EFFECTIVE_BALANCE_EIP7251
|
||||
# churn_limit = spec.get_validator_churn_limit(state)
|
||||
# expected_exit_epoch = spec.compute_activation_exit_epoch(spec.get_current_epoch(state))
|
||||
# expected_exit_epoch += spec.MAX_EFFECTIVE_BALANCE_EIP7251 // churn_limit
|
||||
|
||||
# validator_index = 0
|
||||
# spec.initiate_validator_exit(state, validator_index)
|
||||
# # Check exit epoch
|
||||
# assert state.validators[validator_index].exit_epoch == expected_exit_epoch
|
||||
# # Check exit_balance_to_consume
|
||||
# assert state.exit_balance_to_consume == churn_limit - (spec.MAX_EFFECTIVE_BALANCE_EIP7251 % churn_limit)
|
||||
# # Check earliest_exit_epoch
|
||||
# assert state.earliest_exit_epoch == expected_exit_epoch
|
||||
|
||||
@with_eip7251_and_later
|
||||
@spec_state_test
|
||||
@with_presets([MAINNET], "With CHURN_LIMIT_QUOTIENT=32, can't change validator balance without changing churn_limit")
|
||||
def test_max_balance_exit(spec, state):
|
||||
churn_limit = spec.get_activation_exit_churn_limit(state)
|
||||
assert churn_limit == spec.MIN_ACTIVATION_BALANCE * spec.config.MIN_PER_EPOCH_CHURN_LIMIT
|
||||
|
||||
# Set 0th validator effective balance to 2048 ETH
|
||||
state.validators[0].effective_balance = spec.MAX_EFFECTIVE_BALANCE_EIP7251
|
||||
yield 'pre', state
|
||||
|
||||
expected_exit_epoch = spec.compute_activation_exit_epoch(spec.get_current_epoch(state))
|
||||
# Validator consumes exit churn for 16 epochs, exits at the 17th one
|
||||
expected_exit_epoch += (spec.MAX_EFFECTIVE_BALANCE_EIP7251 // churn_limit)
|
||||
|
||||
validator_index = 0
|
||||
spec.initiate_validator_exit(state, validator_index)
|
||||
yield 'post', state
|
||||
# Check exit epoch
|
||||
assert state.validators[validator_index].exit_epoch == expected_exit_epoch
|
||||
# Check exit_balance_to_consume
|
||||
assert state.exit_balance_to_consume == churn_limit
|
||||
# Check earliest_exit_epoch
|
||||
assert state.earliest_exit_epoch == expected_exit_epoch
|
||||
|
||||
|
||||
@with_eip7251_and_later
|
||||
@spec_state_test
|
||||
@with_presets([MAINNET], "With CHURN_LIMIT_QUOTIENT=32, can't change validator balance without changing churn_limit")
|
||||
def test_exit_with_balance_equal_to_churn_limit(spec, state):
|
||||
churn_limit = spec.get_activation_exit_churn_limit(state)
|
||||
|
||||
# Set 0th validator effective balance to churn_limit
|
||||
state.validators[0].effective_balance = churn_limit
|
||||
yield 'pre', state
|
||||
|
||||
validator_index = 0
|
||||
spec.initiate_validator_exit(state, validator_index)
|
||||
|
||||
yield 'post', state
|
||||
# Validator consumes churn limit fully in the current epoch
|
||||
assert (state.validators[validator_index].exit_epoch ==
|
||||
spec.compute_activation_exit_epoch(spec.get_current_epoch(state)))
|
||||
# Check exit_balance_to_consume
|
||||
assert state.exit_balance_to_consume == 0
|
||||
# Check earliest_exit_epoch
|
||||
assert state.earliest_exit_epoch == state.validators[validator_index].exit_epoch
|
||||
|
||||
|
||||
@with_eip7251_and_later
|
||||
@spec_state_test
|
||||
@with_presets([MAINNET], "With CHURN_LIMIT_QUOTIENT=32, can't change validator balance without changing churn_limit")
|
||||
def test_exit_churn_limit_balance_existing_churn_(spec, state):
|
||||
cl = spec.get_activation_exit_churn_limit(state)
|
||||
|
||||
# set exit epoch to the first available one and set exit balance to consume to full churn limit
|
||||
state.earliest_exit_epoch = spec.compute_activation_exit_epoch(spec.get_current_epoch(state))
|
||||
state.exit_balance_to_consume = cl
|
||||
# consume some churn in exit epoch
|
||||
state.exit_balance_to_consume -= 1000000000
|
||||
|
||||
# Set 0th validator effective balance to the churn limit
|
||||
state.validators[0].effective_balance = cl
|
||||
|
||||
yield 'pre', state
|
||||
|
||||
# The existing 1 ETH churn will push an extra epoch
|
||||
expected_exit_epoch = state.earliest_exit_epoch + 1
|
||||
|
||||
yield 'post', state
|
||||
validator_index = 0
|
||||
spec.initiate_validator_exit(state, validator_index)
|
||||
# Check exit epoch
|
||||
assert state.validators[validator_index].exit_epoch == expected_exit_epoch
|
||||
# Check balance consumed in exit epoch is the remainder 1 ETH
|
||||
assert state.exit_balance_to_consume == cl - 1000000000
|
||||
# check earliest exit epoch
|
||||
assert expected_exit_epoch == state.earliest_exit_epoch
|
||||
|
||||
|
||||
@with_eip7251_and_later
|
||||
@spec_state_test
|
||||
@with_presets([MAINNET], "With CHURN_LIMIT_QUOTIENT=32, can't change validator balance without changing churn_limit")
|
||||
def test_multi_epoch_exit_existing_churn(spec, state):
|
||||
cl = spec.get_activation_exit_churn_limit(state)
|
||||
|
||||
# set exit epoch to the first available one and set exit balance to consume to full churn limit
|
||||
state.earliest_exit_epoch = spec.compute_activation_exit_epoch(spec.get_current_epoch(state))
|
||||
state.exit_balance_to_consume = cl
|
||||
# consume some churn in exit epoch
|
||||
state.exit_balance_to_consume -= 1000000000
|
||||
|
||||
# Set 0th validator effective balance to 2x the churn limit
|
||||
state.validators[0].effective_balance = 2 * cl
|
||||
|
||||
yield 'pre', state
|
||||
# Two extra epochs will be necessary
|
||||
expected_exit_epoch = spec.compute_activation_exit_epoch(spec.get_current_epoch(state)) + 2
|
||||
|
||||
validator_index = 0
|
||||
spec.initiate_validator_exit(state, validator_index)
|
||||
yield 'post', state
|
||||
# Check exit epoch
|
||||
assert state.validators[validator_index].exit_epoch == expected_exit_epoch
|
||||
# Check balance consumed in exit epoch is the remainder 1 ETH
|
||||
assert state.exit_balance_to_consume == cl - 1000000000
|
||||
# check earliest exit epoch
|
||||
assert expected_exit_epoch == state.earliest_exit_epoch
|
||||
|
||||
|
||||
# Repurposed from phase0 voluntary exit tests, should disable the phase0 ones
|
||||
|
||||
def run_test_success_exit_queue(spec, state):
|
||||
# move state forward SHARD_COMMITTEE_PERIOD epochs to allow for exit
|
||||
state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH
|
||||
|
||||
current_epoch = spec.get_current_epoch(state)
|
||||
churn_limit = spec.get_activation_exit_churn_limit(state)
|
||||
# exit `MAX_EXITS_PER_EPOCH`
|
||||
max_exits = churn_limit // spec.MIN_ACTIVATION_BALANCE
|
||||
initial_indices = spec.get_active_validator_indices(state, current_epoch)[:max_exits]
|
||||
|
||||
# Prepare a bunch of exits, based on the current state
|
||||
exit_queue = []
|
||||
for index in initial_indices:
|
||||
privkey = pubkey_to_privkey[state.validators[index].pubkey]
|
||||
|
||||
signed_voluntary_exit = sign_voluntary_exit(
|
||||
spec, state, spec.VoluntaryExit(epoch=current_epoch, validator_index=index), privkey)
|
||||
|
||||
exit_queue.append(signed_voluntary_exit)
|
||||
|
||||
# Now run all the exits
|
||||
for voluntary_exit in exit_queue:
|
||||
# the function yields data, but we are just interested in running it here, ignore yields.
|
||||
for _ in run_voluntary_exit_processing(spec, state, voluntary_exit):
|
||||
continue
|
||||
|
||||
# exit an additional validator
|
||||
validator_index = spec.get_active_validator_indices(state, current_epoch)[-1]
|
||||
privkey = pubkey_to_privkey[state.validators[validator_index].pubkey]
|
||||
|
||||
signed_voluntary_exit = sign_voluntary_exit(
|
||||
spec, state, spec.VoluntaryExit(epoch=current_epoch, validator_index=validator_index), privkey)
|
||||
|
||||
# This is the interesting part of the test: on a pre-state with a full exit queue,
|
||||
# when processing an additional exit, it results in an exit in a later epoch
|
||||
yield from run_voluntary_exit_processing(spec, state, signed_voluntary_exit)
|
||||
|
||||
for index in initial_indices:
|
||||
assert (
|
||||
state.validators[validator_index].exit_epoch ==
|
||||
state.validators[index].exit_epoch + 1
|
||||
)
|
||||
assert state.earliest_exit_epoch == state.validators[validator_index].exit_epoch
|
||||
consumed_churn = spec.MIN_ACTIVATION_BALANCE * (max_exits + 1)
|
||||
assert state.exit_balance_to_consume == churn_limit - (consumed_churn % churn_limit)
|
||||
|
||||
|
||||
@with_eip7251_and_later
|
||||
@spec_state_test
|
||||
def test_success_exit_queue__min_churn(spec, state):
|
||||
yield from run_test_success_exit_queue(spec, state)
|
||||
|
||||
|
||||
@with_eip7251_and_later
|
||||
@with_presets([MINIMAL],
|
||||
reason="mainnet config leads to larger validator set than limit of public/private keys pre-generated")
|
||||
@spec_test
|
||||
@with_custom_state(balances_fn=scaled_churn_balances_min_churn_limit,
|
||||
threshold_fn=lambda spec: spec.config.EJECTION_BALANCE)
|
||||
@single_phase
|
||||
def test_success_exit_queue__scaled_churn(spec, state):
|
||||
churn_limit = spec.get_activation_exit_churn_limit(state)
|
||||
assert churn_limit > spec.config.MIN_PER_EPOCH_CHURN_LIMIT
|
||||
yield from run_test_success_exit_queue(spec, state)
|
||||
|
||||
|
||||
# After here no modifications were made, can just leave them in phase0 as is
|
||||
|
||||
@with_eip7251_and_later
|
||||
@spec_state_test
|
||||
def test_basic(spec, state):
|
||||
state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH
|
||||
current_epoch = spec.get_current_epoch(state)
|
||||
validator_index = spec.get_active_validator_indices(state, current_epoch)[0]
|
||||
privkey = pubkey_to_privkey[state.validators[validator_index].pubkey]
|
||||
|
||||
signed_voluntary_exit = sign_voluntary_exit(
|
||||
spec, state, spec.VoluntaryExit(epoch=current_epoch, validator_index=validator_index), privkey)
|
||||
|
||||
yield from run_voluntary_exit_processing(spec, state, signed_voluntary_exit)
|
||||
|
||||
assert state.validators[validator_index].exit_epoch == spec.compute_activation_exit_epoch(current_epoch)
|
||||
|
||||
|
||||
@with_eip7251_and_later
|
||||
@spec_state_test
|
||||
@always_bls
|
||||
def test_invalid_incorrect_signature(spec, state):
|
||||
# move state forward SHARD_COMMITTEE_PERIOD epochs to allow for exit
|
||||
state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH
|
||||
|
||||
current_epoch = spec.get_current_epoch(state)
|
||||
validator_index = spec.get_active_validator_indices(state, current_epoch)[0]
|
||||
|
||||
voluntary_exit = spec.VoluntaryExit(
|
||||
epoch=current_epoch,
|
||||
validator_index=validator_index,
|
||||
)
|
||||
signed_voluntary_exit = sign_voluntary_exit(spec, state, voluntary_exit, 12345)
|
||||
|
||||
yield from run_voluntary_exit_processing(spec, state, signed_voluntary_exit, valid=False)
|
||||
|
||||
|
||||
@with_eip7251_and_later
|
||||
@spec_state_test
|
||||
def test_default_exit_epoch_subsequent_exit(spec, state):
|
||||
# move state forward SHARD_COMMITTEE_PERIOD epochs to allow for exit
|
||||
state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH
|
||||
|
||||
current_epoch = spec.get_current_epoch(state)
|
||||
validator_index = spec.get_active_validator_indices(state, current_epoch)[0]
|
||||
privkey = pubkey_to_privkey[state.validators[validator_index].pubkey]
|
||||
|
||||
signed_voluntary_exit = sign_voluntary_exit(
|
||||
spec, state, spec.VoluntaryExit(epoch=current_epoch, validator_index=validator_index), privkey)
|
||||
|
||||
# Exit one validator prior to this new one
|
||||
exited_index = spec.get_active_validator_indices(state, current_epoch)[-1]
|
||||
state.validators[exited_index].exit_epoch = current_epoch - 1
|
||||
|
||||
yield from run_voluntary_exit_processing(spec, state, signed_voluntary_exit)
|
||||
|
||||
assert state.validators[validator_index].exit_epoch == spec.compute_activation_exit_epoch(current_epoch)
|
||||
|
||||
|
||||
@with_eip7251_and_later
|
||||
@spec_state_test
|
||||
def test_invalid_validator_exit_in_future(spec, state):
|
||||
# move state forward SHARD_COMMITTEE_PERIOD epochs to allow for exit
|
||||
state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH
|
||||
|
||||
current_epoch = spec.get_current_epoch(state)
|
||||
validator_index = spec.get_active_validator_indices(state, current_epoch)[0]
|
||||
privkey = pubkey_to_privkey[state.validators[validator_index].pubkey]
|
||||
|
||||
voluntary_exit = spec.VoluntaryExit(
|
||||
epoch=current_epoch + 1,
|
||||
validator_index=validator_index,
|
||||
)
|
||||
signed_voluntary_exit = sign_voluntary_exit(spec, state, voluntary_exit, privkey)
|
||||
|
||||
yield from run_voluntary_exit_processing(spec, state, signed_voluntary_exit, valid=False)
|
||||
|
||||
|
||||
@with_eip7251_and_later
|
||||
@spec_state_test
|
||||
def test_invalid_validator_incorrect_validator_index(spec, state):
|
||||
# move state forward SHARD_COMMITTEE_PERIOD epochs to allow for exit
|
||||
state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH
|
||||
|
||||
current_epoch = spec.get_current_epoch(state)
|
||||
validator_index = spec.get_active_validator_indices(state, current_epoch)[0]
|
||||
privkey = pubkey_to_privkey[state.validators[validator_index].pubkey]
|
||||
|
||||
voluntary_exit = spec.VoluntaryExit(
|
||||
epoch=current_epoch,
|
||||
validator_index=len(state.validators),
|
||||
)
|
||||
signed_voluntary_exit = sign_voluntary_exit(spec, state, voluntary_exit, privkey)
|
||||
|
||||
yield from run_voluntary_exit_processing(spec, state, signed_voluntary_exit, valid=False)
|
||||
|
||||
|
||||
@with_eip7251_and_later
|
||||
@spec_state_test
|
||||
def test_invalid_validator_not_active(spec, state):
|
||||
current_epoch = spec.get_current_epoch(state)
|
||||
validator_index = spec.get_active_validator_indices(state, current_epoch)[0]
|
||||
privkey = pubkey_to_privkey[state.validators[validator_index].pubkey]
|
||||
|
||||
state.validators[validator_index].activation_epoch = spec.FAR_FUTURE_EPOCH
|
||||
|
||||
signed_voluntary_exit = sign_voluntary_exit(
|
||||
spec, state, spec.VoluntaryExit(epoch=current_epoch, validator_index=validator_index), privkey)
|
||||
|
||||
yield from run_voluntary_exit_processing(spec, state, signed_voluntary_exit, valid=False)
|
||||
|
||||
|
||||
@with_eip7251_and_later
|
||||
@spec_state_test
|
||||
def test_invalid_validator_already_exited(spec, state):
|
||||
# move state forward SHARD_COMMITTEE_PERIOD epochs to allow validator able to exit
|
||||
state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH
|
||||
|
||||
current_epoch = spec.get_current_epoch(state)
|
||||
validator_index = spec.get_active_validator_indices(state, current_epoch)[0]
|
||||
privkey = pubkey_to_privkey[state.validators[validator_index].pubkey]
|
||||
|
||||
# but validator already has exited
|
||||
state.validators[validator_index].exit_epoch = current_epoch + 2
|
||||
|
||||
signed_voluntary_exit = sign_voluntary_exit(
|
||||
spec, state, spec.VoluntaryExit(epoch=current_epoch, validator_index=validator_index), privkey)
|
||||
|
||||
yield from run_voluntary_exit_processing(spec, state, signed_voluntary_exit, valid=False)
|
||||
|
||||
|
||||
@with_eip7251_and_later
|
||||
@spec_state_test
|
||||
def test_invalid_validator_not_active_long_enough(spec, state):
|
||||
current_epoch = spec.get_current_epoch(state)
|
||||
validator_index = spec.get_active_validator_indices(state, current_epoch)[0]
|
||||
privkey = pubkey_to_privkey[state.validators[validator_index].pubkey]
|
||||
|
||||
signed_voluntary_exit = sign_voluntary_exit(
|
||||
spec, state, spec.VoluntaryExit(epoch=current_epoch, validator_index=validator_index), privkey)
|
||||
|
||||
assert (
|
||||
current_epoch - state.validators[validator_index].activation_epoch <
|
||||
spec.config.SHARD_COMMITTEE_PERIOD
|
||||
)
|
||||
|
||||
yield from run_voluntary_exit_processing(spec, state, signed_voluntary_exit, valid=False)
|
@ -0,0 +1,12 @@
|
||||
from eth2spec.test.context import spec_state_test, with_eip7251_and_later
|
||||
from eth2spec.test.phase0.epoch_processing.test_process_effective_balance_updates import (
|
||||
run_test_effective_balance_hysteresis,
|
||||
)
|
||||
|
||||
|
||||
@with_eip7251_and_later
|
||||
@spec_state_test
|
||||
def test_effective_balance_hysteresis_with_compounding_credentials(spec, state):
|
||||
run_test_effective_balance_hysteresis(
|
||||
spec, state, with_compounding_credentials=True
|
||||
)
|
@ -10,9 +10,13 @@ from eth2spec.test.context import (
|
||||
def test_pending_deposit_min_activation_balance(spec, state):
|
||||
index = 0
|
||||
amount = spec.MIN_ACTIVATION_BALANCE
|
||||
state.pending_balance_deposits.append(spec.PendingBalanceDeposit(index=index, amount=amount))
|
||||
state.pending_balance_deposits.append(
|
||||
spec.PendingBalanceDeposit(index=index, amount=amount)
|
||||
)
|
||||
pre_balance = state.balances[index]
|
||||
yield from run_epoch_processing_with(spec, state, 'process_pending_balance_deposits')
|
||||
yield from run_epoch_processing_with(
|
||||
spec, state, "process_pending_balance_deposits"
|
||||
)
|
||||
assert state.balances[index] == pre_balance + amount
|
||||
# No leftover deposit balance to consume when there are no deposits left to process
|
||||
assert state.deposit_balance_to_consume == 0
|
||||
@ -24,9 +28,13 @@ def test_pending_deposit_min_activation_balance(spec, state):
|
||||
def test_pending_deposit_balance_equal_churn(spec, state):
|
||||
index = 0
|
||||
amount = spec.get_activation_exit_churn_limit(state)
|
||||
state.pending_balance_deposits.append(spec.PendingBalanceDeposit(index=index, amount=amount))
|
||||
state.pending_balance_deposits.append(
|
||||
spec.PendingBalanceDeposit(index=index, amount=amount)
|
||||
)
|
||||
pre_balance = state.balances[index]
|
||||
yield from run_epoch_processing_with(spec, state, 'process_pending_balance_deposits')
|
||||
yield from run_epoch_processing_with(
|
||||
spec, state, "process_pending_balance_deposits"
|
||||
)
|
||||
assert state.balances[index] == pre_balance + amount
|
||||
assert state.deposit_balance_to_consume == 0
|
||||
assert state.pending_balance_deposits == []
|
||||
@ -37,26 +45,38 @@ def test_pending_deposit_balance_equal_churn(spec, state):
|
||||
def test_pending_deposit_balance_above_churn(spec, state):
|
||||
index = 0
|
||||
amount = spec.get_activation_exit_churn_limit(state) + 1
|
||||
state.pending_balance_deposits.append(spec.PendingBalanceDeposit(index=index, amount=amount))
|
||||
state.pending_balance_deposits.append(
|
||||
spec.PendingBalanceDeposit(index=index, amount=amount)
|
||||
)
|
||||
pre_balance = state.balances[index]
|
||||
yield from run_epoch_processing_with(spec, state, 'process_pending_balance_deposits')
|
||||
yield from run_epoch_processing_with(
|
||||
spec, state, "process_pending_balance_deposits"
|
||||
)
|
||||
# deposit was above churn, balance hasn't changed
|
||||
assert state.balances[index] == pre_balance
|
||||
# deposit balance to consume is the full churn limit
|
||||
assert state.deposit_balance_to_consume == spec.get_activation_exit_churn_limit(state)
|
||||
assert state.deposit_balance_to_consume == spec.get_activation_exit_churn_limit(
|
||||
state
|
||||
)
|
||||
# deposit is still in the queue
|
||||
assert state.pending_balance_deposits == [spec.PendingBalanceDeposit(index=index, amount=amount)]
|
||||
assert state.pending_balance_deposits == [
|
||||
spec.PendingBalanceDeposit(index=index, amount=amount)
|
||||
]
|
||||
|
||||
|
||||
@with_eip7251_and_later
|
||||
@spec_state_test
|
||||
def test_pending_deposit_preexisting_churn(spec, state):
|
||||
index = 0
|
||||
amount = 10 ** 9 + 1
|
||||
amount = 10**9 + 1
|
||||
state.deposit_balance_to_consume = 2 * amount
|
||||
state.pending_balance_deposits.append(spec.PendingBalanceDeposit(index=index, amount=amount))
|
||||
state.pending_balance_deposits.append(
|
||||
spec.PendingBalanceDeposit(index=index, amount=amount)
|
||||
)
|
||||
pre_balance = state.balances[index]
|
||||
yield from run_epoch_processing_with(spec, state, 'process_pending_balance_deposits')
|
||||
yield from run_epoch_processing_with(
|
||||
spec, state, "process_pending_balance_deposits"
|
||||
)
|
||||
# balance was deposited correctly
|
||||
assert state.balances[index] == pre_balance + amount
|
||||
# No leftover deposit balance to consume when there are no deposits left to process
|
||||
@ -69,10 +89,16 @@ def test_pending_deposit_preexisting_churn(spec, state):
|
||||
@spec_state_test
|
||||
def test_multiple_pending_deposits_below_churn(spec, state):
|
||||
amount = 10**9
|
||||
state.pending_balance_deposits.append(spec.PendingBalanceDeposit(index=0, amount=amount))
|
||||
state.pending_balance_deposits.append(spec.PendingBalanceDeposit(index=1, amount=amount))
|
||||
state.pending_balance_deposits.append(
|
||||
spec.PendingBalanceDeposit(index=0, amount=amount)
|
||||
)
|
||||
state.pending_balance_deposits.append(
|
||||
spec.PendingBalanceDeposit(index=1, amount=amount)
|
||||
)
|
||||
pre_balances = state.balances
|
||||
yield from run_epoch_processing_with(spec, state, 'process_pending_balance_deposits')
|
||||
yield from run_epoch_processing_with(
|
||||
spec, state, "process_pending_balance_deposits"
|
||||
)
|
||||
for i in [0, 1]:
|
||||
assert state.balances[i] == pre_balances[i] + amount
|
||||
# No leftover deposit balance to consume when there are no deposits left to process
|
||||
@ -86,14 +112,23 @@ def test_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_balance_deposits.append(spec.PendingBalanceDeposit(index=i, amount=amount))
|
||||
state.pending_balance_deposits.append(
|
||||
spec.PendingBalanceDeposit(index=i, amount=amount)
|
||||
)
|
||||
pre_balances = state.balances
|
||||
yield from run_epoch_processing_with(spec, state, 'process_pending_balance_deposits')
|
||||
yield from run_epoch_processing_with(
|
||||
spec, state, "process_pending_balance_deposits"
|
||||
)
|
||||
# First two deposits are processed, third is not because above churn
|
||||
for i in [0, 1]:
|
||||
assert state.balances[i] == pre_balances[i] + amount
|
||||
assert state.balances[2] == pre_balances[2]
|
||||
# Only first two subtract from the deposit balance to consume
|
||||
assert state.deposit_balance_to_consume == spec.get_activation_exit_churn_limit(state) - 2 * amount
|
||||
assert (
|
||||
state.deposit_balance_to_consume
|
||||
== spec.get_activation_exit_churn_limit(state) - 2 * amount
|
||||
)
|
||||
# third deposit is still in the queue
|
||||
assert state.pending_balance_deposits == [spec.PendingBalanceDeposit(index=2, amount=amount)]
|
||||
assert state.pending_balance_deposits == [
|
||||
spec.PendingBalanceDeposit(index=2, amount=amount)
|
||||
]
|
||||
|
@ -16,13 +16,66 @@ def test_basic_pending_consolidation(spec, 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.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 = spec.get_current_epoch(state)
|
||||
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
|
||||
|
||||
yield from run_epoch_processing_with(spec, state, "process_pending_consolidations")
|
||||
|
||||
# Pending consolidation was successfully processed
|
||||
assert (
|
||||
state.validators[target_index].withdrawal_credentials[:1]
|
||||
== spec.COMPOUNDING_WITHDRAWAL_PREFIX
|
||||
)
|
||||
assert state.balances[target_index] == 2 * spec.MIN_ACTIVATION_BALANCE
|
||||
assert state.balances[source_index] == 0
|
||||
assert state.pending_consolidations == []
|
||||
|
||||
|
||||
@with_eip7251_and_later
|
||||
@spec_state_test
|
||||
def test_consolidation_not_yet_withdrawable_validator(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 the target to eth1 withdrawal credentials
|
||||
eth1_withdrawal_credential = (
|
||||
spec.ETH1_ADDRESS_WITHDRAWAL_PREFIX + b"\x00" * 11 + b"\x11" * 20
|
||||
)
|
||||
state.validators[target_index].withdrawal_credentials = eth1_withdrawal_credential
|
||||
# Initiate exit of source validator
|
||||
spec.initiate_validator_exit(state, source_index)
|
||||
|
||||
pre_pending_consolidations = state.pending_consolidations.copy()
|
||||
pre_balances = state.balances.copy()
|
||||
pre_target_withdrawal_credential = state.validators[
|
||||
target_index
|
||||
].withdrawal_credentials[:1]
|
||||
|
||||
yield from run_epoch_processing_with(spec, state, "process_pending_consolidations")
|
||||
|
||||
# Pending consolidation is not processed
|
||||
# Balances are unchanged
|
||||
assert state.balances[source_index] == pre_balances[0]
|
||||
assert state.balances[target_index] == pre_balances[1]
|
||||
# Target withdrawal credential is unchanged
|
||||
assert (
|
||||
state.validators[target_index].withdrawal_credentials[:1]
|
||||
== pre_target_withdrawal_credential
|
||||
)
|
||||
# Pending consolidation is still in the queue
|
||||
assert state.pending_consolidations == pre_pending_consolidations
|
||||
|
||||
|
||||
@with_eip7251_and_later
|
||||
@ -35,12 +88,22 @@ def test_skip_consolidation_when_source_slashed(spec, state):
|
||||
target1_index = spec.get_active_validator_indices(state, current_epoch)[3]
|
||||
# append pending consolidation
|
||||
state.pending_consolidations.append(
|
||||
spec.PendingConsolidation(source_index=source0_index, target_index=target0_index)
|
||||
spec.PendingConsolidation(
|
||||
source_index=source0_index, target_index=target0_index
|
||||
)
|
||||
)
|
||||
state.pending_consolidations.append(
|
||||
spec.PendingConsolidation(source_index=source1_index, target_index=target1_index)
|
||||
spec.PendingConsolidation(
|
||||
source_index=source1_index, target_index=target1_index
|
||||
)
|
||||
)
|
||||
|
||||
eth1_withdrawal_credential = (
|
||||
spec.ETH1_ADDRESS_WITHDRAWAL_PREFIX + b"\x00" * 11 + b"\x11" * 20
|
||||
)
|
||||
state.validators[target0_index].withdrawal_credentials = eth1_withdrawal_credential
|
||||
state.validators[target1_index].withdrawal_credentials = eth1_withdrawal_credential
|
||||
|
||||
# Set withdrawable epoch of sources to current epoch to allow processing
|
||||
state.validators[source0_index].withdrawable_epoch = spec.get_current_epoch(state)
|
||||
state.validators[source1_index].withdrawable_epoch = spec.get_current_epoch(state)
|
||||
@ -52,6 +115,73 @@ def test_skip_consolidation_when_source_slashed(spec, state):
|
||||
# first pending consolidation should not be processed
|
||||
assert state.balances[target0_index] == spec.MIN_ACTIVATION_BALANCE
|
||||
assert state.balances[source0_index] == spec.MIN_ACTIVATION_BALANCE
|
||||
assert (
|
||||
state.validators[target0_index].withdrawal_credentials[:1]
|
||||
== spec.ETH1_ADDRESS_WITHDRAWAL_PREFIX
|
||||
)
|
||||
# second pending consolidation should be processed: first one is skipped and doesn't block the queue
|
||||
assert state.balances[target1_index] == 2 * spec.MIN_ACTIVATION_BALANCE
|
||||
assert state.balances[source1_index] == 0
|
||||
assert (
|
||||
state.validators[target1_index].withdrawal_credentials[:1]
|
||||
== spec.COMPOUNDING_WITHDRAWAL_PREFIX
|
||||
)
|
||||
|
||||
|
||||
@with_eip7251_and_later
|
||||
@spec_state_test
|
||||
def test_all_consolidation_cases_together(spec, state):
|
||||
current_epoch = spec.get_current_epoch(state)
|
||||
source_index = [
|
||||
spec.get_active_validator_indices(state, current_epoch)[i] for i in range(4)
|
||||
]
|
||||
target_index = [
|
||||
spec.get_active_validator_indices(state, current_epoch)[4 + i] for i in range(4)
|
||||
]
|
||||
state.pending_consolidations = [
|
||||
spec.PendingConsolidation(
|
||||
source_index=source_index[i], target_index=target_index[i]
|
||||
)
|
||||
for i in range(4)
|
||||
]
|
||||
# Set withdrawable epoch to current epoch for first and last source validators
|
||||
for i in [0, 2]:
|
||||
state.validators[source_index[i]].withdrawable_epoch = current_epoch
|
||||
# Set second source validator as slashed
|
||||
state.validators[source_index[1]].slashed = True
|
||||
# Set targets withdrawal credentials to eth1
|
||||
eth1_withdrawal_credential = (
|
||||
spec.ETH1_ADDRESS_WITHDRAWAL_PREFIX + b"\x00" * 11 + b"\x11" * 20
|
||||
)
|
||||
for i in range(4):
|
||||
state.validators[target_index[i]].withdrawal_credentials = (
|
||||
eth1_withdrawal_credential
|
||||
)
|
||||
# Initiate exit of third source validator
|
||||
spec.initiate_validator_exit(state, 2)
|
||||
|
||||
pre_balances = state.balances.copy()
|
||||
pre_target_withdrawal_prefixes = [
|
||||
state.validators[target_index[i]].withdrawal_credentials[:1]
|
||||
for i in [0, 1, 2, 3]
|
||||
]
|
||||
pre_pending_consolidations = state.pending_consolidations.copy()
|
||||
yield from run_epoch_processing_with(spec, state, "process_pending_consolidations")
|
||||
|
||||
# First consolidation is successfully processed
|
||||
assert (
|
||||
state.validators[target_index[0]].withdrawal_credentials[:1]
|
||||
== spec.COMPOUNDING_WITHDRAWAL_PREFIX
|
||||
)
|
||||
assert state.balances[target_index[0]] == 2 * spec.MIN_ACTIVATION_BALANCE
|
||||
assert state.balances[source_index[0]] == 0
|
||||
# All other consolidations are not processed
|
||||
for i in [1, 2, 3]:
|
||||
assert (
|
||||
state.validators[target_index[i]].withdrawal_credentials[:1]
|
||||
== pre_target_withdrawal_prefixes[i]
|
||||
)
|
||||
assert state.balances[source_index[i]] == pre_balances[source_index[i]]
|
||||
assert state.balances[target_index[i]] == pre_balances[target_index[i]]
|
||||
# First consolidation is processed, second is skipped, last two are left in the queue
|
||||
state.pending_consolidations = pre_pending_consolidations[2:]
|
||||
|
@ -1,7 +1,7 @@
|
||||
from random import Random
|
||||
|
||||
from eth2spec.test.context import expect_assertion_error
|
||||
from eth2spec.test.helpers.forks import is_post_altair
|
||||
from eth2spec.test.helpers.forks import is_post_altair, is_post_eip7251
|
||||
from eth2spec.test.helpers.keys import pubkeys, privkeys
|
||||
from eth2spec.test.helpers.state import get_balance
|
||||
from eth2spec.utils import bls
|
||||
@ -234,6 +234,7 @@ def run_deposit_processing(spec, state, deposit, validator_index, valid=True, ef
|
||||
"""
|
||||
pre_validator_count = len(state.validators)
|
||||
pre_balance = 0
|
||||
pre_effective_balance = 0
|
||||
is_top_up = False
|
||||
# is a top-up
|
||||
if validator_index < pre_validator_count:
|
||||
@ -241,6 +242,9 @@ def run_deposit_processing(spec, state, deposit, validator_index, valid=True, ef
|
||||
pre_balance = get_balance(state, validator_index)
|
||||
pre_effective_balance = state.validators[validator_index].effective_balance
|
||||
|
||||
if is_post_eip7251(spec):
|
||||
pre_pending_deposits = len(state.pending_balance_deposits)
|
||||
|
||||
yield 'pre', state
|
||||
yield 'deposit', deposit
|
||||
|
||||
@ -260,19 +264,30 @@ def run_deposit_processing(spec, state, deposit, validator_index, valid=True, ef
|
||||
assert get_balance(state, validator_index) == pre_balance
|
||||
else:
|
||||
if is_top_up:
|
||||
# Top-ups do not change effective balance
|
||||
assert state.validators[validator_index].effective_balance == pre_effective_balance
|
||||
# Top-ups don't add validators
|
||||
assert len(state.validators) == pre_validator_count
|
||||
assert len(state.balances) == pre_validator_count
|
||||
else:
|
||||
# new validator
|
||||
# new validator is added
|
||||
assert len(state.validators) == pre_validator_count + 1
|
||||
assert len(state.balances) == pre_validator_count + 1
|
||||
effective_balance = min(spec.MAX_EFFECTIVE_BALANCE, deposit.data.amount)
|
||||
effective_balance -= effective_balance % spec.EFFECTIVE_BALANCE_INCREMENT
|
||||
assert state.validators[validator_index].effective_balance == effective_balance
|
||||
|
||||
assert get_balance(state, validator_index) == pre_balance + deposit.data.amount
|
||||
if not is_post_eip7251(spec):
|
||||
if is_top_up:
|
||||
# Top-ups do not change effective balance
|
||||
assert state.validators[validator_index].effective_balance == pre_effective_balance
|
||||
else:
|
||||
effective_balance = min(spec.MAX_EFFECTIVE_BALANCE, deposit.data.amount)
|
||||
effective_balance -= effective_balance % spec.EFFECTIVE_BALANCE_INCREMENT
|
||||
assert state.validators[validator_index].effective_balance == effective_balance
|
||||
assert get_balance(state, validator_index) == pre_balance + deposit.data.amount
|
||||
else:
|
||||
# no balance or effective balance changes on deposit processing post eip7251
|
||||
assert get_balance(state, validator_index) == pre_balance
|
||||
assert state.validators[validator_index].effective_balance == pre_effective_balance
|
||||
# new correct balance deposit queued up
|
||||
assert len(state.pending_balance_deposits) == pre_pending_deposits + 1
|
||||
assert state.pending_balance_deposits[pre_pending_deposits].amount == deposit.data.amount
|
||||
assert state.pending_balance_deposits[pre_pending_deposits].index == validator_index
|
||||
|
||||
assert state.eth1_deposit_index == state.eth1_data.deposit_count
|
||||
|
||||
@ -390,88 +405,3 @@ def run_deposit_receipt_processing_with_specific_fork_version(
|
||||
valid=valid,
|
||||
effective=effective
|
||||
)
|
||||
|
||||
|
||||
# ********************
|
||||
# * EIP7251 *
|
||||
# ********************
|
||||
|
||||
|
||||
def run_deposit_processing_eip7251(spec, state, deposit, validator_index, valid=True, effective=True):
|
||||
"""
|
||||
Run ``process_deposit``, yielding:
|
||||
- pre-state ('pre')
|
||||
- deposit ('deposit')
|
||||
- post-state ('post').
|
||||
If ``valid == False``, run expecting ``AssertionError``
|
||||
"""
|
||||
pre_validator_count = len(state.validators)
|
||||
pre_pending_deposits = len(state.pending_balance_deposits)
|
||||
pre_balance = 0
|
||||
pre_effective_balance = 0
|
||||
is_top_up = False
|
||||
# is a top-up
|
||||
if validator_index < pre_validator_count:
|
||||
is_top_up = True
|
||||
pre_balance = get_balance(state, validator_index)
|
||||
pre_effective_balance = state.validators[validator_index].effective_balance
|
||||
|
||||
yield 'pre', state
|
||||
yield 'deposit', deposit
|
||||
|
||||
if not valid:
|
||||
expect_assertion_error(lambda: spec.process_deposit(state, deposit))
|
||||
yield 'post', None
|
||||
return
|
||||
|
||||
spec.process_deposit(state, deposit)
|
||||
|
||||
yield 'post', state
|
||||
|
||||
if not effective or not bls.KeyValidate(deposit.data.pubkey):
|
||||
assert len(state.validators) == pre_validator_count
|
||||
assert len(state.balances) == pre_validator_count
|
||||
else:
|
||||
# no balance changes on deposit processing
|
||||
assert get_balance(state, validator_index) == pre_balance
|
||||
assert state.validators[validator_index].effective_balance == pre_effective_balance
|
||||
if is_top_up:
|
||||
assert len(state.validators) == pre_validator_count
|
||||
assert len(state.balances) == pre_validator_count
|
||||
else:
|
||||
# new validator
|
||||
assert len(state.validators) == pre_validator_count + 1
|
||||
assert len(state.balances) == pre_validator_count + 1
|
||||
# new correct balance deposit has been appended
|
||||
assert len(state.pending_balance_deposits) == pre_pending_deposits + 1
|
||||
assert state.pending_balance_deposits[pre_pending_deposits].amount == deposit.data.amount
|
||||
assert state.pending_balance_deposits[pre_pending_deposits].index == validator_index
|
||||
assert state.eth1_deposit_index == state.eth1_data.deposit_count
|
||||
|
||||
|
||||
def run_deposit_processing_eip7251_with_specific_fork_version(
|
||||
spec,
|
||||
state,
|
||||
fork_version,
|
||||
valid=True,
|
||||
effective=True):
|
||||
validator_index = len(state.validators)
|
||||
amount = spec.MAX_EFFECTIVE_BALANCE
|
||||
|
||||
pubkey = pubkeys[validator_index]
|
||||
privkey = privkeys[validator_index]
|
||||
withdrawal_credentials = spec.BLS_WITHDRAWAL_PREFIX + spec.hash(pubkey)[1:]
|
||||
|
||||
deposit_message = spec.DepositMessage(pubkey=pubkey, withdrawal_credentials=withdrawal_credentials, amount=amount)
|
||||
domain = spec.compute_domain(domain_type=spec.DOMAIN_DEPOSIT, fork_version=fork_version)
|
||||
deposit_data = spec.DepositData(
|
||||
pubkey=pubkey, withdrawal_credentials=withdrawal_credentials, amount=amount,
|
||||
signature=bls.Sign(privkey, spec.compute_signing_root(deposit_message, domain))
|
||||
)
|
||||
deposit, root, _ = deposit_from_context(spec, [deposit_data], 0)
|
||||
|
||||
state.eth1_deposit_index = 0
|
||||
state.eth1_data.deposit_root = root
|
||||
state.eth1_data.deposit_count = 1
|
||||
|
||||
yield from run_deposit_processing_eip7251(spec, state, deposit, validator_index, valid=valid, effective=effective)
|
||||
|
@ -4,6 +4,7 @@ from rlp import encode
|
||||
from rlp.sedes import big_endian_int, Binary, List
|
||||
|
||||
from eth2spec.debug.random_value import get_random_bytes_list
|
||||
from eth2spec.test.helpers.withdrawals import get_expected_withdrawals
|
||||
from eth2spec.test.helpers.forks import (
|
||||
is_post_capella,
|
||||
is_post_deneb,
|
||||
@ -223,7 +224,7 @@ def build_empty_execution_payload(spec, state, randao_mix=None):
|
||||
transactions=empty_txs,
|
||||
)
|
||||
if is_post_capella(spec):
|
||||
payload.withdrawals = spec.get_expected_withdrawals(state)
|
||||
payload.withdrawals = get_expected_withdrawals(spec, state)
|
||||
if is_post_deneb(spec):
|
||||
payload.blob_gas_used = 0
|
||||
payload.excess_blob_gas = 0
|
||||
|
@ -152,7 +152,10 @@ def create_genesis_state(spec, validator_balances, activation_threshold):
|
||||
state.deposit_balance_to_consume = 0
|
||||
state.exit_balance_to_consume = 0
|
||||
state.earliest_exit_epoch = spec.GENESIS_EPOCH
|
||||
state.consolidation_balance_to_consume = 0
|
||||
state.earliest_consolidation_epoch = 0
|
||||
state.pending_balance_deposits = []
|
||||
state.pending_partial_withdrawals = []
|
||||
state.pending_consolidations = []
|
||||
|
||||
return state
|
||||
|
@ -1,5 +1,5 @@
|
||||
from eth2spec.test.helpers.block_header import sign_block_header
|
||||
from eth2spec.test.helpers.forks import is_post_altair, is_post_bellatrix
|
||||
from eth2spec.test.helpers.forks import is_post_altair, is_post_bellatrix, is_post_eip7251
|
||||
from eth2spec.test.helpers.keys import pubkey_to_privkey
|
||||
from eth2spec.test.helpers.state import get_balance
|
||||
from eth2spec.test.helpers.sync_committee import (
|
||||
@ -9,7 +9,9 @@ from eth2spec.test.helpers.sync_committee import (
|
||||
|
||||
|
||||
def get_min_slashing_penalty_quotient(spec):
|
||||
if is_post_bellatrix(spec):
|
||||
if is_post_eip7251(spec):
|
||||
return spec.MIN_SLASHING_PENALTY_QUOTIENT_EIP7251
|
||||
elif is_post_bellatrix(spec):
|
||||
return spec.MIN_SLASHING_PENALTY_QUOTIENT_BELLATRIX
|
||||
elif is_post_altair(spec):
|
||||
return spec.MIN_SLASHING_PENALTY_QUOTIENT_ALTAIR
|
||||
@ -17,6 +19,13 @@ def get_min_slashing_penalty_quotient(spec):
|
||||
return spec.MIN_SLASHING_PENALTY_QUOTIENT
|
||||
|
||||
|
||||
def get_whistleblower_reward_quotient(spec):
|
||||
if is_post_eip7251(spec):
|
||||
return spec.WHISTLEBLOWER_REWARD_QUOTIENT_EIP7251
|
||||
else:
|
||||
return spec.WHISTLEBLOWER_REWARD_QUOTIENT
|
||||
|
||||
|
||||
def check_proposer_slashing_effect(spec, pre_state, state, slashed_index, block=None):
|
||||
slashed_validator = state.validators[slashed_index]
|
||||
assert slashed_validator.slashed
|
||||
@ -25,7 +34,7 @@ def check_proposer_slashing_effect(spec, pre_state, state, slashed_index, block=
|
||||
|
||||
proposer_index = spec.get_beacon_proposer_index(state)
|
||||
slash_penalty = state.validators[slashed_index].effective_balance // get_min_slashing_penalty_quotient(spec)
|
||||
whistleblower_reward = state.validators[slashed_index].effective_balance // spec.WHISTLEBLOWER_REWARD_QUOTIENT
|
||||
whistleblower_reward = state.validators[slashed_index].effective_balance // get_whistleblower_reward_quotient(spec)
|
||||
|
||||
# Altair introduces sync committee (SC) reward and penalty
|
||||
sc_reward_for_slashed = sc_penalty_for_slashed = sc_reward_for_proposer = sc_penalty_for_proposer = 0
|
||||
|
@ -1,4 +1,13 @@
|
||||
import random
|
||||
from eth2spec.test.helpers.forks import is_post_eip7251
|
||||
|
||||
|
||||
def get_expected_withdrawals(spec, state):
|
||||
if is_post_eip7251(spec):
|
||||
withdrawals, _ = spec.get_expected_withdrawals(state)
|
||||
return withdrawals
|
||||
else:
|
||||
return spec.get_expected_withdrawals(state)
|
||||
|
||||
|
||||
def set_validator_fully_withdrawable(spec, state, index, withdrawable_epoch=None):
|
||||
|
@ -10,7 +10,10 @@ from eth2spec.test.helpers.attester_slashings import (
|
||||
get_valid_attester_slashing, get_valid_attester_slashing_by_indices,
|
||||
get_indexed_attestation_participants, get_attestation_2_data, get_attestation_1_data,
|
||||
)
|
||||
from eth2spec.test.helpers.proposer_slashings import get_min_slashing_penalty_quotient
|
||||
from eth2spec.test.helpers.proposer_slashings import (
|
||||
get_min_slashing_penalty_quotient,
|
||||
get_whistleblower_reward_quotient,
|
||||
)
|
||||
from eth2spec.test.helpers.state import (
|
||||
get_balance,
|
||||
next_epoch_via_block,
|
||||
@ -49,7 +52,7 @@ def run_attester_slashing_processing(spec, state, attester_slashing, valid=True)
|
||||
}
|
||||
|
||||
total_proposer_rewards = sum(
|
||||
effective_balance // spec.WHISTLEBLOWER_REWARD_QUOTIENT
|
||||
effective_balance // get_whistleblower_reward_quotient(spec)
|
||||
for effective_balance in pre_slashing_effectives.values()
|
||||
)
|
||||
|
||||
@ -71,7 +74,9 @@ def run_attester_slashing_processing(spec, state, attester_slashing, valid=True)
|
||||
assert slashed_validator.withdrawable_epoch == expected_withdrawable_epoch
|
||||
else:
|
||||
assert slashed_validator.withdrawable_epoch < spec.FAR_FUTURE_EPOCH
|
||||
assert get_balance(state, slashed_index) < pre_slashing_balances[slashed_index]
|
||||
if slashed_index != proposer_index:
|
||||
# NOTE: check proposer balances below
|
||||
assert get_balance(state, slashed_index) < pre_slashing_balances[slashed_index]
|
||||
|
||||
if proposer_index not in slashed_indices:
|
||||
# gained whistleblower reward
|
||||
|
@ -7,6 +7,7 @@ from eth2spec.test.helpers.deposits import (
|
||||
sign_deposit_data,
|
||||
)
|
||||
from eth2spec.test.helpers.keys import privkeys, pubkeys
|
||||
from eth2spec.test.helpers.forks import is_post_eip7251
|
||||
|
||||
|
||||
@with_all_phases
|
||||
@ -123,8 +124,9 @@ def test_top_up__max_effective_balance(spec, state):
|
||||
|
||||
yield from run_deposit_processing(spec, state, deposit, validator_index)
|
||||
|
||||
assert state.balances[validator_index] == spec.MAX_EFFECTIVE_BALANCE + amount
|
||||
assert state.validators[validator_index].effective_balance == spec.MAX_EFFECTIVE_BALANCE
|
||||
if not is_post_eip7251(spec):
|
||||
assert state.balances[validator_index] == spec.MAX_EFFECTIVE_BALANCE + amount
|
||||
assert state.validators[validator_index].effective_balance == spec.MAX_EFFECTIVE_BALANCE
|
||||
|
||||
|
||||
@with_all_phases
|
||||
@ -141,9 +143,10 @@ def test_top_up__less_effective_balance(spec, state):
|
||||
|
||||
yield from run_deposit_processing(spec, state, deposit, validator_index)
|
||||
|
||||
assert state.balances[validator_index] == initial_balance + amount
|
||||
# unchanged effective balance
|
||||
assert state.validators[validator_index].effective_balance == initial_effective_balance
|
||||
if not is_post_eip7251(spec):
|
||||
assert state.balances[validator_index] == initial_balance + amount
|
||||
# unchanged effective balance
|
||||
assert state.validators[validator_index].effective_balance == initial_effective_balance
|
||||
|
||||
|
||||
@with_all_phases
|
||||
@ -160,9 +163,10 @@ def test_top_up__zero_balance(spec, state):
|
||||
|
||||
yield from run_deposit_processing(spec, state, deposit, validator_index)
|
||||
|
||||
assert state.balances[validator_index] == initial_balance + amount
|
||||
# unchanged effective balance
|
||||
assert state.validators[validator_index].effective_balance == initial_effective_balance
|
||||
if not is_post_eip7251(spec):
|
||||
assert state.balances[validator_index] == initial_balance + amount
|
||||
# unchanged effective balance
|
||||
assert state.validators[validator_index].effective_balance == initial_effective_balance
|
||||
|
||||
|
||||
@with_all_phases
|
||||
|
@ -1,15 +1,24 @@
|
||||
from eth2spec.test.context import spec_state_test, with_all_phases
|
||||
from eth2spec.test.helpers.epoch_processing import run_epoch_processing_to
|
||||
from eth2spec.test.helpers.withdrawals import (
|
||||
set_compounding_withdrawal_credential,
|
||||
)
|
||||
from eth2spec.test.helpers.forks import is_post_eip7251
|
||||
|
||||
|
||||
@with_all_phases
|
||||
@spec_state_test
|
||||
def test_effective_balance_hysteresis(spec, state):
|
||||
run_test_effective_balance_hysteresis(spec, state)
|
||||
|
||||
|
||||
def run_test_effective_balance_hysteresis(spec, state, with_compounding_credentials=False):
|
||||
assert is_post_eip7251(spec) or not with_compounding_credentials
|
||||
# Prepare state up to the final-updates.
|
||||
# Then overwrite the balances, we only want to focus to be on the hysteresis based changes.
|
||||
run_epoch_processing_to(spec, state, 'process_effective_balance_updates')
|
||||
# Set some edge cases for balances
|
||||
max = spec.MAX_EFFECTIVE_BALANCE
|
||||
max = spec.MAX_EFFECTIVE_BALANCE_EIP_7251 if with_compounding_credentials else spec.MIN_ACTIVATION_BALANCE
|
||||
min = spec.config.EJECTION_BALANCE
|
||||
inc = spec.EFFECTIVE_BALANCE_INCREMENT
|
||||
div = spec.HYSTERESIS_QUOTIENT
|
||||
@ -35,6 +44,8 @@ def test_effective_balance_hysteresis(spec, state):
|
||||
current_epoch = spec.get_current_epoch(state)
|
||||
for i, (pre_eff, bal, _, _) in enumerate(cases):
|
||||
assert spec.is_active_validator(state.validators[i], current_epoch)
|
||||
if with_compounding_credentials:
|
||||
set_compounding_withdrawal_credential(spec, state, i)
|
||||
state.validators[i].effective_balance = pre_eff
|
||||
state.balances[i] = bal
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
from eth2spec.test.helpers.deposits import mock_deposit
|
||||
from eth2spec.test.helpers.state import next_epoch, next_slots
|
||||
from eth2spec.test.helpers.forks import is_post_eip7251
|
||||
from eth2spec.test.helpers.constants import MINIMAL
|
||||
from eth2spec.test.context import (
|
||||
spec_test, spec_state_test,
|
||||
@ -105,17 +106,23 @@ def test_activation_queue_sorting(spec, state):
|
||||
|
||||
yield from run_process_registry_updates(spec, state)
|
||||
|
||||
# the first got in as second
|
||||
assert state.validators[0].activation_epoch != spec.FAR_FUTURE_EPOCH
|
||||
# the prioritized got in as first
|
||||
assert state.validators[mock_activations - 1].activation_epoch != spec.FAR_FUTURE_EPOCH
|
||||
# the second last is at the end of the queue, and did not make the churn,
|
||||
# hence is not assigned an activation_epoch yet.
|
||||
assert state.validators[mock_activations - 2].activation_epoch == spec.FAR_FUTURE_EPOCH
|
||||
# the one at churn_limit did not make it, it was out-prioritized
|
||||
assert state.validators[churn_limit].activation_epoch == spec.FAR_FUTURE_EPOCH
|
||||
# but the one in front of the above did
|
||||
assert state.validators[churn_limit - 1].activation_epoch != spec.FAR_FUTURE_EPOCH
|
||||
if is_post_eip7251(spec):
|
||||
# NOTE: EIP-7521 changed how activations are gated
|
||||
# given the prefix setup here, all validators should be activated
|
||||
activation_epochs = [state.validators[i].activation_epoch for i in range(mock_activations)]
|
||||
assert all([epoch != spec.FAR_FUTURE_EPOCH for epoch in activation_epochs])
|
||||
else:
|
||||
# the first got in as second
|
||||
assert state.validators[0].activation_epoch != spec.FAR_FUTURE_EPOCH
|
||||
# the prioritized got in as first
|
||||
assert state.validators[mock_activations - 1].activation_epoch != spec.FAR_FUTURE_EPOCH
|
||||
# the second last is at the end of the queue, and did not make the churn,
|
||||
# hence is not assigned an activation_epoch yet.
|
||||
assert state.validators[mock_activations - 2].activation_epoch == spec.FAR_FUTURE_EPOCH
|
||||
# the one at churn_limit did not make it, it was out-prioritized
|
||||
assert state.validators[churn_limit].activation_epoch == spec.FAR_FUTURE_EPOCH
|
||||
# but the one in front of the above did
|
||||
assert state.validators[churn_limit - 1].activation_epoch != spec.FAR_FUTURE_EPOCH
|
||||
|
||||
|
||||
def run_test_activation_queue_efficiency(spec, state):
|
||||
@ -141,7 +148,9 @@ def run_test_activation_queue_efficiency(spec, state):
|
||||
|
||||
# Half should churn in first run of registry update
|
||||
for i in range(mock_activations):
|
||||
if i < churn_limit_0:
|
||||
# NOTE: EIP-7251 changes how activations are gated
|
||||
# given the prefix setup here, all validators are eligible for activation
|
||||
if i < churn_limit_0 or is_post_eip7251(spec):
|
||||
assert state.validators[i].activation_epoch < spec.FAR_FUTURE_EPOCH
|
||||
else:
|
||||
assert state.validators[i].activation_epoch == spec.FAR_FUTURE_EPOCH
|
||||
@ -205,16 +214,30 @@ def run_test_ejection_past_churn_limit(spec, state):
|
||||
|
||||
yield from run_process_registry_updates(spec, state)
|
||||
|
||||
if is_post_eip7251(spec):
|
||||
per_epoch_churn = spec.get_activation_exit_churn_limit(state)
|
||||
|
||||
def map_index_to_exit_epoch(i):
|
||||
balance_so_far = i * spec.config.EJECTION_BALANCE
|
||||
offset_epoch = balance_so_far // per_epoch_churn
|
||||
if spec.config.EJECTION_BALANCE > per_epoch_churn - (balance_so_far % per_epoch_churn):
|
||||
offset_epoch += 1
|
||||
return expected_ejection_epoch + offset_epoch
|
||||
else:
|
||||
def map_index_to_exit_epoch(i):
|
||||
# first third ejected in normal speed
|
||||
if i < mock_ejections // 3:
|
||||
return expected_ejection_epoch
|
||||
# second third gets delayed by 1 epoch
|
||||
elif mock_ejections // 3 <= i < mock_ejections * 2 // 3:
|
||||
return expected_ejection_epoch + 1
|
||||
# final third gets delayed by 2 epochs
|
||||
else:
|
||||
return expected_ejection_epoch + 2
|
||||
|
||||
for i in range(mock_ejections):
|
||||
# first third ejected in normal speed
|
||||
if i < mock_ejections // 3:
|
||||
assert state.validators[i].exit_epoch == expected_ejection_epoch
|
||||
# second third gets delayed by 1 epoch
|
||||
elif mock_ejections // 3 <= i < mock_ejections * 2 // 3:
|
||||
assert state.validators[i].exit_epoch == expected_ejection_epoch + 1
|
||||
# final third gets delayed by 2 epochs
|
||||
else:
|
||||
assert state.validators[i].exit_epoch == expected_ejection_epoch + 2
|
||||
target_exit_epoch = map_index_to_exit_epoch(i)
|
||||
assert state.validators[i].exit_epoch == target_exit_epoch
|
||||
|
||||
|
||||
@with_all_phases
|
||||
@ -286,7 +309,10 @@ def run_test_activation_queue_activation_and_ejection(spec, state, num_per_statu
|
||||
for validator_index in activation_indices[churn_limit:]:
|
||||
validator = state.validators[validator_index]
|
||||
assert validator.activation_eligibility_epoch != spec.FAR_FUTURE_EPOCH
|
||||
assert validator.activation_epoch == spec.FAR_FUTURE_EPOCH
|
||||
# NOTE: activations are gated differently after EIP-7251
|
||||
# all eligible validators were activated, regardless of churn limit
|
||||
if not is_post_eip7251(spec):
|
||||
assert validator.activation_epoch == spec.FAR_FUTURE_EPOCH
|
||||
|
||||
# all ejection balance validators ejected for a future epoch
|
||||
for i, validator_index in enumerate(ejection_indices):
|
||||
@ -364,9 +390,13 @@ def test_invalid_large_withdrawable_epoch(spec, state):
|
||||
assert spec.is_active_validator(state.validators[0], spec.get_current_epoch(state))
|
||||
assert spec.is_active_validator(state.validators[1], spec.get_current_epoch(state))
|
||||
|
||||
state.validators[0].exit_epoch = spec.FAR_FUTURE_EPOCH - 1
|
||||
exit_epoch = spec.FAR_FUTURE_EPOCH - 1
|
||||
state.validators[0].exit_epoch = exit_epoch
|
||||
state.validators[1].effective_balance = spec.config.EJECTION_BALANCE
|
||||
|
||||
if is_post_eip7251(spec):
|
||||
state.earliest_exit_epoch = exit_epoch
|
||||
|
||||
try:
|
||||
yield from run_process_registry_updates(spec, state)
|
||||
except ValueError:
|
||||
|
@ -34,6 +34,7 @@ from eth2spec.test.helpers.constants import PHASE0, MINIMAL
|
||||
from eth2spec.test.helpers.forks import (
|
||||
is_post_altair,
|
||||
is_post_bellatrix,
|
||||
is_post_eip7251,
|
||||
is_post_capella,
|
||||
)
|
||||
from eth2spec.test.context import (
|
||||
@ -743,9 +744,14 @@ def test_deposit_in_block(spec, state):
|
||||
yield 'blocks', [signed_block]
|
||||
yield 'post', state
|
||||
|
||||
if is_post_eip7251(spec):
|
||||
balance = state.pending_balance_deposits[0].amount
|
||||
else:
|
||||
balance = get_balance(state, validator_index)
|
||||
|
||||
assert len(state.validators) == initial_registry_len + 1
|
||||
assert len(state.balances) == initial_balances_len + 1
|
||||
assert get_balance(state, validator_index) == spec.MAX_EFFECTIVE_BALANCE
|
||||
assert balance == spec.MAX_EFFECTIVE_BALANCE
|
||||
assert state.validators[validator_index].pubkey == pubkeys[validator_index]
|
||||
|
||||
|
||||
@ -808,7 +814,11 @@ def test_deposit_top_up(spec, state):
|
||||
committee_bits,
|
||||
)
|
||||
|
||||
assert get_balance(state, validator_index) == (
|
||||
balance = get_balance(state, validator_index)
|
||||
if is_post_eip7251(spec):
|
||||
balance += state.pending_balance_deposits[0].amount
|
||||
|
||||
assert balance == (
|
||||
validator_pre_balance + amount + sync_committee_reward - sync_committee_penalty
|
||||
)
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user