Skip to content

feat(l1): bump zkevm EF-tests fixtures to v0.3.3 and extend stateless witness coverage to all for_amsterdam tests#6527

Merged
avilagaston9 merged 8 commits into
mainfrom
feat/l1-ef-tests-bump-zkevm-fixtures-v0.3.3
May 6, 2026
Merged

feat(l1): bump zkevm EF-tests fixtures to v0.3.3 and extend stateless witness coverage to all for_amsterdam tests#6527
avilagaston9 merged 8 commits into
mainfrom
feat/l1-ef-tests-bump-zkevm-fixtures-v0.3.3

Conversation

@avilagaston9
Copy link
Copy Markdown
Contributor

@avilagaston9 avilagaston9 commented Apr 24, 2026

Motivation

zkevm@v0.3.3 ships executionWitness on every for_amsterdam fixture, but the Makefile
only extracts eip8025_optional_proofs — leaving ~2670 witnessed fixtures unused by the
stateless path.

Description

  • Bump .fixtures_url_zkevm to zkevm@v0.3.3 (same bal@v5.6.1 base).
  • Widen zkevm-vectors to extract all of for_amsterdam, overlaying the non-witness
    bal@v5.6.1 JSONs so every fixture runs through run_stateless_from_fixture.
  • Parse statelessOutputBytes to honor the valid byte at offset 32: both
    (valid=1, Ok) and (valid=0, Err) now count as pass.
  • Move stateless-specific skips into a feature-gated EXTRA_SKIPS. 9 validation_*
    fixtures skipped pending follow-up — see below.

Follow-up

9 skipped validation_* tests will be re-enabled in a separate PR: drop malformed entries
lazily in witness conversion, and error on missing bytecode / discontinuous header chains
during stateless execution.

How to test

make -C tooling/ef_tests/blockchain download-test-vectors
make -C tooling/ef_tests/blockchain test-stateless

Expected: 8720 passed, ~160s. test-levm unchanged.

Checklist

  • Updated STORE_SCHEMA_VERSION — N/A

…5.6.1

base, so it lands cleanly on main) and widen the Makefile zkevm-vectors
extraction from just eip8025_optional_proofs to the whole for_amsterdam
tree. This lifts witness-based stateless coverage from the ~93 eip8025
fixtures to all 2763 for_amsterdam fixtures, since every zkevm fixture
now carries executionWitness.

Order the zkevm extraction after amsterdam-vectors so its witness-bearing
JSONs overlay the non-witness copies produced by bal@v5.6.1, giving us
the "free extra checks" the EEST maintainers suggested.

Teach run_stateless_from_fixture about the zkevm output format. The
fixture's statelessOutputBytes packs
  new_payload_request_root (32 B) || valid (1 B) || padding,
so byte 32 is the expected validity marker. parse_expected_valid_flag
decodes it and the outcome match now accepts two cases as success:
valid=1 with Ok and valid=0 with Err (the new tolerance/rejection tests
rely on the latter). Without this, every zkevm@v0.3.3 "invalid
executionWitness" test would fail with an inverted error.

Refactor the skip list in tests/all.rs so prover/stateless extras are
feature-gated instead of living in SKIPPED_BASE. Add a new
#[cfg(feature = "stateless")] EXTRA_SKIPS group covering nine
validation_* tests the v0.3.3 bundle exposes: four "tolerance" cases
(valid=1) where RpcExecutionWitness::into_execution_witness eagerly
rejects entries the execution path never touches, and five "rejection"
cases (valid=0) where our stateless path runs clean instead of
noticing a missing code or ancestor entry. Both groups have TODOs
pointing at the real follow-up work (lazy witness parsing and
completeness checks in the guest program).

