Skip to content

Commit 85bd77b

Browse files
authored
Merge pull request #3572 from etan-status/lc-transitionacrossforks
Consider fork transitions when using `get_sync_aggregate` helper func
2 parents 90d48e5 + 07710e6 commit 85bd77b

File tree

4 files changed

+76
-32
lines changed

4 files changed

+76
-32
lines changed

tests/core/pyspec/eth2spec/test/altair/light_client/test_sync.py

Lines changed: 9 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -16,16 +16,15 @@
1616
state_transition_with_full_block,
1717
)
1818
from eth2spec.test.helpers.constants import (
19-
PHASE0, ALTAIR, BELLATRIX, CAPELLA, DENEB,
19+
ALTAIR, BELLATRIX, CAPELLA, DENEB,
2020
MINIMAL,
21-
ALL_PHASES,
2221
)
2322
from eth2spec.test.helpers.fork_transition import (
2423
do_fork,
2524
)
2625
from eth2spec.test.helpers.forks import (
26+
get_spec_for_fork_version,
2727
is_post_capella, is_post_deneb,
28-
is_post_fork,
2928
)
3029
from eth2spec.test.helpers.light_client import (
3130
compute_start_slot_at_next_sync_committee_period,
@@ -40,19 +39,6 @@
4039
)
4140

4241

43-
def get_spec_for_fork_version(spec, fork_version, phases):
44-
if phases is None:
45-
return spec
46-
for fork in [fork for fork in ALL_PHASES if is_post_fork(spec.fork, fork)]:
47-
if fork == PHASE0:
48-
fork_version_field = 'GENESIS_FORK_VERSION'
49-
else:
50-
fork_version_field = fork.upper() + '_FORK_VERSION'
51-
if fork_version == getattr(spec.config, fork_version_field):
52-
return phases[fork]
53-
raise ValueError("Unknown fork version %s" % fork_version)
54-
55-
5642
class LightClientSyncTest(object):
5743
steps: List[Dict[str, Any]]
5844
genesis_validators_root: Any
@@ -535,7 +521,7 @@ def run_test_single_fork(spec, phases, state, fork):
535521
finalized_state = state.copy()
536522
attested_block = state_transition_with_full_block(spec, state, True, True)
537523
attested_state = state.copy()
538-
sync_aggregate, _ = get_sync_aggregate(spec, state)
524+
sync_aggregate, _ = get_sync_aggregate(spec, state, phases=phases)
539525
block = state_transition_with_full_block(spec, state, True, True, sync_aggregate=sync_aggregate)
540526
yield from emit_update(test, spec, state, block, attested_state, attested_block, finalized_block, phases=phases)
541527
assert test.store.finalized_header.beacon.slot == finalized_state.slot
@@ -548,7 +534,7 @@ def run_test_single_fork(spec, phases, state, fork):
548534
transition_to(spec, state, spec.compute_start_slot_at_epoch(fork_epoch) - 4)
549535
attested_block = state_transition_with_full_block(spec, state, True, True)
550536
attested_state = state.copy()
551-
sync_aggregate, _ = get_sync_aggregate(spec, state)
537+
sync_aggregate, _ = get_sync_aggregate(spec, state, phases=phases)
552538
block = state_transition_with_full_block(spec, state, True, True, sync_aggregate=sync_aggregate)
553539
update = yield from emit_update(
554540
test, spec, state, block, attested_state, attested_block, finalized_block, phases=phases)
@@ -564,7 +550,7 @@ def run_test_single_fork(spec, phases, state, fork):
564550
# Final slot before fork, check that importing the pre-fork format still works
565551
attested_block = block.copy()
566552
attested_state = state.copy()
567-
sync_aggregate, _ = get_sync_aggregate(spec, state)
553+
sync_aggregate, _ = get_sync_aggregate(spec, state, phases=phases)
568554
block = state_transition_with_full_block(spec, state, True, True, sync_aggregate=sync_aggregate)
569555
yield from emit_update(test, spec, state, block, attested_state, attested_block, finalized_block, phases=phases)
570556
assert test.store.finalized_header.beacon.slot == finalized_state.slot
@@ -575,7 +561,7 @@ def run_test_single_fork(spec, phases, state, fork):
575561
# Upgrade to post-fork spec, attested block is still before the fork
576562
attested_block = block.copy()
577563
attested_state = state.copy()
578-
sync_aggregate, _ = get_sync_aggregate(phases[fork], state)
564+
sync_aggregate, _ = get_sync_aggregate(phases[fork], state, phases=phases)
579565
state, block = do_fork(state, spec, phases[fork], fork_epoch, sync_aggregate=sync_aggregate)
580566
spec = phases[fork]
581567
yield from emit_update(test, spec, state, block, attested_state, attested_block, finalized_block, phases=phases)
@@ -587,7 +573,7 @@ def run_test_single_fork(spec, phases, state, fork):
587573
# Another block after the fork, this time attested block is after the fork
588574
attested_block = block.copy()
589575
attested_state = state.copy()
590-
sync_aggregate, _ = get_sync_aggregate(spec, state)
576+
sync_aggregate, _ = get_sync_aggregate(spec, state, phases=phases)
591577
block = state_transition_with_full_block(spec, state, True, True, sync_aggregate=sync_aggregate)
592578
yield from emit_update(test, spec, state, block, attested_state, attested_block, finalized_block, phases=phases)
593579
assert test.store.finalized_header.beacon.slot == finalized_state.slot
@@ -599,7 +585,7 @@ def run_test_single_fork(spec, phases, state, fork):
599585
transition_to(spec, state, spec.compute_start_slot_at_epoch(fork_epoch + 1) - 2)
600586
attested_block = state_transition_with_full_block(spec, state, True, True)
601587
attested_state = state.copy()
602-
sync_aggregate, _ = get_sync_aggregate(spec, state)
588+
sync_aggregate, _ = get_sync_aggregate(spec, state, phases=phases)
603589
block = state_transition_with_full_block(spec, state, True, True, sync_aggregate=sync_aggregate)
604590
yield from emit_update(test, spec, state, block, attested_state, attested_block, finalized_block, phases=phases)
605591
assert test.store.finalized_header.beacon.slot == finalized_state.slot
@@ -613,7 +599,7 @@ def run_test_single_fork(spec, phases, state, fork):
613599
_, _, state = next_slots_with_attestations(spec, state, 2 * spec.SLOTS_PER_EPOCH - 1, True, True)
614600
attested_block = state_transition_with_full_block(spec, state, True, True)
615601
attested_state = state.copy()
616-
sync_aggregate, _ = get_sync_aggregate(spec, state)
602+
sync_aggregate, _ = get_sync_aggregate(spec, state, phases=phases)
617603
block = state_transition_with_full_block(spec, state, True, True, sync_aggregate=sync_aggregate)
618604
yield from emit_update(test, spec, state, block, attested_state, attested_block, finalized_block, phases=phases)
619605
assert test.store.finalized_header.beacon.slot == finalized_state.slot

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

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,10 @@
33
from eth2spec.test.helpers.attester_slashings import (
44
get_valid_attester_slashing_by_indices,
55
)
6-
from eth2spec.test.helpers.attestations import next_slots_with_attestations
6+
from eth2spec.test.helpers.attestations import (
7+
next_slots_with_attestations,
8+
state_transition_with_full_block,
9+
)
710
from eth2spec.test.helpers.block import (
811
build_empty_block_for_next_slot,
912
build_empty_block,
@@ -21,6 +24,9 @@
2124
from eth2spec.test.helpers.proposer_slashings import (
2225
get_valid_proposer_slashing,
2326
)
27+
from eth2spec.test.helpers.forks import (
28+
get_next_fork_transition,
29+
)
2430
from eth2spec.test.helpers.state import (
2531
next_slot,
2632
state_transition_and_sign_block,
@@ -196,6 +202,34 @@ def _transition_until_fork_minus_one(spec, state, fork_epoch):
196202
transition_to(spec, state, to_slot)
197203

198204

205+
def transition_across_forks(spec, state, to_slot, phases=None, with_block=False, sync_aggregate=None):
206+
assert to_slot > state.slot
207+
state = state.copy()
208+
block = None
209+
to_epoch = spec.compute_epoch_at_slot(to_slot)
210+
while state.slot < to_slot:
211+
assert block is None
212+
epoch = spec.compute_epoch_at_slot(state.slot)
213+
post_spec, fork_epoch = get_next_fork_transition(spec, epoch, phases)
214+
if fork_epoch is None or to_epoch < fork_epoch:
215+
if with_block and (to_slot == state.slot + 1):
216+
transition_to(spec, state, to_slot - 1)
217+
block = state_transition_with_full_block(
218+
spec, state, True, True,
219+
sync_aggregate=sync_aggregate)
220+
else:
221+
transition_to(spec, state, to_slot)
222+
else:
223+
transition_until_fork(spec, state, fork_epoch)
224+
state, block = do_fork(
225+
state, spec, post_spec, fork_epoch,
226+
with_block=with_block and (to_slot == state.slot + 1),
227+
sync_aggregate=sync_aggregate,
228+
)
229+
spec = post_spec
230+
return spec, state, block
231+
232+
199233
def transition_to_next_epoch_and_append_blocks(spec,
200234
state,
201235
post_tag,

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

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
from .constants import (
2-
ALTAIR, BELLATRIX, CAPELLA, DENEB,
2+
PHASE0, ALTAIR, BELLATRIX, CAPELLA, DENEB,
33
EIP6110, EIP7002, WHISK,
44
PREVIOUS_FORK_OF,
55
)
@@ -47,3 +47,27 @@ def is_post_eip7002(spec):
4747

4848
def is_post_whisk(spec):
4949
return is_post_fork(spec.fork, WHISK)
50+
51+
52+
def get_spec_for_fork_version(spec, fork_version, phases):
53+
if phases is None:
54+
return spec
55+
for fork in [fork for fork in phases if is_post_fork(spec.fork, fork)]:
56+
if fork == PHASE0:
57+
fork_version_field = 'GENESIS_FORK_VERSION'
58+
else:
59+
fork_version_field = fork.upper() + '_FORK_VERSION'
60+
if fork_version == getattr(spec.config, fork_version_field):
61+
return phases[fork]
62+
raise ValueError("Unknown fork version %s" % fork_version)
63+
64+
65+
def get_next_fork_transition(spec, epoch, phases):
66+
if phases is None:
67+
return None, None
68+
for fork in [fork for fork in phases if PREVIOUS_FORK_OF[fork] == spec.fork]:
69+
assert fork != PHASE0 # PHASE0 does not have previous fork
70+
fork_epoch = getattr(phases[fork].config, fork.upper() + '_FORK_EPOCH')
71+
assert fork_epoch > epoch # Forks through given epoch already applied
72+
return phases[fork], fork_epoch
73+
return None, None # Already at latest fork

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

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
from eth2spec.test.helpers.state import (
2-
transition_to,
1+
from eth2spec.test.helpers.fork_transition import (
2+
transition_across_forks,
33
)
44
from eth2spec.test.helpers.forks import (
55
is_post_capella, is_post_deneb,
@@ -20,14 +20,14 @@ def compute_start_slot_at_next_sync_committee_period(spec, state):
2020
return compute_start_slot_at_sync_committee_period(spec, sync_committee_period + 1)
2121

2222

23-
def get_sync_aggregate(spec, state, num_participants=None, signature_slot=None):
23+
def get_sync_aggregate(spec, state, num_participants=None, signature_slot=None, phases=None):
2424
# By default, the sync committee signs the previous slot
2525
if signature_slot is None:
2626
signature_slot = state.slot + 1
27+
assert signature_slot > state.slot
2728

2829
# Ensure correct sync committee and fork version are selected
29-
signature_state = state.copy()
30-
transition_to(spec, signature_state, signature_slot)
30+
signature_spec, signature_state, _ = transition_across_forks(spec, state, signature_slot, phases)
3131

3232
# Fetch sync committee
3333
committee_indices = compute_committee_indices(signature_state)
@@ -41,12 +41,12 @@ def get_sync_aggregate(spec, state, num_participants=None, signature_slot=None):
4141
# Compute sync aggregate
4242
sync_committee_bits = [True] * num_participants + [False] * (committee_size - num_participants)
4343
sync_committee_signature = compute_aggregate_sync_committee_signature(
44-
spec,
44+
signature_spec,
4545
signature_state,
4646
max(signature_slot, 1) - 1,
4747
committee_indices[:num_participants],
4848
)
49-
sync_aggregate = spec.SyncAggregate(
49+
sync_aggregate = signature_spec.SyncAggregate(
5050
sync_committee_bits=sync_committee_bits,
5151
sync_committee_signature=sync_committee_signature,
5252
)

0 commit comments

Comments
 (0)