fix: update spec-test runners for the latest leanSpec fixture schema#429
Conversation
CI now downloads the latest leanSpec fixtures release (#385), and the current release includes schema changes the test runners did not yet understand, leaving main's Test job red: - Block steps carry a tickToSlot flag (default true). The early-arrival tests set it to false to deliver a block ahead of the store clock, so the forkchoice runner and the Hive test driver now only advance the clock to the block's slot when the flag is set. - Rejection expectations were renamed from expectException to rejectionReason; the verify_signatures and state_transition fixture types accept both spellings. - The SSZ fixture format string was renamed from ssz to ssz_test; the runner accepts both. No consensus-code changes: ethlambda already imports early blocks and rejects the invalid signatures these fixtures cover; only the harness misread the new encoding.
🤖 Kimi Code ReviewReview Summary These are test-harness improvements to handle spec fixture format changes and early-arrival block scenarios. The changes are correct, well-documented, and maintain backward compatibility. Detailed Feedback
Consensus Safety Check
No blocking issues found. The PR is ready for merge. Automated review by Kimi (Moonshot AI) · kimi-k2.5 · custom prompt |
🤖 Codex Code ReviewNo findings in the changed code. The patch is narrow and the behavior change is sensible: I could not run the targeted Rust tests in this environment because Automated review by OpenAI Codex · gpt-5.4 · custom prompt |
Greptile SummaryThis PR updates three spec-test runners and two fixture-type definitions to handle schema changes introduced by the latest leanSpec fixture release, without touching any consensus logic. All failures on
Confidence Score: 5/5All changes are confined to test runners and fixture deserialization types; no consensus, store, or production code paths are modified. Every change is a backward-compatible extension: the new No files require special attention.
|
| Filename | Overview |
|---|---|
| crates/common/test-fixtures/src/fork_choice.rs | Adds tick_to_slot: bool to ForkChoiceStep with default = "default_true", correctly reusing the existing helper; default preserves all current test behaviour. |
| crates/blockchain/tests/forkchoice_spectests.rs | Guards on_tick behind step.tick_to_slot; block import and outcome assertion are unaffected when the flag is false. |
| crates/net/rpc/src/test_driver.rs | Mirrors the spec-test runner change: on_tick is skipped when tick_to_slot is false; no other logic is touched. |
| crates/common/test-fixtures/src/state_transition.rs | Adds alias = "rejectionReason" to the already-default-annotated expect_exception field; clean backward-compatible addition. |
| crates/common/test-fixtures/src/verify_signatures.rs | Adds default and alias = "rejectionReason" to expect_exception; default is technically redundant for Option<T> in serde_json but makes intent explicit. |
| crates/common/types/tests/ssz_spectests.rs | Replaces single-string constant with a two-element slice; format check updated to SUPPORTED_FIXTURE_FORMATS.contains(…) with an improved error message. |
Flowchart
%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[block step received] --> B{tick_to_slot?}
B -- true default --> C[on_tick to block slot]
C --> D[on_block_without_verification]
B -- false early-arrival test --> D
D --> E{result.is_ok?}
E -- yes --> F[assert valid == true]
E -- no --> G[assert valid == false]
H[fixture field: expectException or rejectionReason] --> I[serde alias: both accepted]
J[SSZ fixture_format field] --> K{format value?}
K -- ssz --> L[accepted]
K -- ssz_test --> L
K -- other --> M[error: unsupported format]
Reviews (1): Last reviewed commit: "Update spec-test runners for the latest ..." | Re-trigger Greptile
🤖 Claude Code ReviewHere is the full review: PR Review: fix: update spec-test runners for the latest leanSpec fixture schemaScope: Test harness / fixture deserialization only. No consensus logic, state transition, fork choice, or cryptography code is modified. This simplifies the review considerably. Correctness
The design is correct. Both call sites ( serde alias for This fixes a silent correctness failure, not just a deserialization error. Without the alias:
The Minor note: SSZ format string (ssz_spectests.rs) The One pre-existing behavior preserved by this PR: the ConsistencyThe Minor ObservationThe doc comment at SummaryThe changes are correct, backward-compatible, and well-scoped. The most important fix is the serde alias that prevents silent test-correctness failures on rejection-case fixtures. LGTM. Automated review by Claude (Anthropic) · sonnet · custom prompt |
leanSpec now generates most vectors with placeholder aggregation proofs
("MOCKED-AGGREGATION-PROOF" sentinel bytes) so filling no longer pays
for recursive SNARK merges; a top-level proofSetting field marks the
regime (0 = mocked, must not be verified; 1 = real and valid; 2 = real
and invalid). Vectors that actually exercise proof validity opt back
into real crypto.
Parse proofSetting (defaulting to real-and-valid for older fixtures)
and route gossipAggregatedAttestation steps of mocked vectors through a
new on_gossip_aggregated_attestation_without_verification, mirroring
the existing on_block/on_block_without_verification split. Production
paths are unchanged and always verify.
| /// Newer leanSpec releases name the format `ssz_test`; the pinned-commit | ||
| /// fixtures still use `ssz`. Accept both. | ||
| const SUPPORTED_FIXTURE_FORMATS: &[&str] = &["ssz", "ssz_test"]; |
There was a problem hiding this comment.
If newer leanSpec releases use ssz_test, we should only support that
| pub fn on_gossip_aggregated_attestation_without_verification( | ||
| store: &mut Store, | ||
| aggregated: SignedAggregatedAttestation, | ||
| ) -> Result<(), StoreError> { | ||
| on_gossip_aggregated_attestation_core(store, aggregated, false) | ||
| } |
There was a problem hiding this comment.
There should be a better way to do this.
The ssz spelling was renamed to ssz_test in leanSpec's fixture consistency pass (leanSpec #864, merged 2026-06-06) and CI always downloads the latest release, so the old name can never appear again. Addresses review feedback.
Motivation
#385 switched CI to download the latest leanSpec fixtures release instead of generating them from a pinned commit. The current release carries fixture-schema changes the test runners don't understand yet, so the Test job on
mainfails.Note: leanSpec's release is a single rolling
latesttag — it was republished mid-review (2026-06-10 17:31 UTC), which is what the second commit addresses.Description
Runner/harness-only changes — no consensus behavior is touched, and ethlambda already matches the spec in every affected case:
tickToSlot(fork-choice block steps): new flag, defaulttrue. The early-arrival tests set it tofalseto deliver a block ahead of the store clock and assert the clock doesn't move. The forkchoice spectest runner and the Hive test driver now only tick to the block's slot when the flag is set.rejectionReason: leanSpec renamedexpectException. Theverify_signaturesandstate_transitionfixture types accept both spellings via a serde alias.ssz_test: the SSZ fixture format string was renamed fromssz; the runner accepts both.proofSetting/ mocked proofs: leanSpec now fills most vectors with placeholder aggregation proofs (MOCKED-AGGREGATION-PROOFsentinel) instead of paying for recursive SNARK merges, marking the regime in a top-levelproofSettingfield (0 = mocked, must not be verified; 1 = real and valid; 2 = real and invalid). The forkchoice runner routes mocked vectors through a newon_gossip_aggregated_attestation_without_verification(mirroring theon_block/on_block_without_verificationsplit). Production paths always verify.Known follow-ups (out of scope):
proofSettingyet; Hive runs against mocked-proof fixtures will need a protocol addition.latestrelease means any upstream republish can breakmain's CI at any time; pinning the fixtures tarball SHA256 would restore reproducibility.How to Test
Locally verified against the 2026-06-10 17:31 UTC fixtures drop: full
cargo test --workspace --releasepasses (108 forkchoice, 118 SSZ, 67 STF, all remaining suites green).