End state: test-stateless goes from 16 failures to 8720 passed /
0 failed / 9 skipped. test-levm behavior is unchanged.
@github-actions github-actions Bot added the L1 Ethereum client label Apr 24, 2026
@avilagaston9 avilagaston9 marked this pull request as ready for review April 27, 2026 20:20
@avilagaston9 avilagaston9 requested a review from a team as a code owner April 27, 2026 20:20
Copilot AI review requested due to automatic review settings April 27, 2026 20:20
@greptile-apps
Copy link
Copy Markdown

greptile-apps Bot commented Apr 27, 2026

Greptile Summary

This PR bumps the zkevm EF-test fixtures from v0.3.0 to v0.3.3, widens the Makefile extraction from a single subdirectory to the full for_amsterdam tree, and extends the stateless test runner to honour the valid byte in statelessOutputBytes — allowing both expected-pass and expected-rejection fixtures to count as test passes. Nine known-broken validation_* tests are explicitly skipped with clear follow-up notes.

Confidence Score: 4/5

Safe to merge; the only finding is a P2 edge-case fallback in the validity-byte parser that is unlikely to affect real fixtures.

All P0/P1 paths look correct: the hex byte extraction (chars 64..66 = byte 32) is accurate, the match on (expected_valid, outcome) covers all four arms, the Makefile overlay order is correct, and the feature-gated EXTRA_SKIPS block is properly exhaustive. The single concern is a P2 silent-fallback when statelessOutputBytes is present but too short to contain the valid byte.

tooling/ef_tests/blockchain/test_runner.rs — the parse_expected_valid_flag fallback behaviour for truncated byte strings.

Important Files Changed

Filename Overview
tooling/ef_tests/blockchain/.fixtures_url_zkevm Bumps zkevm fixture URL from v0.3.0 to v0.3.3 — single-line version pin change.
tooling/ef_tests/blockchain/Makefile Adds amsterdam-vectors as a prerequisite of zkevm-vectors and widens the extracted path from eip8025_optional_proofs to the full for_amsterdam tree; overlay order is correct and phony-target deduplication prevents double extraction.
tooling/ef_tests/blockchain/test_runner.rs Adds parse_expected_valid_flag to extract the validity byte from statelessOutputBytes and updates the stateless outcome matching logic to handle both pass (valid=1) and expected-rejection (valid=0) cases; the fallback for absent bytes is correct but a truncated-but-present string silently defaults to expected_valid = true.
tooling/ef_tests/blockchain/tests/all.rs Adds a feature-gated EXTRA_SKIPS block for the stateless feature covering 9 known-broken validation fixtures (4 tolerance + 5 rejection), and correctly tightens the fallback empty-skips guard to not(any(sp1, stateless)).

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[run_stateless_from_fixture] --> B{block has executionWitness?}
    B -- No --> NEXT[next block]
    B -- Yes --> C[read statelessOutputBytes]
    C --> D{bytes present?}
    D -- No --> E[expected_valid = true]
    D -- Yes --> F[parse_expected_valid_flag\nbyte index 32 of hex string]
    F -- parse ok --> G[expected_valid = b != 0]
    F -- parse fails / too short --> E
    E & G --> H[run stateless execution\nRpcExecutionWitness → ProgramInput]
    H --> I{outcome}
    I -- Ok --> J{expected_valid?}
    I -- Err --> K{expected_valid?}
    J -- true --> PASS[✅ pass]
    J -- false --> FAIL2[❌ expected failure but succeeded]
    K -- false --> PASS
    K -- true --> FAIL1[❌ expected success but failed]
Loading
Prompt To Fix All With AI
This is a comment left during a code review.
Path: tooling/ef_tests/blockchain/test_runner.rs
Line: 606-610

Comment:
**Silent `true` fallback on truncated `statelessOutputBytes`**

`and_then(parse_expected_valid_flag).unwrap_or(true)` treats a present-but-too-short hex string (< 66 chars after stripping `0x`) identically to an absent field. If a fixture ships a `statelessOutputBytes` that is exactly 32 bytes (64 hex chars) — omitting the `valid` byte — `get(64..66)` returns `None` and the test silently runs as "expected to succeed" instead of surfacing the ambiguous fixture. A targeted `None`-return for the case where bytes are present but the string is too short would make the failure explicit rather than silent.

