Skip to content

PoC: Aurora zkEVM#103

Open
mrLSD wants to merge 4 commits intomasterfrom
zk-evm
Open

PoC: Aurora zkEVM#103
mrLSD wants to merge 4 commits intomasterfrom
zk-evm

Conversation

@mrLSD
Copy link
Copy Markdown
Member

@mrLSD mrLSD commented Jan 28, 2026

Summary by CodeRabbit

  • New Features

    • Introduced zero-knowledge EVM test execution capability with CLI tool for running test suites and generating proofs.
  • Chores

    • Updated workspace configuration and refactored test dependencies with enhanced feature flags.
    • Exposed core testing modules and utilities for external integration.
    • Added build tooling and Rust toolchain configuration for ZK infrastructure.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Jan 28, 2026

Walkthrough

This PR introduces a new zk-evm crate for zero-knowledge EVM test execution alongside enhancements to the evm-tests public API. The zk-evm crate integrates RISC0 proving infrastructure with a guest binary for executing EVM state tests. The evm-tests crate is refactored to expose previously internal modules, types, and functions while disabling KZG precompile support.

Changes

Cohort / File(s) Summary
Workspace & Dependency Configuration
Cargo.toml, evm-tests/Cargo.toml
Added workspace exclusion for zk-evm. Enhanced c-kzg dependency in evm-tests with explicit features: default-features = false, generate-bindings, portable, serde.
evm-tests Public API Exposure
evm-tests/src/lib.rs, evm-tests/src/assertions.rs, evm-tests/src/precompiles.rs, evm-tests/src/types/mod.rs, evm-tests/src/types/account_state.rs, evm-tests/src/types/spec.rs
Exposed four modules (assertions, config, precompiles, types) as public. Added #[must_use] attributes to Precompiles constructors and exit reason validators. Made AccountsState inner BTreeMap public, PreState fields public, info module public, and Spec::get_gasometer_config public. Removed/disabled KZG precompile from Cancun and Osaka specs.
EVM Runtime Signature Update
evm/src/runtime/mod.rs
Tightened Resolve generic parameter lifetime in run() method return type from Resolve<H> to Resolve<'_, H>.
zk-evm Crate - Manifests & Config
zk-evm/Cargo.toml, zk-evm/Makefile, zk-evm/rust-toolchain.toml, zk-evm/.gitignore, zk-evm/methods/Cargo.toml, zk-evm/methods/guest/Cargo.toml
Created new zk-evm workspace with dependencies on aurora-evm-jsontests, risc0-zkvm, clap, and serde. Configured methods subcrate with risc0-build for guest compilation. Added Makefile target for running tests with static fixture paths and rust-toolchain configuration.
zk-evm Build Infrastructure
zk-evm/methods/src/lib.rs, zk-evm/methods/build.rs
Integrated generated methods via include! macro in lib.rs. Added build.rs entry point that invokes risc0_build::embed_methods().
zk-evm Guest Binary
zk-evm/methods/guest/src/main.rs
Implemented comprehensive EVM state test executor (~258 lines) for RISC0 guest environment. Parses JSON test suites, executes transactions with full EVM semantics (gas calculation, precompiles, delegation, fee handling), validates exit reasons, and produces ExecutionResult serialized output.
zk-evm CLI Binary
zk-evm/src/main.rs
Implemented ZK-EVM CLI (~76 lines) that accepts test fixture paths, validates JSON structure, executes guest via prover, and verifies receipt integrity. Integrates risc0-zkvm proving infrastructure.

Sequence Diagrams

sequenceDiagram
    participant User
    participant CLI as zk-evm CLI
    participant Prover as RISC0 Prover
    participant Guest as Guest Executor
    participant Output

    User->>CLI: Execute with fixture path
    CLI->>CLI: Parse & validate JSON test file
    CLI->>Prover: Build ExecutorEnv with test suite
    Prover->>Guest: Execute ZK_EVM_ELF with environment
    Guest->>Guest: Parse test suites from input
    Guest->>Guest: Execute each test transaction<br/>(gas, precompiles, state changes)
    Guest->>Guest: Validate exit reasons & compute hashes
    Guest->>Output: Commit JSON results to journal
    Prover->>Prover: Generate receipt with proof
    CLI->>CLI: Verify receipt against ZK_EVM_ID
    CLI->>User: Return verified results
