Skip to content

Commit

Permalink
Merge pull request #3990 from mkalinin/upgrade-to-electra-tests
Browse files Browse the repository at this point in the history
electra: Add more transition tests
  • Loading branch information
jtraglia authored Nov 5, 2024
2 parents 49b6840 + 5653d73 commit a09d0c3
Show file tree
Hide file tree
Showing 10 changed files with 206 additions and 9 deletions.
3 changes: 1 addition & 2 deletions specs/electra/fork.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,6 @@ an irregular state change is made to upgrade to Electra.
```python
def upgrade_to_electra(pre: deneb.BeaconState) -> BeaconState:
epoch = deneb.get_current_epoch(pre)
latest_execution_payload_header = pre.latest_execution_payload_header

earliest_exit_epoch = compute_activation_exit_epoch(get_current_epoch(pre))
for validator in pre.validators:
Expand Down Expand Up @@ -121,7 +120,7 @@ def upgrade_to_electra(pre: deneb.BeaconState) -> BeaconState:
current_sync_committee=pre.current_sync_committee,
next_sync_committee=pre.next_sync_committee,
# Execution-layer
latest_execution_payload_header=latest_execution_payload_header, # [Modified in Electra:EIP6110:EIP7002]
latest_execution_payload_header=pre.latest_execution_payload_header,
# Withdrawals
next_withdrawal_index=pre.next_withdrawal_index,
next_withdrawal_validator_index=pre.next_withdrawal_validator_index,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,11 +87,22 @@ def test_fork_random_large_validator_set(spec, phases, state):
@with_state
@with_meta_tags(ELECTRA_FORK_TEST_META_TAGS)
def test_fork_pre_activation(spec, phases, state):
index = 0
post_spec = phases[ELECTRA]
state.validators[0].activation_epoch = spec.FAR_FUTURE_EPOCH
state.validators[index].activation_epoch = spec.FAR_FUTURE_EPOCH
post_state = yield from run_fork_test(post_spec, state)

assert len(post_state.pending_deposits) > 0
validator = post_state.validators[index]
assert post_state.balances[index] == 0
assert validator.effective_balance == 0
assert validator.activation_eligibility_epoch == spec.FAR_FUTURE_EPOCH
assert post_state.pending_deposits == [post_spec.PendingDeposit(
pubkey=validator.pubkey,
withdrawal_credentials=validator.withdrawal_credentials,
amount=state.balances[index],
signature=spec.bls.G2_POINT_AT_INFINITY,
slot=spec.GENESIS_SLOT,
)]


@with_phases(phases=[DENEB], other_phases=[ELECTRA])
Expand Down Expand Up @@ -123,13 +134,21 @@ def test_fork_pending_deposits_are_sorted(spec, phases, state):
@with_state
@with_meta_tags(ELECTRA_FORK_TEST_META_TAGS)
def test_fork_has_compounding_withdrawal_credential(spec, phases, state):
index = 0
post_spec = phases[ELECTRA]
validator = state.validators[0]
state.balances[0] = post_spec.MIN_ACTIVATION_BALANCE + 1
validator = state.validators[index]
state.balances[index] = post_spec.MIN_ACTIVATION_BALANCE + 1
validator.withdrawal_credentials = post_spec.COMPOUNDING_WITHDRAWAL_PREFIX + validator.withdrawal_credentials[1:]
post_state = yield from run_fork_test(post_spec, state)

assert len(post_state.pending_deposits) > 0
assert post_state.balances[index] == post_spec.MIN_ACTIVATION_BALANCE
assert post_state.pending_deposits == [post_spec.PendingDeposit(
pubkey=validator.pubkey,
withdrawal_credentials=validator.withdrawal_credentials,
amount=state.balances[index] - post_spec.MIN_ACTIVATION_BALANCE,
signature=spec.bls.G2_POINT_AT_INFINITY,
slot=spec.GENESIS_SLOT,
)]


@with_phases(phases=[DENEB], other_phases=[ELECTRA])
Expand Down
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
from eth2spec.test.context import (
ForkMeta,
always_bls,
with_fork_metas,
with_presets,
)
from eth2spec.test.helpers.constants import (
AFTER_ELECTRA_PRE_POST_FORKS,
MINIMAL,
)
from eth2spec.test.helpers.fork_transition import (
OperationType,
run_transition_with_operation,
)


#
# DepositRequest
#

@with_fork_metas([ForkMeta(pre_fork_name=pre, post_fork_name=post, fork_epoch=2)
for pre, post in AFTER_ELECTRA_PRE_POST_FORKS])
@always_bls
def test_transition_with_deposit_request_right_after_fork(state, fork_epoch, spec, post_spec, pre_tag, post_tag):
"""
Create a DEPOSIT_REQUEST right *after* the transition
"""
yield from run_transition_with_operation(
state,
fork_epoch,
spec,
post_spec,
pre_tag,
post_tag,
operation_type=OperationType.DEPOSIT_REQUEST,
operation_at_slot=fork_epoch * spec.SLOTS_PER_EPOCH,
)


#
# WithdrawalRequest
#

@with_fork_metas([ForkMeta(pre_fork_name=pre, post_fork_name=post, fork_epoch=66)
for pre, post in AFTER_ELECTRA_PRE_POST_FORKS])
@with_presets([MINIMAL], reason="too slow")
@always_bls
def test_transition_with_full_withdrawal_request_right_after_fork(
state,
fork_epoch,
spec,
post_spec,
pre_tag,
post_tag
):
"""
Create a WITHDRAWAL_REQUEST right *after* the transition
"""
yield from run_transition_with_operation(
state,
fork_epoch,
spec,
post_spec,
pre_tag,
post_tag,
operation_type=OperationType.WITHDRAWAL_REQUEST,
operation_at_slot=fork_epoch * spec.SLOTS_PER_EPOCH,
)


#
# ConsolidationRequest
#

@with_fork_metas([ForkMeta(pre_fork_name=pre, post_fork_name=post, fork_epoch=2)
for pre, post in AFTER_ELECTRA_PRE_POST_FORKS])
@always_bls
def test_transition_with_consolidation_request_right_after_fork(
state,
fork_epoch,
spec,
post_spec,
pre_tag,
post_tag
):
"""
Create a CONSOLIDATION_REQUEST right *after* the transition
"""
yield from run_transition_with_operation(
state,
fork_epoch,
spec,
post_spec,
pre_tag,
post_tag,
operation_type=OperationType.CONSOLIDATION_REQUEST,
operation_at_slot=fork_epoch * spec.SLOTS_PER_EPOCH,
)
15 changes: 15 additions & 0 deletions tests/core/pyspec/eth2spec/test/helpers/consolidations.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
from eth2spec.test.helpers.withdrawals import (
set_eth1_withdrawal_credential_with_balance
)


def prepare_switch_to_compounding_request(spec, state, validator_index, address=None):
validator = state.validators[validator_index]
if not spec.has_execution_withdrawal_credential(validator):
set_eth1_withdrawal_credential_with_balance(spec, state, validator_index, address=address)

return spec.ConsolidationRequest(
source_address=state.validators[validator_index].withdrawal_credentials[12:],
source_pubkey=state.validators[validator_index].pubkey,
target_pubkey=state.validators[validator_index].pubkey,
)
3 changes: 3 additions & 0 deletions tests/core/pyspec/eth2spec/test/helpers/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,10 @@
ALL_PRE_POST_FORKS = POST_FORK_OF.items()
DENEB_TRANSITION_UPGRADES_AND_AFTER = {key: value for key, value in POST_FORK_OF.items()
if key not in [PHASE0, ALTAIR, BELLATRIX]}
ELECTRA_TRANSITION_UPGRADES_AND_AFTER = {key: value for key, value in POST_FORK_OF.items()
if key not in [PHASE0, ALTAIR, BELLATRIX, CAPELLA]}
AFTER_DENEB_PRE_POST_FORKS = DENEB_TRANSITION_UPGRADES_AND_AFTER.items()
AFTER_ELECTRA_PRE_POST_FORKS = ELECTRA_TRANSITION_UPGRADES_AND_AFTER.items()

#
# Config and Preset
Expand Down
2 changes: 1 addition & 1 deletion tests/core/pyspec/eth2spec/test/helpers/electra/fork.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ def run_fork_test(post_spec, pre_state):
stable_validator_fields = [
'pubkey', 'withdrawal_credentials',
'slashed',
'exit_epoch', 'withdrawable_epoch',
'activation_epoch', 'exit_epoch', 'withdrawable_epoch',
]
for field in stable_validator_fields:
assert getattr(pre_validator, field) == getattr(post_validator, field)
Expand Down
45 changes: 44 additions & 1 deletion tests/core/pyspec/eth2spec/test/helpers/fork_transition.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
)
from eth2spec.test.helpers.deposits import (
prepare_state_and_deposit,
prepare_deposit_request,
)
from eth2spec.test.helpers.proposer_slashings import (
get_valid_proposer_slashing,
Expand All @@ -37,6 +38,12 @@
from eth2spec.test.helpers.voluntary_exits import (
prepare_signed_exits,
)
from eth2spec.test.helpers.withdrawals import (
prepare_withdrawal_request,
)
from eth2spec.test.helpers.consolidations import (
prepare_switch_to_compounding_request,
)


class OperationType(Enum):
Expand All @@ -45,11 +52,18 @@ class OperationType(Enum):
DEPOSIT = auto()
VOLUNTARY_EXIT = auto()
BLS_TO_EXECUTION_CHANGE = auto()
DEPOSIT_REQUEST = auto()
WITHDRAWAL_REQUEST = auto()
CONSOLIDATION_REQUEST = auto()


def _set_operations_by_dict(block, operation_dict):
for key, value in operation_dict.items():
setattr(block.body, key, value)
# to handle e.g. `execution_requests.deposits` and `deposits`
obj = block.body
for attr in key.split('.')[:-1]:
obj = getattr(obj, attr)
setattr(obj, key.split('.')[-1], value)


def _state_transition_and_sign_block_at_slot(spec,
Expand Down Expand Up @@ -328,6 +342,21 @@ def run_transition_with_operation(state,
selected_validator_index = 0
bls_to_execution_changes = [get_signed_address_change(spec, state, selected_validator_index)]
operation_dict = {'bls_to_execution_changes': bls_to_execution_changes}
elif operation_type == OperationType.DEPOSIT_REQUEST:
# create a new deposit request
selected_validator_index = len(state.validators)
amount = post_spec.MIN_ACTIVATION_BALANCE
deposit_request = prepare_deposit_request(post_spec, selected_validator_index, amount, signed=True)
operation_dict = {'execution_requests.deposits': [deposit_request]}
elif operation_type == OperationType.WITHDRAWAL_REQUEST:
selected_validator_index = 0
withdrawal_request = prepare_withdrawal_request(
post_spec, state, selected_validator_index, amount=post_spec.FULL_EXIT_REQUEST_AMOUNT)
operation_dict = {'execution_requests.withdrawals': [withdrawal_request]}
elif operation_type == OperationType.CONSOLIDATION_REQUEST:
selected_validator_index = 0
consolidation_request = prepare_switch_to_compounding_request(post_spec, state, selected_validator_index)
operation_dict = {'execution_requests.consolidations': [consolidation_request]}

def _check_state():
if operation_type == OperationType.PROPOSER_SLASHING:
Expand All @@ -352,6 +381,20 @@ def _check_state():
elif operation_type == OperationType.BLS_TO_EXECUTION_CHANGE:
validator = state.validators[selected_validator_index]
assert validator.withdrawal_credentials[:1] == spec.ETH1_ADDRESS_WITHDRAWAL_PREFIX
elif operation_type == OperationType.DEPOSIT_REQUEST:
assert state.pending_deposits == [post_spec.PendingDeposit(
pubkey=deposit_request.pubkey,
withdrawal_credentials=deposit_request.withdrawal_credentials,
amount=deposit_request.amount,
signature=deposit_request.signature,
slot=state.slot,
)]
elif operation_type == OperationType.WITHDRAWAL_REQUEST:
validator = state.validators[selected_validator_index]
assert validator.exit_epoch < post_spec.FAR_FUTURE_EPOCH
elif operation_type == OperationType.CONSOLIDATION_REQUEST:
validator = state.validators[selected_validator_index]
assert validator.withdrawal_credentials[:1] == post_spec.COMPOUNDING_WITHDRAWAL_PREFIX

yield "pre", state

Expand Down
16 changes: 16 additions & 0 deletions tests/core/pyspec/eth2spec/test/helpers/withdrawals.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,22 @@ def prepare_pending_withdrawal(spec, state, validator_index,

return withdrawal


def prepare_withdrawal_request(spec, state, validator_index, address=None, amount=None):
validator = state.validators[validator_index]
if not spec.has_execution_withdrawal_credential(validator):
set_eth1_withdrawal_credential_with_balance(spec, state, validator_index, address=address)

if amount is None:
amount = spec.FULL_EXIT_REQUEST_AMOUNT

return spec.WithdrawalRequest(
source_address=state.validators[validator_index].withdrawal_credentials[12:],
validator_pubkey=state.validators[validator_index].pubkey,
amount=amount,
)


#
# Run processing
#
Expand Down
4 changes: 4 additions & 0 deletions tests/generators/transition/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@
test_operations as test_deneb_operations,
test_transition as test_deneb_transition,
)
from eth2spec.test.electra.transition import (
test_operations as test_electra_operations,
)


def create_provider(tests_src, preset_name: str, pre_fork_name: str, post_fork_name: str) -> gen_typing.TestProvider:
Expand Down Expand Up @@ -49,6 +52,7 @@ def cases_fn() -> Iterable[gen_typing.TestCase]:
test_altair_operations,
test_deneb_operations,
test_deneb_transition,
test_electra_operations,
)
for transition_test_module in all_tests:
for pre_fork, post_fork in ALL_PRE_POST_FORKS:
Expand Down

0 comments on commit a09d0c3

Please sign in to comment.