The existing code already handles this correctly at the call site (`unwrap_or(true)`) for the absent-field case; the concern is that a malformed fixture with a truncated byte string would be silently treated as "expected valid" rather than triggering a parse warning.

How can I resolve this? If you propose a fix, please make it concise.

Reviews (1): Last reviewed commit: "Merge branch 'main' into feat/l1-ef-test..." | Re-trigger Greptile

Comment on lines +606 to +610
fn parse_expected_valid_flag(hex: &str) -> Option<bool> {
let trimmed = hex.strip_prefix("0x").unwrap_or(hex);
let byte_hex = trimmed.get(64..66)?;
u8::from_str_radix(byte_hex, 16).ok().map(|b| b != 0)
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Silent true fallback on truncated statelessOutputBytes

and_then(parse_expected_valid_flag).unwrap_or(true) treats a present-but-too-short hex string (< 66 chars after stripping 0x) identically to an absent field. If a fixture ships a statelessOutputBytes that is exactly 32 bytes (64 hex chars) — omitting the valid byte — get(64..66) returns None and the test silently runs as "expected to succeed" instead of surfacing the ambiguous fixture. A targeted None-return for the case where bytes are present but the string is too short would make the failure explicit rather than silent.

The existing code already handles this correctly at the call site (unwrap_or(true)) for the absent-field case; the concern is that a malformed fixture with a truncated byte string would be silently treated as "expected valid" rather than triggering a parse warning.

Prompt To Fix With AI
This is a comment left during a code review.
Path: tooling/ef_tests/blockchain/test_runner.rs
Line: 606-610

Comment:
**Silent `true` fallback on truncated `statelessOutputBytes`**

`and_then(parse_expected_valid_flag).unwrap_or(true)` treats a present-but-too-short hex string (< 66 chars after stripping `0x`) identically to an absent field. If a fixture ships a `statelessOutputBytes` that is exactly 32 bytes (64 hex chars) — omitting the `valid` byte — `get(64..66)` returns `None` and the test silently runs as "expected to succeed" instead of surfacing the ambiguous fixture. A targeted `None`-return for the case where bytes are present but the string is too short would make the failure explicit rather than silent.

The existing code already handles this correctly at the call site (`unwrap_or(true)`) for the absent-field case; the concern is that a malformed fixture with a truncated byte string would be silently treated as "expected valid" rather than triggering a parse warning.

How can I resolve this? If you propose a fix, please make it concise.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in 5a597e6 — parse_expected_valid_flag now returns Result<bool, String>. Truncated input, non-hex bytes, and validity bytes other than 0x00/0x01 all become hard errors at the call site.

@github-actions
Copy link
Copy Markdown

🤖 Claude Code Review

Now I have enough context to write a thorough review.


PR #6527 Review — Bump zkevm EF-tests to v0.3.3 and widen stateless witness coverage

Overview

This PR expands stateless test coverage from ~93 (eip8025_optional_proofs) to all 2763 for_amsterdam fixtures by bumping the zkevm fixture pin to v0.3.3 and widening the Makefile extraction. It also adds proper handling of the statelessOutputBytes validity flag so both "expected-pass" and "expected-fail" fixture outcomes are tested correctly.


Makefile

Overlay ordering is implicit and fragile

zkevm-vectors: $(ZKEVM_ARTIFACT) $(SPECTEST_VECTORS_DIR) amsterdam-vectors
    tar -xzf $(ZKEVM_ARTIFACT) --strip-components=2 -C $(SPECTEST_VECTORS_DIR) fixtures/blockchain_tests/for_amsterdam

The correctness of this target depends entirely on amsterdam-vectors running first, so the zkevm tar can overwrite those files with witness-enriched versions. This is an important invariant for future maintainers — a one-line comment would prevent confusion when someone bumps fixtures again and forgets the overlay dependency:

# Run amsterdam-vectors first so zkevm can overlay witness-enriched JSONs on top of the base fixtures.
zkevm-vectors: $(ZKEVM_ARTIFACT) $(SPECTEST_VECTORS_DIR) amsterdam-vectors

Since amsterdam-vectors is .PHONY, it also re-runs the tar extraction every time make zkevm-vectors is called (even on a warm workspace). Not a correctness problem for test infra, but worth being aware of.


parse_expected_valid_flag (test_runner.rs:606–610)

The implementation is correct. Byte 32 = hex chars 64–65 — the arithmetic is right, and .get(64..66) on an ASCII hex string is safe.

fn parse_expected_valid_flag(hex: &str) -> Option<bool> {
    let trimmed = hex.strip_prefix("0x").unwrap_or(hex);
    let byte_hex = trimmed.get(64..66)?;
    u8::from_str_radix(byte_hex, 16).ok().map(|b| b != 0)
}

Silent fallback on malformed/short input — if statelessOutputBytes is present but shorter than 33 bytes (< 66 hex chars after stripping the prefix), parse_expected_valid_flag returns None, the .and_then propagates None, and unwrap_or(true) silently treats the fixture as "expected valid". For well-formed fixture data this is fine, but if a future fixture revision produces a truncated field, the test would pass silently instead of surfacing the malformed data. Consider logging a warning or returning an error instead of silently defaulting to true when the field is present but unparseable.


run_stateless_from_fixture (test_runner.rs:533–599)

Unnecessary clone on block

let program_input = ProgramInput::new(vec![block.clone()], execution_witness);

block is not used after the IIFE closure, only block_number (which is Copy) is referenced in the error arms below. Using move || and vec![block] avoids the clone:

let stateless_outcome: Result<(), String> = (move || {
    // ...
    let program_input = ProgramInput::new(vec![block], execution_witness);
    // ...
})();

Minor for test code, but CoreBlock likely isn't trivially cheap to clone.

Dead SP1 arm inside #[cfg(feature = "stateless")] function

#[cfg(feature = "sp1")]
BackendType::SP1 => Sp1Backend::new().execute(program_input),

Since compile_error! at all.rs:6–7 ensures sp1 and stateless are mutually exclusive, this arm is unreachable when the enclosing #[cfg(feature = "stateless")] function is compiled. This is pre-existing code, but the now-documented mutual-exclusion invariant makes it more obviously dead — a // unreachable when stateless: sp1 and stateless are mutually exclusive note would prevent future confusion.

witness_json.clone() — pre-existing, acceptable

serde_json::from_value consumes its argument; cloning the &serde_json::Value reference here is necessary and was present before this PR.


tests/all.rs

The three-way cfg for EXTRA_SKIPS is clean:

#[cfg(feature = "sp1")]    const EXTRA_SKIPS: &[&str] = &[...];
#[cfg(feature = "stateless")] const EXTRA_SKIPS: &[&str] = &[...];
#[cfg(not(any(feature = "sp1", feature = "stateless")))] const EXTRA_SKIPS: &[&str] = &[];

The old #[cfg(not(feature = "sp1"))] fallback was wrong — it would have produced an empty skip list when stateless was enabled, silently running failing tests. The fix here is correct.

Skip documentation quality — the 9 skipped entries are split into two clearly-labeled groups ("tolerance tests" vs "rejection tests") with explanations of why each group fails and what follow-up work is needed. This is exactly the right level of documentation for a skip list.


Summary

  • Makefile overlay ordering: add a comment explaining the dependency (otherwise future bumpers will be confused).
  • unwrap_or(true) fallback: acceptable for test infra, but log a warning when the field is present but unparseable.
  • block.clone() inside the IIFE: minor; move || avoids it.
  • Skip list and validity-flag logic: well-reasoned and correctly implemented.
  • The overall approach (overlay extraction + validity-byte parsing + pass/fail matching) is sound.

Automated review by Claude (Anthropic) · sonnet · custom prompt

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates the blockchain EF-test vector sourcing to zkevm fixture release v0.3.3 and expands the stateless runner to utilize the now-available executionWitness across all for_amsterdam fixtures, including honoring the valid marker encoded in statelessOutputBytes.

Changes:

  • Bump zkevm fixtures download URL to zkevm@v0.3.3.
  • Update vector extraction to unpack all for_amsterdam zkevm fixtures (overlaying the existing amsterdam vectors).
  • Extend stateless fixture execution to interpret statelessOutputBytes validity and treat (valid=0, Err) as a passing expected-failure outcome; add stateless-only skip list for known problematic fixtures.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.

File Description
tooling/ef_tests/blockchain/tests/all.rs Adds stateless-feature-gated EXTRA_SKIPS for known problematic validation fixtures.
tooling/ef_tests/blockchain/test_runner.rs Parses statelessOutputBytes validity flag and adjusts pass/fail logic accordingly; introduces helper to extract the flag byte.
tooling/ef_tests/blockchain/Makefile Expands zkevm-vectors extraction scope to all for_amsterdam and ensures base vectors are present first.
tooling/ef_tests/blockchain/.fixtures_url_zkevm Bumps downloaded zkevm fixture release to v0.3.3.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 554 to 566
// zkevm fixtures encode the expected stateless outcome in `statelessOutputBytes`
// as `new_payload_request_root (32 bytes) ++ valid (1 byte) ++ trailing padding`.
// When the fixture signals `valid = false` the witness is deliberately incomplete
// and the stateless path must reject it; absent bytes means "expected to succeed".
let expected_valid = block_data
.stateless_output_bytes
.as_deref()
.and_then(parse_expected_valid_flag)
.unwrap_or(true);

let block: CoreBlock = block_data.clone().into();
let block_number = block.header.number;

Copy link

Copilot AI Apr 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

expected_valid defaults to true not only when stateless_output_bytes is absent, but also when it is present yet malformed/too short (because parse_expected_valid_flag returns None). That can silently treat corrupted fixtures as “expected to succeed”. Consider returning an explicit error when stateless_output_bytes is Some(_) but the validity byte cannot be parsed, and only default to true when the field is actually missing.

Suggested change
// zkevm fixtures encode the expected stateless outcome in `statelessOutputBytes`
// as `new_payload_request_root (32 bytes) ++ valid (1 byte) ++ trailing padding`.
// When the fixture signals `valid = false` the witness is deliberately incomplete
// and the stateless path must reject it; absent bytes means "expected to succeed".
let expected_valid = block_data
.stateless_output_bytes
.as_deref()
.and_then(parse_expected_valid_flag)
.unwrap_or(true);
let block: CoreBlock = block_data.clone().into();
let block_number = block.header.number;
let block: CoreBlock = block_data.clone().into();
let block_number = block.header.number;
// zkevm fixtures encode the expected stateless outcome in `statelessOutputBytes`
// as `new_payload_request_root (32 bytes) ++ valid (1 byte) ++ trailing padding`.
// When the fixture signals `valid = false` the witness is deliberately incomplete
// and the stateless path must reject it; absent bytes means "expected to succeed".
let expected_valid = match block_data.stateless_output_bytes.as_deref() {
None => true,
Some(stateless_output_bytes) => parse_expected_valid_flag(stateless_output_bytes)
.ok_or_else(|| {
format!(
"Malformed statelessOutputBytes for {test_key} block {block_number}"
)
})?,
};

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in 5a597e6 — took your suggested shape: match on Some/None, and a present-but-malformed field returns an explicit error rather than defaulting to true.

Comment on lines +582 to +584
match (expected_valid, stateless_outcome) {
(true, Ok(())) | (false, Err(_)) => {}
(true, Err(e)) => {
Copy link

Copilot AI Apr 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When expected_valid is false, any error is currently treated as an acceptable pass ((false, Err(_)) => {}). That includes host-side failures like executionWitness JSON parsing and witness conversion, which can mask regressions and also means the guest may never be invoked. Consider distinguishing error stages (parse/conversion vs execution) and only accepting the expected-failure case when the stateless execution step actually runs and rejects the witness.

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in 5a597e6 — split the IIFE. serde_json::from_value and into_execution_witness now propagate via ? unconditionally; only backend execution errors are matched against expected_valid.

@github-actions
Copy link
Copy Markdown

🤖 Codex Code Review

Findings

  1. test_runner.rs:558, test_runner.rs:606
    Present-but-malformed statelessOutputBytes is silently treated as valid = true. and_then(parse_expected_valid_flag).unwrap_or(true) collapses three different states: field absent, field present but truncated/invalid, and an actual 01 flag. That can turn fixture format drift or corrupted vectors into false greens. I’d make Some(..) + parse failure a hard error, and I’d only accept 00 / 01 as valid encodings.

  2. test_runner.rs:567
    For valid = 0, the harness treats any Err from JSON decode, witness conversion, or execution as a passing result. That weakens the new negative fixtures: an unrelated regression in executionWitness decoding would still make the suite pass, so you stop testing the intended witness-completeness rejection. At minimum, keep serde_json::from_value failures fatal; ideally distinguish decode/conversion errors from guest execution rejection.

Notes

  • Makefile:74 still scopes test-stateless-zkevm to eip8025_optional_proofs. If the v0.3.3 additions that motivated this PR live outside that subtree, the dedicated zkevm target will miss them.
  • No obvious production-path/runtime regression jumped out from this diff; the concerns above are in the test harness coverage/strictness.
  • I couldn’t run cargo test in this environment because the sandbox blocks writes under ~/.cargo / ~/.rustup, so this review is static-only.

Automated review by OpenAI Codex · gpt-5.4 · custom prompt

Comment on lines -31 to 53
#[cfg(not(feature = "sp1"))]
#[cfg(feature = "stateless")]
const EXTRA_SKIPS: &[&str] = &[
// zkevm@v0.3.3 tolerance tests: the fixture's `statelessOutputBytes` declares `valid = 1`
// because the executed path does not actually consume the malformed/extra/missing witness
// entry, but our RpcExecutionWitness conversion eagerly validates the full witness and
// rejects it. Re-enable once the witness conversion is lazy per EIP-8025 §Tolerance.
"validation_headers_malformed_rlp_header",
"validation_headers_missing_oldest_blockhash_ancestor",
"validation_headers_missing_parent_header",
"validation_state_extra_unused_trie_node",
// zkevm@v0.3.3 rejection tests: `statelessOutputBytes` declares `valid = 0` so the guest
// program must reject the deliberately-incomplete witness, but our stateless path runs
// to completion instead of detecting the missing entry. Re-enable once the witness
// completeness checks land (missing delegation/external-code bytecodes, non-contiguous
// header chain detection).
"validation_codes_missing_delegated_code_on_insufficient_balance_call",
"validation_codes_missing_external_code_read_target",
"validation_codes_missing_redelegation_old_marker",
"validation_codes_missing_sender_delegation_marker",
"validation_headers_non_contiguous_chain",
];
#[cfg(not(any(feature = "sp1", feature = "stateless")))]
const EXTRA_SKIPS: &[&str] = &[];
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if sp1 is set but stateless isn't this won't compile, and if sp1 implies stateless then why specify both?

Copy link
Copy Markdown
Contributor Author

@avilagaston9 avilagaston9 May 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sp1 alone compiles (verified). The sp1 + stateless combo is rejected by the compile_error! at lines 6–7. They are not redundant: stateless uses the in-process Exec backend; sp1 runs the guest ELF inside the SP1 zkVM executor.

res.map(|_| ()).map_err(|e| format!("execution: {e}"))
})();

match (expected_valid, stateless_outcome) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Block on this: the (false, Err(_)) => {} arm is too permissive — it treats any host-side failure as a pass, including executionWitness JSON parse errors, into_execution_witness conversion errors, and program-input setup errors. None exercise the stateless rejection path the fixture is asserting. A regression in RpcExecutionWitness::deserialize would silently pass every valid=false fixture without ever invoking the guest. Split the closure so JSON/conversion errors propagate as real failures regardless of expected_valid. (Copilot flagged.)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in 5a597e6 — IIFE removed. JSON parse and witness conversion always fail the test; only Backend::execute errors satisfy (false, Err(_)).

/// The output encoding is `new_payload_request_root (32 bytes) ++ valid (1 byte) ++ padding`,
/// so byte index 32 carries the validity marker.
#[cfg(feature = "stateless")]
fn parse_expected_valid_flag(hex: &str) -> Option<bool> {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unwrap_or(true) (at the call site above) collapses three distinct cases — field absent, field present but malformed, field present with valid byte 0x00 — into the same default. Right fix: parse_expected_valid_flag returns Result (or at minimum an Option with the absent case kept distinct from the malformed case), so a bad fixture can't silently flip into the success bucket. With ~2670 new fixtures landing, having one silently misinterpreted is a real risk. (Greptile + Copilot both flagged.)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in 5a597e6 — parse_expected_valid_flag returns Result<bool, String>, the call site ?s the error, and only 0x00/0x01 are accepted. Absent / malformed / 0x00 / 0x01 are now all distinguishable.

"static_Call1MB1024Calldepth",
];
#[cfg(not(feature = "sp1"))]
#[cfg(feature = "stateless")]
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cfg(feature = "sp1") and cfg(feature = "stateless") aren't mutually exclusive at the cfg level — if both are enabled together, this file fails to compile (two definitions of EXTRA_SKIPS). Either gate the third arm with cfg(all(not(feature="sp1"), not(feature="stateless"))) (which it already does via not(any(...))) AND add a compile_error! in cfg(all(feature="sp1", feature="stateless")) to make the exclusivity explicit. Currently those features may be exclusive in practice, but the constraint isn't documented anywhere.

Copy link
Copy Markdown
Contributor Author

@avilagaston9 avilagaston9 May 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

compile_error! is at lines 6–7. In ad031d5 I gated the sp1 arms with not(feature = "stateless") so the both-on combo now fails with only that diagnostic (previously two duplicate-definition errors rode along with it).

avilagaston9 and others added 4 commits May 4, 2026 15:11
conversion, and execution stages so the first two always fail the test,
instead of being absorbed by the (false, Err(_)) acceptance arm. With
the previous IIFE, a regression in RpcExecutionWitness deserialization
or into_execution_witness would have silently passed every valid=0
fixture without ever invoking the guest. Now only the backend execution
result is matched against expected_valid.

Tighten parse_expected_valid_flag to return Result instead of Option so
a present-but-malformed statelessOutputBytes is a hard error rather than
silently defaulting to expected_valid=true. Also restrict the accepted
byte values to 0x00 and 0x01; anything else (truncated input, invalid
hex, byte != 0/1) now produces an explicit error message.

Move block into ProgramInput::new instead of cloning it, and document
the amsterdam-vectors -> zkevm-vectors overlay ordering in the Makefile.
`not(feature = "stateless")` so that, when both features are mistakenly
enabled together, the `compile_error!` at the top of the file is the
only diagnostic that surfaces — not the two duplicate-definition errors
that previously rode along with it. The stateless arms remain the sole
definers in the both-on case; values are irrelevant since compilation
already aborts.
@avilagaston9 avilagaston9 enabled auto-merge May 6, 2026 18:16
@avilagaston9 avilagaston9 added this pull request to the merge queue May 6, 2026
@avilagaston9 avilagaston9 removed this pull request from the merge queue due to a manual request May 6, 2026
This was referenced May 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

L1 Ethereum client

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

6 participants