Loading
sequenceDiagram
    participant Guest as Guest Executor
    participant Parser as JSON Parser
    participant Config as Test Config
    participant Executor as Stack Executor
    participant Backend as Memory Backend
    participant Results as Result Vector

    Guest->>Parser: Read test suite from stdin
    Parser->>Config: Initialize TestConfig::default()
    
    loop For each test case
        Config->>Config: Get gasometer config by spec
        Config->>Backend: Create MemoryBackend
        Backend->>Executor: Create StackExecutor with precompiles
        Executor->>Executor: Validate transaction (gas, nonce, etc.)
        Executor->>Executor: Execute call or create based on EIP-3607/7702
        Executor->>Executor: Compute miner rewards & update balances
        Executor->>Results: Collect ExecutionResult<br/>(gas_used, valid_hash, actual_hash)
    end
    
    Results->>Guest: Serialize to JSON
    Guest->>Guest: Commit results to journal
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • aurora-is-near/aurora-evm#95: Modifies evm-tests crate structure, precompiles, types, and dependencies (c-kzg features), directly aligning with this PR's evm-tests refactoring.

Suggested labels

enhancement, tests, ethereum-tests

Poem

🐰 A zero-knowledge hop through EVM's grand test suite,
Guest executors prove each tx with risc0 loot,
Precompiles dance (KZG now takes a rest),
Public APIs bloom—the tests know best! ✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 inconclusive)
Check name Status Explanation Resolution
Title check ❓ Inconclusive The title 'PoC: Aurora zkEVM' is vague and lacks specificity. It uses generic terms that don't clearly convey what actual changes are made in this substantial pull request, which adds a new zk-evm crate with test infrastructure, guest programs, and public API expansions. Use a more specific title that describes the primary change, such as 'Add Aurora zkEVM proof-of-concept implementation with guest program and test runner' to better communicate the scope and intent of this changeset.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Docstring Coverage ✅ Passed Docstring coverage is 85.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In `@zk-evm/methods/guest/src/main.rs`:
- Around line 62-78: The code calls states.first().unwrap() when handling a
vicinity error, which will panic if states is empty; replace the unwrap with a
clear expect message (e.g., let h = states.first().expect("post_states should
not be empty").hash;) or otherwise defensively handle the empty-case before
calling original_state.check_valid_hash; update the occurrence in the vicinity
error branch near assert_vicinity_validation and ExecutionResult so the failure
is explicit and debuggable.
- Line 43: Fix the typo in the inline comment "Geet gasometer config for the
current spec" by replacing "Geet" with "Get" so the comment reads "Get gasometer
config for the current spec" (update the comment in main.rs where that comment
appears).
🧹 Nitpick comments (7)
zk-evm/Makefile (1)

1-3: Consider adding .PHONY declaration and documenting fixture path requirements.

A few observations for this PoC Makefile:

  1. The run target should be declared as .PHONY since it doesn't produce a file output.
  2. The hardcoded path to external fixtures (../../../ethereum/fixtures_static-v4.5.0/...) assumes a specific directory structure outside the repository, which may not exist on other developer machines.

Consider making the fixture path configurable via a variable or documenting the expected setup in a README.

♻️ Suggested improvement
+.PHONY: run
+
+# Path to ethereum test fixtures (adjust to your local setup)
+FIXTURE_PATH ?= ../../../ethereum/fixtures_static-v4.5.0/fixtures/state_tests/static/state_tests/stStaticCall/static_log_Caller.json
+
 run:
-	`@cargo` run --release -- ../../../ethereum/fixtures_static-v4.5.0/fixtures/state_tests/static/state_tests/stStaticCall/static_log_Caller.json
+	`@cargo` run --release -- $(FIXTURE_PATH)
 #	`@cargo` run --release -- ../../../ethereum/ethtests-17.0/GeneralStateTests/stInitCodeTest/StackUnderFlowContractCreation.json

This allows overriding the path: make run FIXTURE_PATH=/path/to/other/fixture.json

zk-evm/src/main.rs (1)

44-52: Consider reading the file only once.

The file is read twice: first via BufReader for JSON validation, then again via read_to_string. For a PoC this is acceptable, but could be optimized.

♻️ Suggested optimization
 fn get_tests_suite(file_name: &Path) -> String {
-    let file = File::open(file_name).expect("Open file failed");
-    let reader = BufReader::new(file);
-
-    // We parse the JSON test cases to verify is it deserialized correctly
-    let _ = serde_json::from_reader::<_, HashMap<String, StateTestCase>>(reader)
-        .expect("Parse test cases failed");
-    std::fs::read_to_string(file_name).unwrap()
+    let content = std::fs::read_to_string(file_name).expect("Open file failed");
+    // We parse the JSON test cases to verify it deserializes correctly
+    let _ = serde_json::from_str::<HashMap<String, StateTestCase>>(&content)
+        .expect("Parse test cases failed");
+    content
 }
evm-tests/src/precompiles.rs (1)

1-3: Consider removing commented-out KZG code if not needed.

Commented-out code (module import and use statement) adds noise. If KZG support is intentionally disabled for the zk-EVM PoC and won't be re-enabled soon, consider removing these lines entirely. If this is temporary, a TODO comment explaining when it will be restored would be helpful.

evm-tests/Cargo.toml (1)

22-22: Consider removing the commented dependency.

Similar to the precompiles code, if c-kzg is intentionally disabled for the zk-EVM PoC, removing the commented line keeps the manifest cleaner. Alternatively, add a comment explaining when/why it would be restored.

zk-evm/methods/guest/src/main.rs (3)

1-1: Consider narrowing the allow attributes.

#![allow(unused_imports, dead_code)] is quite broad. For a PoC this is acceptable, but consider removing unused imports and dead code before promoting to production, or using more targeted #[allow(...)] on specific items.


232-241: Hardcoded test name introduces maintenance burden.

The magic string "failed_tx_xcf416c53" couples this code to a specific test case name. While the comment explains the edge case well, consider extracting this to a constant or configuration for better maintainability.

Suggested refactor
+const PRECOMPILE_EDGE_CASE_TEST: &str = "failed_tx_xcf416c53";
+
 fn main() {
     // ...
-                if *spec <= Spec::London && test_config.name == "failed_tx_xcf416c53" {
+                if *spec <= Spec::London && test_config.name == PRECOMPILE_EDGE_CASE_TEST {

91-250: Complex loop body could benefit from extraction.

The inner loop body (lines 91-250) handles multiple concerns: transaction validation, execution branching (call vs create), gas fee calculation, and state verification. For a PoC this is acceptable, but consider extracting logical units into helper functions if this code evolves beyond PoC.


for (_, test) in test_suite {
for (spec, states) in &test.post_states {
// Geet gasometer config for the current spec
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Typo in comment.

"Geet" should be "Get".

Proposed fix
-            // Geet gasometer config for the current spec
+            // Get gasometer config for the current spec
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Geet gasometer config for the current spec
// Get gasometer config for the current spec
🤖 Prompt for AI Agents
In `@zk-evm/methods/guest/src/main.rs` at line 43, Fix the typo in the inline
comment "Geet gasometer config for the current spec" by replacing "Geet" with
"Get" so the comment reads "Get gasometer config for the current spec" (update
the comment in main.rs where that comment appears).

Comment on lines +62 to +78
if let Err(tx_err) = vicinity {
let h = states.first().unwrap().hash;
// if vicinity could not be computed, then the transaction was invalid, so we simply
// check the original state and move on
let (is_valid_hash, actual_hash) = original_state.check_valid_hash(&h);
if !is_valid_hash {
results.push(ExecutionResult {
used_gas: 0,
is_valid_hash,
actual_hash: actual_hash.to_string(),
});

continue;
}
assert_vicinity_validation(&tx_err, states, spec, &test_config);
// As it's an expected validation error-skip the test run
continue;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Potential panic if states is empty.

states.first().unwrap() will panic if the states vector is empty. While test JSON files typically guarantee non-empty post-states, consider defensive handling or documenting this assumption.

Proposed fix using if-let or pattern match
             if let Err(tx_err) = vicinity {
-                let h = states.first().unwrap().hash;
+                let Some(first_state) = states.first() else {
+                    continue;
+                };
+                let h = first_state.hash;
                 // if vicinity could not be computed, then the transaction was invalid, so we simply
                 // check the original state and move on

Based on learnings, explicit panics are preferred in test code for debugging. If empty states should never occur, an expect() with a descriptive message would be clearer:

let h = states.first().expect("post_states should not be empty").hash;
🤖 Prompt for AI Agents
In `@zk-evm/methods/guest/src/main.rs` around lines 62 - 78, The code calls
states.first().unwrap() when handling a vicinity error, which will panic if
states is empty; replace the unwrap with a clear expect message (e.g., let h =
states.first().expect("post_states should not be empty").hash;) or otherwise
defensively handle the empty-case before calling
original_state.check_valid_hash; update the occurrence in the vicinity error
branch near assert_vicinity_validation and ExecutionResult so the failure is
explicit and debuggable.

@mrLSD mrLSD added the zk-evm label Mar 25, 2026
@mrLSD mrLSD self-assigned this Mar 25, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants