refactor(forks): tighten ForkProtocol surface (Stage 1 of #686)#694
Merged
tcoratger merged 3 commits intoApr 30, 2026
Merged
Conversation
Drop Any from ForkProtocol method signatures. Replace with fork-stable primitives (Uint64) and structural protocols (SpecStateType, SpecBlockType, SpecStoreType). Drop ClassVar from state_class/block_class/store_class so subclasses can narrow them under pyright/ty invariance rules. Rename NETWORK_NAME to GOSSIP_DIGEST: the field already serves the gossipsub fork-digest role. Remove the None-fork fallback in generate_pre_state. Every call now dispatches through fork.generate_genesis. The pre pytest fixture threads fork from the framework's fork fixture. Refs leanEthereum#686 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
object was too loose for the structural validators parameter on generate_genesis. SSZList is the fork-stable concrete base; the element type stays generic because each fork owns its own Validator class. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
38 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Part of #686 — Stage 1 only. Other stages (2–8) remain in scope of the tracking issue.
Summary
Tightens the
ForkProtocolsurface so subclass-and-narrow inheritance ("Vision B") works under pyright/tyinvariance rules, and removes the silent fork bypass in pre-state generation.Type tightening
AnyfromForkProtocolmethod signatures. Replace withUint64and structural Protocols.SpecBlockTypeProtocol soblock_classis no longer typedtype(i.e.type[Any]).ClassVarfromstate_class/block_class/store_class.ClassVartriggers the type checker's invariance rule and would block a futureDevnet5Spec(LstarSpec)from declaringstate_class: type[Devnet5State] = Devnet5State.ClassVarstays on true constants (NAME,VERSION,GOSSIP_DIGEST,previous).NETWORK_NAME→GOSSIP_DIGEST. The field already served the gossipsub fork-digest role; the rename matches the intent.generate_pre_statefork fallbackfork: ForkProtocol | None = Nonebranch that calledState.generate_genesis(...)directly whenforkwasNone. Every call now dispatches throughfork.generate_genesis(...).prepytest fixture (packages/testing/.../filler.py) now requests the framework'sforkfixture and threadsfork.spec_class()()through.sync.py,api_endpoint.py) passLstarSpec()explicitly, consistent with their existing lstar coupling.Honest casts at concrete-fork boundaries
fork.generate_genesis(...)andfork.create_store(...)return Protocol-typed values (SpecStateType/SpecStoreType). The two callers that need narrow access (__main__.py,node.py) usecast(State, ...)/cast(Store, ...)at the boundary — no# type: ignoreneeded. The lstar fork class deliberately does not override these methods to "narrow" the return type, since doing so would require# type: ignore[arg-type]to bridge the LSP-widened input back to the concrete narrow signature. A clean cast at the boundary is more honest than an ignore in the spec class.Stage 1 checklist (from #686)
AnyinForkProtocolmethod signatures with fork-stable primitives and structural protocols.SpecBlockTypeProtocol soblock_classstops being typedtype.ClassVarfromstate_class/block_class/store_class.GOSSIP_DIGEST: ClassVar[str]; route consumers throughfork.GOSSIP_DIGEST.generate_pre_statefork fallback. Thread fork through theprepytest fixture.The remaining Stage 1 items (use
DEFAULT_REGISTRYin__main__.py, addprevious, renameSpecRunner→ForkRegistry, makeupgrade_stateabstract, direct bindings ondevnet5/spec.py) were already merged in earlier PRs.Test plan
uvx tox -e all-checkspasses (ruff, format, ty, codespell, mdformat).uv run pytest --no-covpasses.uv run fill --fork=lstar --clean -n autogenerates fixtures.🤖 Generated with Claude Code