Skip to content

Commit 6e5c247

Browse files
authored
tests: add forkchoice attestation processing test vectors (leanEthereum#98)
* tests: add forkchoice attestation processing test vectors * small fix * more pythonic location * wip * fix conflicts * small fix * fix comment
1 parent 5b19a27 commit 6e5c247

5 files changed

Lines changed: 805 additions & 3 deletions

File tree

packages/testing/src/consensus_testing/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
StateTransitionTest,
1010
)
1111
from .test_types import (
12+
AttestationCheck,
1213
AttestationStep,
1314
BaseForkChoiceStep,
1415
BlockSpec,
@@ -41,6 +42,7 @@
4142
"ForkChoiceStep",
4243
"StateExpectation",
4344
"StoreChecks",
45+
"AttestationCheck",
4446
# Type aliases for test function signatures
4547
"StateTransitionTestFiller",
4648
"ForkChoiceTestFiller",

packages/testing/src/consensus_testing/test_types/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,12 @@
1010
ForkChoiceStep,
1111
TickStep,
1212
)
13-
from .store_checks import StoreChecks
13+
from .store_checks import AttestationCheck, StoreChecks
1414

1515
__all__ = [
1616
"StateExpectation",
1717
"StoreChecks",
18+
"AttestationCheck",
1819
"BaseForkChoiceStep",
1920
"BlockSpec",
2021
"TickStep",

packages/testing/src/consensus_testing/test_types/store_checks.py

Lines changed: 102 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,87 @@
11
"""Store checks model for selective validation in fork choice tests."""
22

3-
from typing import TYPE_CHECKING
3+
from typing import TYPE_CHECKING, Literal
44

55
from lean_spec.subspecs.containers.slot import Slot
6-
from lean_spec.types import Bytes32, CamelModel, Uint64
6+
from lean_spec.types import Bytes32, CamelModel, Uint64, ValidatorIndex
77

88
if TYPE_CHECKING:
9+
from lean_spec.subspecs.containers import SignedAttestation
910
from lean_spec.subspecs.forkchoice.store import Store
1011

1112

13+
class AttestationCheck(CamelModel):
14+
"""
15+
Validation checks for a specific validator's attestation.
16+
17+
All fields optional - only check fields explicitly set.
18+
Used to validate attestation content beyond just counting.
19+
"""
20+
21+
validator: ValidatorIndex
22+
"""Which validator's attestation to check."""
23+
24+
attestation_slot: Slot | None = None
25+
"""Expected attestation data slot."""
26+
27+
head_slot: Slot | None = None
28+
"""Expected head checkpoint slot."""
29+
30+
source_slot: Slot | None = None
31+
"""Expected source checkpoint slot."""
32+
33+
target_slot: Slot | None = None
34+
"""Expected target checkpoint slot."""
35+
36+
location: Literal["new", "known"]
37+
"""
38+
Expected attestation location:
39+
- "new" for `latest_new_attestations`
40+
- "known" for `latest_known_attestations`
41+
"""
42+
43+
def validate_attestation(
44+
self, attestation: "SignedAttestation", location: str, step_index: int
45+
) -> None:
46+
"""Validate attestation properties."""
47+
fields_to_check = self.model_fields_set - {"validator", "location"}
48+
49+
for field_name in fields_to_check:
50+
expected = getattr(self, field_name)
51+
52+
if field_name == "attestation_slot":
53+
actual = attestation.message.data.slot
54+
if actual != expected:
55+
raise AssertionError(
56+
f"Step {step_index}: validator {self.validator} {location} "
57+
f"attestation slot = {actual}, expected {expected}"
58+
)
59+
60+
elif field_name == "head_slot":
61+
actual = attestation.message.data.head.slot
62+
if actual != expected:
63+
raise AssertionError(
64+
f"Step {step_index}: validator {self.validator} {location} "
65+
f"head slot = {actual}, expected {expected}"
66+
)
67+
68+
elif field_name == "source_slot":
69+
actual = attestation.message.data.source.slot
70+
if actual != expected:
71+
raise AssertionError(
72+
f"Step {step_index}: validator {self.validator} {location} "
73+
f"source slot = {actual}, expected {expected}"
74+
)
75+
76+
elif field_name == "target_slot":
77+
actual = attestation.message.data.target.slot
78+
if actual != expected:
79+
raise AssertionError(
80+
f"Step {step_index}: validator {self.validator} {location} "
81+
f"target slot = {actual}, expected {expected}"
82+
)
83+
84+
1285
class StoreChecks(CamelModel):
1386
"""
1487
Store state checks for fork choice tests.
@@ -51,6 +124,9 @@ class StoreChecks(CamelModel):
51124
safe_target: Bytes32 | None = None
52125
"""Expected safe target root."""
53126

127+
attestation_checks: list[AttestationCheck] | None = None
128+
"""Optional list of attestation content checks for specific validators."""
129+
54130
def validate_against_store(self, store: "Store", step_index: int) -> None:
55131
"""
56132
Validate these checks against actual Store state.
@@ -137,3 +213,27 @@ def validate_against_store(self, store: "Store", step_index: int) -> None:
137213
f"Step {step_index}: safe_target = 0x{actual_root.hex()}, "
138214
f"expected 0x{expected_value.hex()}"
139215
)
216+
217+
elif field_name == "attestation_checks":
218+
# Validate specific attestation contents
219+
for check in expected_value:
220+
validator_idx = check.validator
221+
222+
# Check attestation location
223+
if check.location == "new":
224+
if validator_idx not in store.latest_new_attestations:
225+
raise AssertionError(
226+
f"Step {step_index}: validator {validator_idx} not found "
227+
f"in latest_new_attestations"
228+
)
229+
attestation = store.latest_new_attestations[validator_idx]
230+
check.validate_attestation(attestation, "in latest_new", step_index)
231+
232+
else: # check.location == "known"
233+
if validator_idx not in store.latest_known_attestations:
234+
raise AssertionError(
235+
f"Step {step_index}: validator {validator_idx} not found "
236+
f"in latest_known_attestations"
237+
)
238+
attestation = store.latest_known_attestations[validator_idx]
239+
check.validate_attestation(attestation, "in latest_known", step_index)
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
"""
2+
Fork choice test vectors for the devnet fork.
3+
4+
This package contains spec test vectors for fork choice behavior.
5+
"""

0 commit comments

Comments
 (0)