Skip to content

Commit a09d0c3

Browse files
authored
Merge pull request #3990 from mkalinin/upgrade-to-electra-tests
electra: Add more transition tests
2 parents 49b6840 + 5653d73 commit a09d0c3

File tree

10 files changed

+206
-9
lines changed

10 files changed

+206
-9
lines changed

specs/electra/fork.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,6 @@ an irregular state change is made to upgrade to Electra.
7272
```python
7373
def upgrade_to_electra(pre: deneb.BeaconState) -> BeaconState:
7474
epoch = deneb.get_current_epoch(pre)
75-
latest_execution_payload_header = pre.latest_execution_payload_header
7675

7776
earliest_exit_epoch = compute_activation_exit_epoch(get_current_epoch(pre))
7877
for validator in pre.validators:
@@ -121,7 +120,7 @@ def upgrade_to_electra(pre: deneb.BeaconState) -> BeaconState:
121120
current_sync_committee=pre.current_sync_committee,
122121
next_sync_committee=pre.next_sync_committee,
123122
# Execution-layer
124-
latest_execution_payload_header=latest_execution_payload_header, # [Modified in Electra:EIP6110:EIP7002]
123+
latest_execution_payload_header=pre.latest_execution_payload_header,
125124
# Withdrawals
126125
next_withdrawal_index=pre.next_withdrawal_index,
127126
next_withdrawal_validator_index=pre.next_withdrawal_validator_index,

tests/core/pyspec/eth2spec/test/electra/fork/test_electra_fork_basic.py

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -87,11 +87,22 @@ def test_fork_random_large_validator_set(spec, phases, state):
8787
@with_state
8888
@with_meta_tags(ELECTRA_FORK_TEST_META_TAGS)
8989
def test_fork_pre_activation(spec, phases, state):
90+
index = 0
9091
post_spec = phases[ELECTRA]
91-
state.validators[0].activation_epoch = spec.FAR_FUTURE_EPOCH
92+
state.validators[index].activation_epoch = spec.FAR_FUTURE_EPOCH
9293
post_state = yield from run_fork_test(post_spec, state)
9394

94-
assert len(post_state.pending_deposits) > 0
95+
validator = post_state.validators[index]
96+
assert post_state.balances[index] == 0
97+
assert validator.effective_balance == 0
98+
assert validator.activation_eligibility_epoch == spec.FAR_FUTURE_EPOCH
99+
assert post_state.pending_deposits == [post_spec.PendingDeposit(
100+
pubkey=validator.pubkey,
101+
withdrawal_credentials=validator.withdrawal_credentials,
102+
amount=state.balances[index],
103+
signature=spec.bls.G2_POINT_AT_INFINITY,
104+
slot=spec.GENESIS_SLOT,
105+
)]
95106

96107

97108
@with_phases(phases=[DENEB], other_phases=[ELECTRA])
@@ -123,13 +134,21 @@ def test_fork_pending_deposits_are_sorted(spec, phases, state):
123134
@with_state
124135
@with_meta_tags(ELECTRA_FORK_TEST_META_TAGS)
125136
def test_fork_has_compounding_withdrawal_credential(spec, phases, state):
137+
index = 0
126138
post_spec = phases[ELECTRA]
127-
validator = state.validators[0]
128-
state.balances[0] = post_spec.MIN_ACTIVATION_BALANCE + 1
139+
validator = state.validators[index]
140+
state.balances[index] = post_spec.MIN_ACTIVATION_BALANCE + 1
129141
validator.withdrawal_credentials = post_spec.COMPOUNDING_WITHDRAWAL_PREFIX + validator.withdrawal_credentials[1:]
130142
post_state = yield from run_fork_test(post_spec, state)
131143

132-
assert len(post_state.pending_deposits) > 0
144+
assert post_state.balances[index] == post_spec.MIN_ACTIVATION_BALANCE
145+
assert post_state.pending_deposits == [post_spec.PendingDeposit(
146+
pubkey=validator.pubkey,
147+
withdrawal_credentials=validator.withdrawal_credentials,
148+
amount=state.balances[index] - post_spec.MIN_ACTIVATION_BALANCE,
149+
signature=spec.bls.G2_POINT_AT_INFINITY,
150+
slot=spec.GENESIS_SLOT,
151+
)]
133152

134153

135154
@with_phases(phases=[DENEB], other_phases=[ELECTRA])

tests/core/pyspec/eth2spec/test/electra/transition/__init__.py

Whitespace-only changes.
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
from eth2spec.test.context import (
2+
ForkMeta,
3+
always_bls,
4+
with_fork_metas,
5+
with_presets,
6+
)
7+
from eth2spec.test.helpers.constants import (
8+
AFTER_ELECTRA_PRE_POST_FORKS,
9+
MINIMAL,
10+
)
11+
from eth2spec.test.helpers.fork_transition import (
12+
OperationType,
13+
run_transition_with_operation,
14+
)
15+
16+
17+
#
18+
# DepositRequest
19+
#
20+
21+
@with_fork_metas([ForkMeta(pre_fork_name=pre, post_fork_name=post, fork_epoch=2)
22+
for pre, post in AFTER_ELECTRA_PRE_POST_FORKS])
23+
@always_bls
24+
def test_transition_with_deposit_request_right_after_fork(state, fork_epoch, spec, post_spec, pre_tag, post_tag):
25+
"""
26+
Create a DEPOSIT_REQUEST right *after* the transition
27+
"""
28+
yield from run_transition_with_operation(
29+
state,
30+
fork_epoch,
31+
spec,
32+
post_spec,
33+
pre_tag,
34+
post_tag,
35+
operation_type=OperationType.DEPOSIT_REQUEST,
36+
operation_at_slot=fork_epoch * spec.SLOTS_PER_EPOCH,
37+
)
38+
39+
40+
#
41+
# WithdrawalRequest
42+
#
43+
44+
@with_fork_metas([ForkMeta(pre_fork_name=pre, post_fork_name=post, fork_epoch=66)
45+
for pre, post in AFTER_ELECTRA_PRE_POST_FORKS])
46+
@with_presets([MINIMAL], reason="too slow")
47+
@always_bls
48+
def test_transition_with_full_withdrawal_request_right_after_fork(
49+
state,
50+
fork_epoch,
51+
spec,
52+
post_spec,
53+
pre_tag,
54+
post_tag
55+
):
56+
"""
57+
Create a WITHDRAWAL_REQUEST right *after* the transition
58+
"""
59+
yield from run_transition_with_operation(
60+
state,
61+
fork_epoch,
62+
spec,
63+
post_spec,
64+
pre_tag,
65+
post_tag,
66+
operation_type=OperationType.WITHDRAWAL_REQUEST,
67+
operation_at_slot=fork_epoch * spec.SLOTS_PER_EPOCH,
68+
)
69+
70+
71+
#
72+
# ConsolidationRequest
73+
#
74+
75+
@with_fork_metas([ForkMeta(pre_fork_name=pre, post_fork_name=post, fork_epoch=2)
76+
for pre, post in AFTER_ELECTRA_PRE_POST_FORKS])
77+
@always_bls
78+
def test_transition_with_consolidation_request_right_after_fork(
79+
state,
80+
fork_epoch,
81+
spec,
82+
post_spec,
83+
pre_tag,
84+
post_tag
85+
):
86+
"""
87+
Create a CONSOLIDATION_REQUEST right *after* the transition
88+
"""
89+
yield from run_transition_with_operation(
90+
state,
91+
fork_epoch,
92+
spec,
93+
post_spec,
94+
pre_tag,
95+
post_tag,
96+
operation_type=OperationType.CONSOLIDATION_REQUEST,
97+
operation_at_slot=fork_epoch * spec.SLOTS_PER_EPOCH,
98+
)
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
from eth2spec.test.helpers.withdrawals import (
2+
set_eth1_withdrawal_credential_with_balance
3+
)
4+
5+
6+
def prepare_switch_to_compounding_request(spec, state, validator_index, address=None):
7+
validator = state.validators[validator_index]
8+
if not spec.has_execution_withdrawal_credential(validator):
9+
set_eth1_withdrawal_credential_with_balance(spec, state, validator_index, address=address)
10+
11+
return spec.ConsolidationRequest(
12+
source_address=state.validators[validator_index].withdrawal_credentials[12:],
13+
source_pubkey=state.validators[validator_index].pubkey,
14+
target_pubkey=state.validators[validator_index].pubkey,
15+
)

tests/core/pyspec/eth2spec/test/helpers/constants.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,10 @@
7474
ALL_PRE_POST_FORKS = POST_FORK_OF.items()
7575
DENEB_TRANSITION_UPGRADES_AND_AFTER = {key: value for key, value in POST_FORK_OF.items()
7676
if key not in [PHASE0, ALTAIR, BELLATRIX]}
77+
ELECTRA_TRANSITION_UPGRADES_AND_AFTER = {key: value for key, value in POST_FORK_OF.items()
78+
if key not in [PHASE0, ALTAIR, BELLATRIX, CAPELLA]}
7779
AFTER_DENEB_PRE_POST_FORKS = DENEB_TRANSITION_UPGRADES_AND_AFTER.items()
80+
AFTER_ELECTRA_PRE_POST_FORKS = ELECTRA_TRANSITION_UPGRADES_AND_AFTER.items()
7881

7982
#
8083
# Config and Preset

tests/core/pyspec/eth2spec/test/helpers/electra/fork.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ def run_fork_test(post_spec, pre_state):
5454
stable_validator_fields = [
5555
'pubkey', 'withdrawal_credentials',
5656
'slashed',
57-
'exit_epoch', 'withdrawable_epoch',
57+
'activation_epoch', 'exit_epoch', 'withdrawable_epoch',
5858
]
5959
for field in stable_validator_fields:
6060
assert getattr(pre_validator, field) == getattr(post_validator, field)

tests/core/pyspec/eth2spec/test/helpers/fork_transition.py

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
)
2222
from eth2spec.test.helpers.deposits import (
2323
prepare_state_and_deposit,
24+
prepare_deposit_request,
2425
)
2526
from eth2spec.test.helpers.proposer_slashings import (
2627
get_valid_proposer_slashing,
@@ -37,6 +38,12 @@
3738
from eth2spec.test.helpers.voluntary_exits import (
3839
prepare_signed_exits,
3940
)
41+
from eth2spec.test.helpers.withdrawals import (
42+
prepare_withdrawal_request,
43+
)
44+
from eth2spec.test.helpers.consolidations import (
45+
prepare_switch_to_compounding_request,
46+
)
4047

4148

4249
class OperationType(Enum):
@@ -45,11 +52,18 @@ class OperationType(Enum):
4552
DEPOSIT = auto()
4653
VOLUNTARY_EXIT = auto()
4754
BLS_TO_EXECUTION_CHANGE = auto()
55+
DEPOSIT_REQUEST = auto()
56+
WITHDRAWAL_REQUEST = auto()
57+
CONSOLIDATION_REQUEST = auto()
4858

4959

5060
def _set_operations_by_dict(block, operation_dict):
5161
for key, value in operation_dict.items():
52-
setattr(block.body, key, value)
62+
# to handle e.g. `execution_requests.deposits` and `deposits`
63+
obj = block.body
64+
for attr in key.split('.')[:-1]:
65+
obj = getattr(obj, attr)
66+
setattr(obj, key.split('.')[-1], value)
5367

5468

5569
def _state_transition_and_sign_block_at_slot(spec,
@@ -328,6 +342,21 @@ def run_transition_with_operation(state,
328342
selected_validator_index = 0
329343
bls_to_execution_changes = [get_signed_address_change(spec, state, selected_validator_index)]
330344
operation_dict = {'bls_to_execution_changes': bls_to_execution_changes}
345+
elif operation_type == OperationType.DEPOSIT_REQUEST:
346+
# create a new deposit request
347+
selected_validator_index = len(state.validators)
348+
amount = post_spec.MIN_ACTIVATION_BALANCE
349+
deposit_request = prepare_deposit_request(post_spec, selected_validator_index, amount, signed=True)
350+
operation_dict = {'execution_requests.deposits': [deposit_request]}
351+
elif operation_type == OperationType.WITHDRAWAL_REQUEST:
352+
selected_validator_index = 0
353+
withdrawal_request = prepare_withdrawal_request(
354+
post_spec, state, selected_validator_index, amount=post_spec.FULL_EXIT_REQUEST_AMOUNT)
355+
operation_dict = {'execution_requests.withdrawals': [withdrawal_request]}
356+
elif operation_type == OperationType.CONSOLIDATION_REQUEST:
357+
selected_validator_index = 0
358+
consolidation_request = prepare_switch_to_compounding_request(post_spec, state, selected_validator_index)
359+
operation_dict = {'execution_requests.consolidations': [consolidation_request]}
331360

332361
def _check_state():
333362
if operation_type == OperationType.PROPOSER_SLASHING:
@@ -352,6 +381,20 @@ def _check_state():
352381
elif operation_type == OperationType.BLS_TO_EXECUTION_CHANGE:
353382
validator = state.validators[selected_validator_index]
354383
assert validator.withdrawal_credentials[:1] == spec.ETH1_ADDRESS_WITHDRAWAL_PREFIX
384+
elif operation_type == OperationType.DEPOSIT_REQUEST:
385+
assert state.pending_deposits == [post_spec.PendingDeposit(
386+
pubkey=deposit_request.pubkey,
387+
withdrawal_credentials=deposit_request.withdrawal_credentials,
388+
amount=deposit_request.amount,
389+
signature=deposit_request.signature,
390+
slot=state.slot,
391+
)]
392+
elif operation_type == OperationType.WITHDRAWAL_REQUEST:
393+
validator = state.validators[selected_validator_index]
394+
assert validator.exit_epoch < post_spec.FAR_FUTURE_EPOCH
395+
elif operation_type == OperationType.CONSOLIDATION_REQUEST:
396+
validator = state.validators[selected_validator_index]
397+
assert validator.withdrawal_credentials[:1] == post_spec.COMPOUNDING_WITHDRAWAL_PREFIX
355398

356399
yield "pre", state
357400

tests/core/pyspec/eth2spec/test/helpers/withdrawals.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,22 @@ def prepare_pending_withdrawal(spec, state, validator_index,
128128

129129
return withdrawal
130130

131+
132+
def prepare_withdrawal_request(spec, state, validator_index, address=None, amount=None):
133+
validator = state.validators[validator_index]
134+
if not spec.has_execution_withdrawal_credential(validator):
135+
set_eth1_withdrawal_credential_with_balance(spec, state, validator_index, address=address)
136+
137+
if amount is None:
138+
amount = spec.FULL_EXIT_REQUEST_AMOUNT
139+
140+
return spec.WithdrawalRequest(
141+
source_address=state.validators[validator_index].withdrawal_credentials[12:],
142+
validator_pubkey=state.validators[validator_index].pubkey,
143+
amount=amount,
144+
)
145+
146+
131147
#
132148
# Run processing
133149
#

tests/generators/transition/main.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@
2020
test_operations as test_deneb_operations,
2121
test_transition as test_deneb_transition,
2222
)
23+
from eth2spec.test.electra.transition import (
24+
test_operations as test_electra_operations,
25+
)
2326

2427

2528
def create_provider(tests_src, preset_name: str, pre_fork_name: str, post_fork_name: str) -> gen_typing.TestProvider:
@@ -49,6 +52,7 @@ def cases_fn() -> Iterable[gen_typing.TestCase]:
4952
test_altair_operations,
5053
test_deneb_operations,
5154
test_deneb_transition,
55+
test_electra_operations,
5256
)
5357
for transition_test_module in all_tests:
5458
for pre_fork, post_fork in ALL_PRE_POST_FORKS:

0 commit comments

Comments
 (0)