Skip to content

feat: add support for EEST blockchain test fixtures#286

Merged
jsign merged 6 commits into
masterfrom
jsign-eest-format-support
May 22, 2026
Merged

feat: add support for EEST blockchain test fixtures#286
jsign merged 6 commits into
masterfrom
jsign-eest-format-support

Conversation

@jsign
Copy link
Copy Markdown
Collaborator

@jsign jsign commented May 21, 2026

This PR:

  • Adds support in ere-hosts to directly consume EEST tests new format from execution-specs@projects/zkevm. It is the usual fixture format, but for each block contains statelessInputBytes and statelessOutputBytes.
  • The runner automatically can detect both workload fixture formats: current one (now called Legacy, and new one Eest). i.e. this is not a breaking change.
  • If Eest fixtures are detected, we directly use stateless{Input|Output}Bytes for the guest program run (i.e. running EEST fixtures can be done directly without a previously required witness-generator-cli).
  • The zkevm-metrics metadata for an EEST run contains more details to easily map to original EEST file.

Example run output in zkevm-metrics:

{
  "name": "eest__tests_amsterdam_eip8025_optional_proofs_test_witness_state_writes_py_test_witness_state_reverted_sstore_still_contains_storage_proof_fork_Amsterdam-blockchain_test__block0",
  "timestamp_completed": "2026-05-21T17:48:02.645237188Z",
  "metadata": {
    "block_index": 0,
    "block_number": 1,
    "block_used_gas": 26012,
    "chain_id": 1,
    "fixture_format": "eest",
    "network": "Amsterdam",
    "original_test_name": "tests/amsterdam/eip8025_optional_proofs/test_witness_state_writes.py::test_witness_state_reverted_sstore_still_contains_storage_proof[fork_Amsterdam-blockchain_test]",
    "source_path": "blockchain_tests/for_amsterdam/amsterdam/eip8025_optional_proofs/witness_state_writes/witness_state_reverted_sstore_still_contains_storage_proof.json"
  },
  "execution": {
    "crashed": {
      "reason": "zkVM method error: Emulator panicked: Mem::read() section not found for addr: 0=0 with width: 8"
    }
  }
}

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

The previous crates/benchmark-runner/src/stateless_validator.rs file was getting a bit loaded. I moved to a module with a bit more organized structure.

I'll simply comment on the new stuff.

Comment on lines +8 to +9
#[derive(Debug, Clone)]
pub(crate) struct EestStatelessFixture {
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Now we have an enum for BenchmarkFixture:

#[derive(Debug, Clone)]
pub(crate) enum BenchmarkFixture {
    Legacy(StatelessValidationFixture),
    Eest(EestStatelessFixture),
}

StatelessValidationFixture is the usual format. This new EestStatelssFixture is the one coming from EEST variant. It mainly contains basic data extracted from parsing EEST fixture that will be also used as Metadata for zkevm-metrics outputs.

Example of output:

{
  "name": "eest__tests_amsterdam_eip8025_optional_proofs_test_witness_state_writes_py_test_witness_state_reverted_sstore_still_contains_storage_proof_fork_Amsterdam-blockchain_test__block0",
  "timestamp_completed": "2026-05-21T17:48:02.645237188Z",
  "metadata": {
    "block_index": 0,
    "block_number": 1,
    "block_used_gas": 26012,
    "chain_id": 1,
    "fixture_format": "eest",
    "network": "Amsterdam",
    "original_test_name": "tests/amsterdam/eip8025_optional_proofs/test_witness_state_writes.py::test_witness_state_reverted_sstore_still_contains_storage_proof[fork_Amsterdam-blockchain_test]",
    "source_path": "blockchain_tests/for_amsterdam/amsterdam/eip8025_optional_proofs/witness_state_writes/witness_state_reverted_sstore_still_contains_storage_proof.json"
  },
  "execution": {
    "crashed": {
      "reason": "zkVM method error: Emulator panicked: Mem::read() section not found for addr: 0=0 with width: 8"
    }
  }
}

pub(crate) stateless_output_bytes: Vec<u8>,
}

#[derive(Debug, Deserialize)]
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

EEST fixture parsing structs.

Comment on lines +20 to +24
#[derive(Debug, Clone)]
pub(crate) enum BenchmarkFixture {
Legacy(Box<StatelessValidationFixture>),
Eest(EestStatelessFixture),
}
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Note now BenchmarkFixture is an enum.

