Skip to content

refactor(forks): make Store generic over StateT, BlockT (Stage 5 of #686)#705

Merged
tcoratger merged 1 commit intoleanEthereum:mainfrom
tcoratger:refactor/generic-store-stage5
May 3, 2026
Merged

refactor(forks): make Store generic over StateT, BlockT (Stage 5 of #686)#705
tcoratger merged 1 commit intoleanEthereum:mainfrom
tcoratger:refactor/generic-store-stage5

Conversation

@tcoratger
Copy link
Copy Markdown
Collaborator

@tcoratger tcoratger commented May 3, 2026

Summary

Per the multi-fork roadmap, Stage 5 makes Store generic so future forks can specialize their State / Block with a typedef instead of copying the class.

  • Store(StrictBaseModel, Generic[StateT, BlockT]) lives in forks/lstar/store.py. TypeVars bind to Container so Pydantic can resolve real schemas at parameterization time.
  • LstarStore = Store[State, Block] is the concrete binding for the lstar fork (defined in forks/lstar/spec.py). LstarSpec.store_class and create_store are typed against it.
  • BlockLookup is dropped — single-line alias used in two helpers, not worth the indirection.
  • Public from lean_spec.forks import Store resolves to LstarStore, so every existing call site keeps working unchanged. LstarStore is also exported under its canonical name.
  • Mutable Store defaults move from = {} to Field(default_factory=dict) to silence Pydantic's generic-default warning.

The third Stage 5 item (a Devnet5Store typedef showing the pattern) is dropped because devnet5 was unified back into lstar.

Design provenance

Design reviewed with the py-architect and doc-writer agents:

  • Architect picked Container-bounded TypeVars over the structural SpecStateType / SpecBlockType protocols — Pydantic v2 generic models need a concrete class at specialization time.
  • Doc-writer kept the existing Store class docstring; the Generic[...] clause documents itself. Only the new TypeVars get one-line role docstrings.

Test plan

  • uvx tox -e all-checks — ruff, format, ty, codespell, mdformat all pass
  • pytest tests -n auto — 3291 passed
  • Runtime sanity: Store is LstarStore is True; instantiation produces Store[State, Block] with (State, Block) resolved in __pydantic_generic_metadata__

🤖 Generated with Claude Code

…eanEthereum#686)

Per the multi-fork roadmap, Store now declares its State and Block types as
type parameters so future forks can specialize them with a typedef instead
of copy-pasting the whole class.

Design (per the py-architect agent):

- `Store(StrictBaseModel, Generic[StateT, BlockT])` in forks/lstar/store.py.
  StateT and BlockT are bound to Container so Pydantic can build a real
  schema at parameterization time; structural protocols would not.
- `LstarStore = Store[State, Block]` in forks/lstar/spec.py is the concrete
  binding owned by the lstar fork. `LstarSpec.store_class` and
  `create_store` are typed against it.
- `BlockLookup` is dropped — it was a single-line alias used in two helper
  signatures that read just as clearly as `dict[Bytes32, Block]`.
- Public `from lean_spec.forks import Store` resolves to `LstarStore`, so
  every existing call site keeps working without change. `LstarStore` is
  also exported under its canonical name for callers that prefer to be
  explicit.
- Mutable Store defaults move from bare `= {}` to `Field(default_factory=
  dict)` to silence the Pydantic generic-default warning ty raised
  intermittently and to keep the schema honest.

The third Stage 5 item (a `Devnet5Store` typedef demonstrating the pattern)
is dropped because devnet5 was unified back into lstar.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@tcoratger tcoratger merged commit a9c8750 into leanEthereum:main May 3, 2026
13 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant