-
Notifications
You must be signed in to change notification settings - Fork 214
feat(l1): bump zkevm EF-tests fixtures to v0.3.3 and extend stateless witness coverage to all for_amsterdam tests #6527
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 2 commits
9d48e68
189b8a6
5a597e6
ad031d5
e216333
3571da7
5bd9c88
56439dd
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1 +1 @@ | ||
| https://github.com/ethereum/execution-spec-tests/releases/download/zkevm%40v0.3.0/fixtures_zkevm.tar.gz | ||
| https://github.com/ethereum/execution-spec-tests/releases/download/zkevm%40v0.3.3/fixtures_zkevm.tar.gz |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -551,32 +551,60 @@ async fn run_stateless_from_fixture( | |
| continue; | ||
| }; | ||
|
|
||
| // 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 rpc_witness: RpcExecutionWitness = serde_json::from_value(witness_json.clone()) | ||
| .map_err(|e| { | ||
| format!("Failed to parse executionWitness for block {block_number}: {e}") | ||
| })?; | ||
|
|
||
| let execution_witness = rpc_witness | ||
| .into_execution_witness(*chain_config, block_number) | ||
| .map_err(|e| format!("Witness conversion failed for block {block_number}: {e}"))?; | ||
|
|
||
| let program_input = ProgramInput::new(vec![block], execution_witness); | ||
|
|
||
| let execute_result = match backend_type { | ||
| BackendType::Exec => ExecBackend::new().execute(program_input), | ||
| #[cfg(feature = "sp1")] | ||
| BackendType::SP1 => Sp1Backend::new().execute(program_input), | ||
| }; | ||
|
|
||
| if let Err(e) = execute_result { | ||
| return Err(format!( | ||
| "Stateless execution from fixture failed for {test_key} block {block_number}: {e}" | ||
| )); | ||
| let stateless_outcome: Result<(), String> = (|| { | ||
| let rpc_witness: RpcExecutionWitness = serde_json::from_value(witness_json.clone()) | ||
| .map_err(|e| format!("executionWitness parse: {e}"))?; | ||
| let execution_witness = rpc_witness | ||
| .into_execution_witness(*chain_config, block_number) | ||
| .map_err(|e| format!("witness conversion: {e}"))?; | ||
| let program_input = ProgramInput::new(vec![block.clone()], execution_witness); | ||
| let res = match backend_type { | ||
| BackendType::Exec => ExecBackend::new().execute(program_input), | ||
| #[cfg(feature = "sp1")] | ||
| BackendType::SP1 => Sp1Backend::new().execute(program_input), | ||
| }; | ||
| res.map(|_| ()).map_err(|e| format!("execution: {e}")) | ||
| })(); | ||
|
|
||
| match (expected_valid, stateless_outcome) { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Block on this: the
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 |
||
| (true, Ok(())) | (false, Err(_)) => {} | ||
| (true, Err(e)) => { | ||
|
||
| return Err(format!( | ||
| "Stateless execution from fixture failed for {test_key} block {block_number}: {e}" | ||
| )); | ||
| } | ||
| (false, Ok(())) => { | ||
| return Err(format!( | ||
| "Stateless execution from fixture succeeded for {test_key} block \ | ||
| {block_number} but fixture expected it to fail (invalid executionWitness)" | ||
| )); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| Ok(()) | ||
| } | ||
|
|
||
| /// Extract the `valid` byte from a zkevm-fixture `statelessOutputBytes` hex string. | ||
| /// | ||
| /// 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> { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done in 5a597e6 — |
||
| 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) | ||
| } | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
The existing code already handles this correctly at the call site ( Prompt To Fix With AIThis 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.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done in 5a597e6 — |
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -28,7 +28,28 @@ const EXTRA_SKIPS: &[&str] = &[ | |
| "Return50000", | ||
| "static_Call1MB1024Calldepth", | ||
| ]; | ||
| #[cfg(not(feature = "sp1"))] | ||
| #[cfg(feature = "stateless")] | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| 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] = &[]; | ||
|
Comment on lines
-31
to
60
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
|
|
||
| // Select backend | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
expected_validdefaults totruenot only whenstateless_output_bytesis absent, but also when it is present yet malformed/too short (becauseparse_expected_valid_flagreturnsNone). That can silently treat corrupted fixtures as “expected to succeed”. Consider returning an explicit error whenstateless_output_bytesisSome(_)but the validity byte cannot be parsed, and only default totruewhen the field is actually missing.There was a problem hiding this comment.
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:
matchonSome/None, and a present-but-malformed field returns an explicit error rather than defaulting totrue.