Comment on lines +152 to +165
fn load_benchmark_fixtures(path: &Path, input_root: &Path) -> Result<Vec<BenchmarkFixture>> {
let content = std::fs::read(path)?;
let value: serde_json::Value = serde_json::from_slice(&content)
.with_context(|| format!("Failed to parse {}", path.display()))?;

if value.get("stateless_input").is_some() {
let fixture = serde_json::from_value(value)
.with_context(|| format!("Failed to parse legacy fixture {}", path.display()))?;
return Ok(vec![BenchmarkFixture::Legacy(Box::new(fixture))]);
}

load_eest_benchmark_fixtures(value, path, input_root)
.map(|fixtures| fixtures.into_iter().map(BenchmarkFixture::Eest).collect())
}
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

The automatic detection if we are in the legacy or eest format.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

As said, mostly refactoring to make it more modular.

Comment on lines +35 to +46
pub(crate) fn stateless_validator_input_from_fixture(
fixture: BenchmarkFixture,
el: ExecutionClient,
) -> Result<Box<dyn GuestFixture>> {
match fixture {
BenchmarkFixture::Legacy(fixture) => match el {
ExecutionClient::Reth => reth_input_from_fixture(*fixture),
ExecutionClient::Ethrex => ethrex_input_from_fixture(*fixture),
},
BenchmarkFixture::Eest(fixture) => raw_eest_input_from_fixture(fixture),
}
}
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Gist-ish of the PR: depending on the BenchmarkFixture variant, we do the usual for Legacy, or call new raw_eest-input_from_fixture(...).

block_number: fixture.block_number,
block_used_gas: fixture.block_used_gas,
};
let expected_public_values = Sha256::digest(fixture.stateless_output_bytes).to_vec();
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Nit: here we explicitly Sha256 for now. But I think in theory, zkVMs are expected to output raw bytes that the guest program wrote to output.

@han0110, do you know if this is something we could assume in new Zisk v0.18.0? Or maybe we should still keep this Sha256-ing for a while.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

But I think in theory, zkVMs are expected to output raw bytes that the guest program wrote to output.

Yes but currently only SP1 and RISC Zero support that, others have restricted size:

  • Airbender - 32 bytes
  • OpenVM - 32 bytes (configurable)
  • ZisK - 256 bytes

So I think we have to stick with the sha256 output for a while, or we drop the support of Airbender in ere-guests and configure OpenVM to support 256 bytes as well (assuming the public values will not exceed 256 bytes, where currently it's 41 bytes)

Copy link
Copy Markdown
Collaborator Author

@jsign jsign May 22, 2026

Choose a reason for hiding this comment

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

Cool, let's keep the Sha256, and we can see how things evolve.

@marcinbugaj, is this something Zisk is planning to support? Since I think from zkEVM standards POV it should be required the return exactly what the guest program wrote as output?

@jsign jsign marked this pull request as ready for review May 21, 2026 20:00
@jsign jsign requested a review from han0110 May 21, 2026 20:00
Copy link
Copy Markdown
Collaborator

@han0110 han0110 left a comment

Choose a reason for hiding this comment

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

LGTM! (looks like the fixture name is a bit tricky to handle when needing to use it for file name)

Comment thread crates/benchmark-runner/src/stateless_validator/fixtures.rs Outdated
block_number: fixture.block_number,
block_used_gas: fixture.block_used_gas,
};
let expected_public_values = Sha256::digest(fixture.stateless_output_bytes).to_vec();
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

But I think in theory, zkVMs are expected to output raw bytes that the guest program wrote to output.

Yes but currently only SP1 and RISC Zero support that, others have restricted size:

  • Airbender - 32 bytes
  • OpenVM - 32 bytes (configurable)
  • ZisK - 256 bytes

So I think we have to stick with the sha256 output for a while, or we drop the support of Airbender in ere-guests and configure OpenVM to support 256 bytes as well (assuming the public values will not exceed 256 bytes, where currently it's 41 bytes)

@jsign
Copy link
Copy Markdown
Collaborator Author

jsign commented May 22, 2026

(looks like the fixture name is a bit tricky to handle when needing to use it for file name)

Yeah, it is a bit tricky not to pass 256 in length. Before, I used a shorter style but had to add a hash to the name to avoid potential collisions, which was ugly. I think it should be fine. If we discover it violates the length max, we should prob switch to that idea too.
For UI-related stuff, it should use the metadata field in the JSON result, which is the original "nice" name (i.e., not rely on the fixture result file name).

@jsign
Copy link
Copy Markdown
Collaborator Author

jsign commented May 22, 2026

Might leave this open for some extra mins/hours -- I'm using this branch to test a dashboard automation reg EEST fixtures direct run.

@jsign jsign merged commit 02758cd into master May 22, 2026
5 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.

2 participants