Skip to content

Commit b63e8d1

Browse files
tcoratgerclaude
andauthored
refactor(testing): delete dead fork machinery (leanEthereum#851)
With a single fork, most of the fork scaffolding had zero callers: - the fork's state accessor was never called anywhere - the ignore flag machinery (class keyword, classvar, accessor) was always False; no fork ever opted out - the valid_from and valid_at markers were registered and filtered but no test uses them; only valid_until exists in the tree - three of the four ordering operators existed solely for those unused markers Changes: - the registry class with its module dir() scan is replaced by a literal name-to-fork dict in the consensus forks package; lookups stay case-insensitive - the fork base keeps name, repr, and the older-or-equal comparison that the valid_until marker consumes; the rest of the ordering algebra and the ignore machinery are gone - the marker check in the filler handles only valid_until - the unused fork type alias and metaclass re-exports are dropped When a second fork lands, the removed pieces can be reintroduced against real usage. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 8c9378a commit b63e8d1

6 files changed

Lines changed: 20 additions & 152 deletions

File tree

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,14 @@
11
"""Fork definitions for consensus layer testing."""
22

3-
from typing import Type
3+
from framework.forks import BaseFork
44

5-
from framework.forks import BaseFork, BaseForkMeta, ForkRegistry
6-
7-
from consensus_testing.forks import forks as _forks_module
85
from consensus_testing.forks.forks import Lstar
96

10-
Fork = Type[BaseFork]
11-
12-
registry = ForkRegistry(_forks_module)
7+
FORKS_BY_NAME: dict[str, type[BaseFork]] = {"lstar": Lstar}
8+
"""Registered consensus forks, keyed by lowercase fork name."""
139

1410
__all__ = [
1511
"BaseFork",
16-
"BaseForkMeta",
17-
"Fork",
12+
"FORKS_BY_NAME",
1813
"Lstar",
19-
"registry",
2014
]

packages/testing/src/consensus_testing/forks/forks.py

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,3 @@ def name(cls) -> str:
1717
def spec_class(cls) -> type[LstarSpec]:
1818
"""Return the ForkProtocol implementation for this fork."""
1919
return LstarSpec
20-
21-
@classmethod
22-
def state_class(cls) -> type:
23-
"""Return the State container class for this fork."""
24-
return LstarSpec.state_class
Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,7 @@
1-
"""Base fork infrastructure for Ethereum testing."""
1+
"""Base fork infrastructure for spec test generation."""
22

3-
from framework.forks.base import BaseFork, BaseForkMeta
4-
from framework.forks.registry import ForkRegistry
3+
from framework.forks.base import BaseFork
54

65
__all__ = [
76
"BaseFork",
8-
"BaseForkMeta",
9-
"ForkRegistry",
107
]
Lines changed: 7 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,14 @@
1-
"""Base fork class for Ethereum layer testing."""
1+
"""Base fork class for spec test generation."""
22

33
from abc import ABC, ABCMeta, abstractmethod
4-
from typing import ClassVar
54

65

76
class BaseForkMeta(ABCMeta):
87
"""
9-
Metaclass for BaseFork enabling fork comparisons via inheritance.
8+
Metaclass for BaseFork enabling fork ordering via inheritance.
109
11-
Fork comparisons work by checking subclass relationships.
12-
For example, if ForkB inherits from ForkA, then ForkA < ForkB.
13-
14-
This metaclass is shared across both consensus and execution layers,
15-
allowing consistent fork comparison logic regardless of layer.
10+
Fork ordering works by checking subclass relationships.
11+
For example, if ForkB inherits from ForkA, then ForkA precedes ForkB.
1612
"""
1713

1814
@abstractmethod
@@ -24,57 +20,19 @@ def __repr__(cls) -> str:
2420
"""Print the name of the fork, instead of the class."""
2521
return cls.name()
2622

27-
def __gt__(cls, other: "BaseForkMeta") -> bool:
28-
"""Check if this fork is newer than another (cls > other)."""
29-
return cls is not other and BaseForkMeta._is_subclass_of(cls, other)
30-
31-
def __ge__(cls, other: "BaseForkMeta") -> bool:
32-
"""Check if this fork is newer or equal to another (cls >= other)."""
33-
return cls is other or BaseForkMeta._is_subclass_of(cls, other)
34-
35-
def __lt__(cls, other: "BaseForkMeta") -> bool:
36-
"""Check if this fork is older than another (cls < other)."""
37-
return cls is not other and BaseForkMeta._is_subclass_of(other, cls)
38-
3923
def __le__(cls, other: "BaseForkMeta") -> bool:
4024
"""Check if this fork is older or equal to another (cls <= other)."""
41-
return cls is other or BaseForkMeta._is_subclass_of(other, cls)
42-
43-
@staticmethod
44-
def _is_subclass_of(a: "BaseForkMeta", b: "BaseForkMeta") -> bool:
45-
"""Check if fork `a` is a subclass of fork `b`."""
46-
return issubclass(a, b)
25+
return cls is other or issubclass(other, cls)
4726

4827

4928
class BaseFork(ABC, metaclass=BaseForkMeta):
5029
"""
51-
Base class for Ethereum layer forks.
30+
Base class for spec test forks.
5231
53-
Each fork represents a specific version of the protocol (consensus or execution).
32+
Each fork represents a specific version of the protocol.
5433
Forks form an inheritance hierarchy where newer forks inherit from older ones.
55-
56-
This base class is shared across both consensus and execution layers, but each
57-
layer will define its own fork hierarchy with different fork names and properties.
5834
"""
5935

60-
# Fork metadata
61-
_ignore: ClassVar[bool] = False
62-
"""If True, this fork will be excluded from the primary fork set."""
63-
64-
def __init_subclass__(
65-
cls,
66-
*,
67-
ignore: bool = False,
68-
) -> None:
69-
"""
70-
Initialize fork subclass with metadata.
71-
72-
Args:
73-
ignore: If True, exclude this fork from ALL_FORKS.
74-
"""
75-
super().__init_subclass__()
76-
cls._ignore = ignore
77-
7836
@classmethod
7937
@abstractmethod
8038
def name(cls) -> str:
@@ -85,8 +43,3 @@ def name(cls) -> str:
8543
This is used in the 'network' field of generated fixtures.
8644
"""
8745
pass
88-
89-
@classmethod
90-
def ignore(cls) -> bool:
91-
"""Return whether this fork should be ignored in test generation."""
92-
return cls._ignore

packages/testing/src/framework/forks/registry.py

Lines changed: 0 additions & 35 deletions
This file was deleted.

packages/testing/src/framework/pytest_plugins/filler.py

Lines changed: 7 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
import pytest
1111
from consensus_testing import generate_pre_state
12-
from consensus_testing.forks import registry
12+
from consensus_testing.forks import FORKS_BY_NAME
1313
from consensus_testing.test_fixtures import (
1414
ApiEndpointTest,
1515
ForkChoiceTest,
@@ -182,25 +182,17 @@ def pytest_ignore_collect(collection_path: Path) -> bool | None:
182182
def pytest_configure(config: pytest.Config) -> None:
183183
"""Setup the fixture generation session."""
184184
# Register fork validity markers
185-
config.addinivalue_line(
186-
"markers",
187-
"valid_from(fork): specifies from which fork a test case is valid",
188-
)
189185
config.addinivalue_line(
190186
"markers",
191187
"valid_until(fork): specifies until which fork a test case is valid",
192188
)
193-
config.addinivalue_line(
194-
"markers",
195-
"valid_at(fork): specifies at which fork a test case is valid",
196-
)
197189

198190
# Get options
199191
output_directory = Path(config.getoption("--output"))
200192
fork_name = config.getoption("--fork")
201193
clean = config.getoption("--clean")
202194

203-
available_fork_names = sorted(fork.name() for fork in registry.forks)
195+
available_fork_names = sorted(fork.name() for fork in FORKS_BY_NAME.values())
204196

205197
# Validate fork
206198
if not fork_name:
@@ -211,7 +203,7 @@ def pytest_configure(config: pytest.Config) -> None:
211203
)
212204
pytest.exit("Missing required --fork option.", returncode=pytest.ExitCode.USAGE_ERROR)
213205

214-
fork_class = registry.get_fork_by_name(fork_name)
206+
fork_class = FORKS_BY_NAME.get(fork_name.lower())
215207
if fork_class is None:
216208
print(
217209
f"Error: Unsupported fork: {fork_name}\n",
@@ -279,49 +271,21 @@ def _check_markers_valid_for_fork(
279271
280272
Shared logic for both collection-time and parametrization-time fork filtering.
281273
"""
282-
has_valid_from = False
283274
has_valid_until = False
284-
has_valid_at = False
285-
286-
valid_from_forks = []
287275
valid_until_forks = []
288-
valid_at_forks = []
289276

290277
for marker in markers:
291-
if marker.name == "valid_from":
292-
has_valid_from = True
293-
for fork_name in marker.args:
294-
target_fork = registry.get_fork_by_name(fork_name)
295-
if target_fork:
296-
valid_from_forks.append(target_fork)
297-
elif marker.name == "valid_until":
278+
if marker.name == "valid_until":
298279
has_valid_until = True
299280
for fork_name in marker.args:
300-
target_fork = registry.get_fork_by_name(fork_name)
281+
target_fork = FORKS_BY_NAME.get(fork_name.lower())
301282
if target_fork:
302283
valid_until_forks.append(target_fork)
303-
elif marker.name == "valid_at":
304-
has_valid_at = True
305-
for fork_name in marker.args:
306-
target_fork = registry.get_fork_by_name(fork_name)
307-
if target_fork:
308-
valid_at_forks.append(target_fork)
309284

310-
if not (has_valid_from or has_valid_until or has_valid_at):
285+
if not has_valid_until:
311286
return True
312287

313-
if has_valid_at:
314-
return fork_class in valid_at_forks
315-
316-
from_valid = True
317-
if has_valid_from:
318-
from_valid = any(fork_class >= from_fork for from_fork in valid_from_forks)
319-
320-
until_valid = True
321-
if has_valid_until:
322-
until_valid = any(fork_class <= until_fork for until_fork in valid_until_forks)
323-
324-
return from_valid and until_valid
288+
return any(fork_class <= until_fork for until_fork in valid_until_forks)
325289

326290

327291
def pytest_sessionfinish(session: pytest.Session, exitstatus: int) -> None:

0 commit comments

Comments
 (0)