Skip to content

refactor(forks): decouple subspecs from forks.lstar (Stage 3 of #686)#698

Merged
tcoratger merged 1 commit into
leanEthereum:mainfrom
tcoratger:refactor/decouple-subspecs-from-fork-stage3
May 2, 2026
Merged

refactor(forks): decouple subspecs from forks.lstar (Stage 3 of #686)#698
tcoratger merged 1 commit into
leanEthereum:mainfrom
tcoratger:refactor/decouple-subspecs-from-fork-stage3

Conversation

@tcoratger
Copy link
Copy Markdown
Collaborator

Summary

Stage 3 of the multi-fork architecture refactor (#686): make src/lean_spec/subspecs/ truly fork-agnostic.

After this PR, no file under src/lean_spec/subspecs/ imports from lean_spec.forks.lstar.*. Subspecs reach fork types through three channels:

  • lean_spec.types for fork-stable primitives (Slot, ValidatorIndex, Checkpoint, plus the newly moved AggregationBits, ValidatorIndices, and VALIDATOR_REGISTRY_LIMIT).
  • lean_spec.forks.protocol for structural Spec*Type protocols (enriched with @property accessors and a shared SpecSSZType base for encode_bytes/decode_bytes). Used in pure-typing surfaces like the Database protocol.
  • lean_spec.forks for re-exports of the active fork's concrete container classes. Used where structural protocols would lose the fidelity needed for concrete forkchoice calls (e.g. Store.on_block(SignedBlock) in subspecs/sync/).

SQLiteDatabase now accepts state_class, block_class, and attestation_data_class via constructor (class-pointer injection) instead of hard-importing forks.lstar containers.

VALIDATOR_REGISTRY_LIMIT moves to lean_spec.types (its natural home — it sizes AggregationBits.LIMIT and ValidatorIndices.LIMIT); subspecs.chain.config re-exports it so existing call sites keep working without churn.

CI guard

A new AST-walk test (tests/lean_spec/forks/test_fork_protocol.py::test_subspecs_do_not_import_concrete_fork) asserts that no file under src/lean_spec/subspecs/ imports from lean_spec.forks.lstar.*. This locks in the property going forward.

Stage 3 checklist

  • subspecs/xmss/ — uses fork-stable types from lean_spec.types.
  • subspecs/storage/Database protocol uses Spec*Type; SQLiteDatabase takes class pointers.
  • subspecs/sync/ — imports Store, SignedBlock, etc. from lean_spec.forks re-exports.
  • subspecs/chain/ — uses fork-stable re-exports.
  • subspecs/validator/ — uses fork-stable re-exports.
  • subspecs/networking/ — uses fork-stable re-exports.
  • subspecs/genesis/ — uses fork-stable re-exports.
  • subspecs/node/node.py — accesses concrete classes via config.fork.*_class and the lean_spec.forks re-exports.
  • CI guard added to assert the property.

Test plan

  • uvx tox -e all-checks (ruff check + format + ty + codespell + mdformat) green.
  • uv run pytest tests/lean_spec/ — 2208 unit tests pass.
  • uv run pytest tests/lean_spec/forks/ — 18 fork tests pass, including the new CI guard.
  • CI runs the consensus filler against the new structure.

🤖 Generated with Claude Code

…thereum#686)

Subspecs no longer hard-import any concrete fork module. They reach
fork-specific types through three channels: fork-stable types in
`lean_spec.types`, structural protocols in `lean_spec.forks.protocol`,
and re-exports of the active fork from `lean_spec.forks`. Concrete
class pointers are injected through `ForkProtocol` (`fork.state_class`,
`fork.block_class`, ...) for subspecs that construct or decode SSZ
instances.

`AggregationBits`, `ValidatorIndices`, and `VALIDATOR_REGISTRY_LIMIT`
move into `lean_spec.types`; `subspecs.chain.config` re-exports the
limit so existing call sites keep working.

`SQLiteDatabase` now takes `state_class`, `block_class`, and
`attestation_data_class` as constructor arguments instead of
hard-importing `forks.lstar` containers.

A new AST-walk test (`test_subspecs_do_not_import_concrete_fork`)
guards the property going forward by asserting no file under
`src/lean_spec/subspecs/` imports from `lean_spec.forks.lstar.*`.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@tcoratger tcoratger merged commit 4d1816d into leanEthereum:main May 2, 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