Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

electra: Add more transition tests #3990

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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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,
jtraglia marked this conversation as resolved.
Show resolved Hide resolved
# 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):
jtraglia marked this conversation as resolved.
Show resolved Hide resolved
"""
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