Skip to content

[Feat] Prover loading assets (circuits) dynamically #1717

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

Draft
wants to merge 10 commits into
base: develop
Choose a base branch
from

Conversation

noel2004
Copy link
Member

@noel2004 noel2004 commented Aug 8, 2025

Prover can load assets while it has received a task.

It load the corresponding task according to the vk specified in universal task.

Summary by CodeRabbit

  • New Features

    • Added dynamic asset loading and caching for proof generation, enabling assets to be downloaded on demand and reused.
    • Introduced new handlers (UniversalHandler, AssetsHandler) for flexible and universal zero-knowledge proof operations.
  • Improvements

    • Simplified and unified proof handler management by removing legacy Euclid handlers and modules.
    • Updated dependency management to use unified package names and fixed git revisions.
    • Enhanced configuration options for asset locations and workspace paths.
  • Bug Fixes

    • Corrected import paths for utility functions to ensure proper module resolution.
  • Chores

    • Updated and refactored internal module structure for maintainability and clarity.
    • Removed unused and legacy code related to previous proof handler implementations.

Copy link

coderabbitai bot commented Aug 8, 2025

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Walkthrough

This change refactors the prover and verifier infrastructure by replacing EuclidV2-specific handlers and dependencies with universal counterparts. Key workspace dependencies are pinned to a specific git commit. The prover now supports dynamic asset loading and caching per verification key, and legacy Euclid handler modules are removed in favor of newly introduced universal and asset handler modules.

Changes

Cohort / File(s) Change Summary
Workspace Dependency Updates
Cargo.toml, crates/libzkp/Cargo.toml, crates/prover-bin/Cargo.toml
Updated scroll-zkvm-prover, scroll-zkvm-verifier, and scroll-zkvm-types dependencies to use a fixed git commit; replaced Euclid-specific dependencies with universal ones; updated and added features to some dependencies.
Prover Handler Refactor
crates/prover-bin/src/prover.rs, crates/prover-bin/src/zk_circuits_handler.rs
Replaced EuclidV2Handler with UniversalHandler and introduced AssetsHandler for dynamic asset loading; refactored handler management, proof generation, and VK retrieval logic accordingly.
New Handler Modules
crates/prover-bin/src/zk_circuits_handler/assets.rs, crates/prover-bin/src/zk_circuits_handler/universal.rs
Added AssetsHandler for asset-based prover management and UniversalHandler for universal proof generation, with appropriate trait implementations and concurrency handling.
Legacy Handler Removal
crates/prover-bin/src/zk_circuits_handler/euclid.rs, crates/prover-bin/src/zk_circuits_handler/euclidV2.rs
Removed all code related to EuclidHandler and EuclidV2Handler, including struct definitions and trait implementations.
Verifier Refactor
crates/libzkp/src/verifier.rs, crates/libzkp/src/verifier/universal.rs
Replaced EuclidV2Verifier with Verifier from the universal module; updated struct names and import paths accordingly.
Import Path Corrections
crates/libzkp/src/lib.rs, crates/libzkp/src/proofs.rs, crates/libzkp/src/tasks/batch/utils.rs
Fixed import paths from util to utils for utility functions.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant LocalProver
    participant AssetsLocationData
    participant UniversalHandler
    participant AssetsHandler

    User->>LocalProver: prove(request with VK)
    LocalProver->>LocalProver: decode VK, check handler cache
    alt Handler not cached
        LocalProver->>AssetsLocationData: get_asset("app.vmexe"), get_asset("openvm.toml")
        AssetsLocationData-->>LocalProver: Downloaded assets
        LocalProver->>UniversalHandler: instantiate with assets
        LocalProver->>LocalProver: cache handler by VK
    end
    LocalProver->>UniversalHandler: generate proof
    UniversalHandler-->>LocalProver: proof data
    LocalProver-->>User: proof response
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested labels

bump-version

Suggested reviewers

  • georgehao
  • lispc

Poem

In the warren, code hops anew,
Euclid’s burrow now bid adieu.
Universal paths, assets fetched on the fly,
VKs cached, as proofs multiply.
Handlers leap, dependencies pinned,
A rabbit’s work—refactored, trimmed!
🥕✨

✨ Finishing Touches
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/dyn_asset_loading

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@noel2004 noel2004 marked this pull request as draft August 8, 2025 10:54
Copy link

@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: 8

🔭 Outside diff range comments (3)
crates/libzkp/src/lib.rs (2)

132-136: Avoid unwrap() on verifier mutex to prevent panics.
Propagate poisoning as an error instead.

-    let ret = verifier.lock().unwrap().verify(task_type, &proof)?;
+    let ret = verifier
+        .lock()
+        .map_err(|e| eyre::eyre!("verifier mutex poisoned: {e}"))?
+        .verify(task_type, &proof)?;

140-145: Same here: replace unwrap() with error propagation.
Consistent error handling.

-    verifier.lock().unwrap().dump_vk(Path::new(file));
+    verifier
+        .lock()
+        .map_err(|e| eyre::eyre!("verifier mutex poisoned: {e}"))?
+        .dump_vk(Path::new(file));
crates/libzkp/src/verifier/universal.rs (1)

33-64: Avoid unwraps and panic_catch; prefer structured error propagation

Multiple unwrap() calls wrapped by panic_catch obscures error causes and stacks. Use proper deserialization and verifier error propagation with ?, returning Result<bool> directly.

Example direction:

-    fn verify(&self, task_type: super::TaskType, proof: &[u8]) -> Result<bool> {
-        panic_catch(|| match task_type {
-            TaskType::Chunk => {
-                let proof = serde_json::from_slice::<ChunkProof>(proof).unwrap();
-                if !proof.pi_hash_check(self.fork) { return false; }
-                self.verifier.verify_proof(proof.as_root_proof(), &proof.vk).unwrap()
-            }
-            ...
-        }).map_err(|err_str: String| eyre::eyre!("{err_str}"))
-    }
+    fn verify(&self, task_type: super::TaskType, proof: &[u8]) -> Result<bool> {
+        match task_type {
+            TaskType::Chunk => {
+                let proof: ChunkProof = serde_json::from_slice(proof)
+                    .map_err(|e| eyre::eyre!("chunk proof deserialization failed: {e}"))?;
+                if !proof.pi_hash_check(self.fork) {
+                    return Ok(false);
+                }
+                Ok(self.verifier.verify_proof(proof.as_root_proof(), &proof.vk)?)
+            }
+            TaskType::Batch => {
+                let proof: BatchProof = serde_json::from_slice(proof)
+                    .map_err(|e| eyre::eyre!("batch proof deserialization failed: {e}"))?;
+                if !proof.pi_hash_check(self.fork) {
+                    return Ok(false);
+                }
+                Ok(self.verifier.verify_proof(proof.as_root_proof(), &proof.vk)?)
+            }
+            TaskType::Bundle => {
+                let proof: BundleProof = serde_json::from_slice(proof)
+                    .map_err(|e| eyre::eyre!("bundle proof deserialization failed: {e}"))?;
+                if !proof.pi_hash_check(self.fork) {
+                    return Ok(false);
+                }
+                let vk = proof.vk.clone();
+                let evm_proof = proof.into_evm_proof();
+                Ok(self.verifier.verify_proof_evm(&evm_proof, &vk)?)
+            }
+        }
+    }
🧹 Nitpick comments (14)
crates/libzkp/src/lib.rs (2)

52-58: Typos and clearer error messages (nit).
Polish comments and bail messages; improves diagnosability.

-            // normailze fork name field in task
+            // normalize fork name field in task
...
-                eyre::bail!("fork name in chunk task not match the calling arg, expected {fork_name_str}, get {}", task.fork_name);
+                eyre::bail!(
+                    "fork name in chunk task does not match the argument; expected '{fork_name_str}', got {}",
+                    task.fork_name
+                );
...
-                eyre::bail!("fork name in batch task not match the calling arg, expected {fork_name_str}, get {}", task.fork_name);
+                eyre::bail!(
+                    "fork name in batch task does not match the argument; expected '{fork_name_str}', got {}",
+                    task.fork_name
+                );
...
-                eyre::bail!("fork name in bundle task not match the calling arg, expected {fork_name_str}, get {}", task.fork_name);
+                eyre::bail!(
+                    "fork name in bundle task does not match the argument; expected '{fork_name_str}', got {}",
+                    task.fork_name
+                );

Also applies to: 67-71, 78-82


71-75: Fix copy-paste in panic mapping messages (batch/bundle).
They currently say “chunk task” in non-chunk paths.

-                    .map_err(|e| eyre::eyre!("caught panic in chunk task{e}"))??;
+                    .map_err(|e| eyre::eyre!("caught panic in batch task: {e}"))??;
...
-                    .map_err(|e| eyre::eyre!("caught panic in chunk task{e}"))??;
+                    .map_err(|e| eyre::eyre!("caught panic in bundle task: {e}"))??;

Also applies to: 82-86

crates/prover-bin/Cargo.toml (1)

21-21: Pin futures-util to exact version for consistency.
Keeps it aligned with futures = 0.3.30 and avoids duplicate minor versions.

-futures-util = "0.3"
+futures-util = "0.3.30"
crates/libzkp/src/verifier.rs (3)

55-56: Unify trait-object bounds in type alias and return type for clarity

VerifierType includes + Send, while get_verifier returns Arc<Mutex<dyn ProofVerifier>> without + Send. Although this likely coerces, returning the alias improves readability and avoids confusion.

Apply:

-pub fn get_verifier(fork_name: &str) -> Result<Arc<Mutex<dyn ProofVerifier>>> {
+pub fn get_verifier(fork_name: &str) -> Result<VerifierType> {

Also applies to: 78-79


78-88: Case-insensitive lookup to match lowercased insert keys

You lowercase keys on insert but not on lookup. Normalize fork_name on retrieval to avoid surprising misses.

-        if let Some(verifier) = verifiers.get(fork_name) {
+        if let Some(verifier) = verifiers.get(&fork_name.to_lowercase()) {

74-76: Prefer expect with message over bare assert for OnceLock set

Provide a clear error message if init is called twice.

-    let ret = VERIFIERS.set(verifiers).is_ok();
-    assert!(ret);
+    VERIFIERS
+        .set(verifiers)
+        .expect("VERIFIERS already initialized; init() should only be called once");
crates/libzkp/src/verifier/universal.rs (2)

19-26: Tweak setup error message; consider propagating errors instead of panicking

The expect message mentions “chunk verifier”, which is misleading here. Also, panicking in constructor complicates recovery and testing.

-            verifier: UniversalVerifier::setup(&config, &exe, &verifier_bin)
-                .expect("Setting up chunk verifier"),
+            verifier: UniversalVerifier::setup(&config, &exe, &verifier_bin)
+                .expect("Setting up universal verifier"),

If feasible, change new to return eyre::Result<Self> and propagate the setup error instead of panicking.


66-68: Don’t panic in deprecated method; no-op with a warning

Panicking on dump_vk can take down the process if someone calls it by mistake. Prefer a no-op and log a warning.

-    fn dump_vk(&self, _file: &Path) {
-        panic!("dump vk has been deprecated");
-    }
+    fn dump_vk(&self, _file: &Path) {
+        tracing::warn!("dump_vk is deprecated on universal verifier; no-op");
+    }
crates/prover-bin/src/zk_circuits_handler.rs (1)

22-26: Naming nit: Phase::EuclidV2 under a universal handler can mislead

Phase name is legacy but the context is now universal/asset-driven. Consider renaming or documenting why EuclidV2 phase is kept for asset layout only.

crates/prover-bin/src/zk_circuits_handler/assets.rs (2)

20-32: Prover setup per proof type is clear; minor suggestion on error context

Setup for chunk/batch/bundle looks correct with EVM enabled only for bundle. Consider adding more specific error messages to ease troubleshooting.

-        let chunk_prover = Prover::setup(p.phase_spec_chunk(workspace_path), false, None)
-            .expect("Failed to setup chunk prover");
+        let chunk_prover = Prover::setup(p.phase_spec_chunk(workspace_path), false, None)
+            .expect("Failed to setup chunk prover (phase_spec_chunk)");
...
-        let batch_prover = Prover::setup(p.phase_spec_batch(workspace_path), false, None)
-            .expect("Failed to setup batch prover");
+        let batch_prover = Prover::setup(p.phase_spec_batch(workspace_path), false, None)
+            .expect("Failed to setup batch prover (phase_spec_batch)");
...
-        let bundle_prover = Prover::setup(p.phase_spec_bundle(workspace_path), true, None)
-            .expect("Failed to setup bundle prover");
+        let bundle_prover = Prover::setup(p.phase_spec_bundle(workspace_path), true, None)
+            .expect("Failed to setup bundle prover (phase_spec_bundle)");

33-41: VK cache init is sound; ensure ProofType keys are exhaustive

Lazy OnceLock<String> per proof type is good. If ProofType gains variants later, it would be safer to derive keys from cfg.vks or a canonical list to avoid missing cache entries.

Consider building cached_vks from an iterator over supported types, or assert all required keys are present at init.

Also applies to: 46-50

crates/prover-bin/src/zk_circuits_handler/universal.rs (2)

45-47: Validate task payload before deserialising

serde_json::from_str blindly trusts the input. Consider cheap, explicit checks (e.g. size limits, required fields) before parsing to avoid DoS via gigabyte-sized JSON.


69-72: Error message loses context

The bail message when evm_prover is missing only prints the VK. Add the requested proof type and maybe the fork name to help operators diagnose mis-configurations.

crates/prover-bin/src/prover.rs (1)

73-90: HEAD size-check may fail silently

Many servers disable HEAD or omit Content-Length. In that case you fall through to continue, skipping a potentially stale file. At minimum, fall back to re-downloading when the HEAD request is not 200 OK / lacks length.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6897cc5 and 8e8da95.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (14)
  • Cargo.toml (1 hunks)
  • crates/libzkp/Cargo.toml (1 hunks)
  • crates/libzkp/src/lib.rs (1 hunks)
  • crates/libzkp/src/proofs.rs (1 hunks)
  • crates/libzkp/src/tasks/batch/utils.rs (1 hunks)
  • crates/libzkp/src/verifier.rs (2 hunks)
  • crates/libzkp/src/verifier/universal.rs (2 hunks)
  • crates/prover-bin/Cargo.toml (3 hunks)
  • crates/prover-bin/src/prover.rs (5 hunks)
  • crates/prover-bin/src/zk_circuits_handler.rs (1 hunks)
  • crates/prover-bin/src/zk_circuits_handler/assets.rs (1 hunks)
  • crates/prover-bin/src/zk_circuits_handler/euclid.rs (0 hunks)
  • crates/prover-bin/src/zk_circuits_handler/euclidV2.rs (0 hunks)
  • crates/prover-bin/src/zk_circuits_handler/universal.rs (1 hunks)
💤 Files with no reviewable changes (2)
  • crates/prover-bin/src/zk_circuits_handler/euclid.rs
  • crates/prover-bin/src/zk_circuits_handler/euclidV2.rs
🔇 Additional comments (13)
crates/libzkp/src/proofs.rs (1)

13-14: Import path fix verified: no outdated references remain

  • Ran rg -n --hidden --glob '!target' 'scroll_zkvm_types::util::vec_as_base64'; no matches found
  • The new utils::vec_as_base64 import is correct and aligns with the types crate rename

Approve code changes.

crates/libzkp/src/tasks/batch/utils.rs (1)

21-21: No stale imports; import path change is correct
Ran a repo-wide search for the old import path (scroll_zkvm_types::util::sha256_rv32) and found no occurrences. The update to scroll_zkvm_types::utils::sha256_rv32 is consistent with the types crate refactor, and get_versioned_hash remains compliant with EIP-4844.

crates/libzkp/Cargo.toml (1)

9-9: No stale Euclid-specific crate references found

  • Ran rg -n --hidden --glob '!target' 'scroll-zkvm-(verifier|prover)-euclid' and confirmed there are no remaining imports of separate Euclid-specific verifier/prover crates.
  • All remaining EuclidV2 symbols (e.g. Phase::EuclidV2, finalizeBundlePostEuclidV2) belong to universal verifier logic and are expected.
crates/libzkp/src/lib.rs (1)

8-8: Import path fix to utils::vec_as_base64 is correct.
Matches updates elsewhere in the crate.

crates/prover-bin/Cargo.toml (3)

10-10: Switch to scroll-zkvm-prover (workspace) aligns with universal flow.
Good step toward dynamic asset loading.


34-34: url with serde feature is a sensible addition.
Enables (de)serialization of URLs in config or tasks.


22-22: No reqwest version skew detected

We’ve scanned the workspace and found only:

  • crates/prover-bin/Cargo.toml
    • reqwest = { version = "0.12.4", features = ["gzip", "stream"] }
    • reqwest-middleware = "0.3"

The "0.3" spec will automatically pick the latest 0.3.x patch, which is compatible with reqwest 0.12.x. No reqwest-retry dependency was found.
No further action required.

crates/libzkp/src/verifier.rs (1)

3-4: Universal verifier switch looks correct

Module import and usage of universal::Verifier align with the PR direction. No issues spotted here.

crates/prover-bin/src/zk_circuits_handler.rs (3)

4-6: Module re-org (universal + assets) is consistent with PR goals

Separation of universal proving and asset utilities is clear and aligns with dynamic asset loading keyed by VK.


10-12: Imports updated to universal types/configs look good

Using ProvingTask and ProverConfig from universal crates matches the architecture shift.


16-20: All CircuitsHandler implementations and call sites updated
Verified that the only impl CircuitsHandler in

  • crates/prover-bin/src/zk_circuits_handler/universal.rs
    matches the new
async fn get_vk(&self) -> String;
async fn get_proof_data(&self, u_task: &ProvingTask, need_snark: bool) -> Result<String>;

and that the lone usage in

  • crates/prover-bin/src/prover.rs
    (handler.get_proof_data(&prover_task, is_evm)) has been adapted accordingly. No further changes required.
Cargo.toml (1)

20-22: Commit 2ec1303 not found in scroll-tech/zkvm-prover – please verify crate sources

The checkout script failed with “couldn’t find remote ref 2ec1303”. Before proceeding, confirm that:

  • The revision 2ec1303 actually exists in https://github.com/scroll-tech/zkvm-prover.git.
  • All three crates (scroll-zkvm-prover, scroll-zkvm-verifier, scroll-zkvm-types) are present at that commit, or update the repo URLs/revs if they live in separate repositories.

Affected location:

  • Cargo.toml, lines 20–22
crates/prover-bin/src/prover.rs (1)

57-68: Asset directory can collide across proof types

Assets for chunk/batch/bundle with identical VKs share the same storage_path (base_path/vk). If the files differ per proof type the cache becomes corrupt. Consider including proof_type in the directory name.

let storage_path = base_path.as_ref()
    .join(format!("{vk}_{:?}", proof_type).to_lowercase());

Comment on lines 61 to 66
let storage_path = base_path.as_ref().join(vk);
std::fs::create_dir_all(&storage_path)?;

// Step 2 & 3: Download each file if needed
let url_base = self.gen_asset_url(vk, proof_type)?;
let client = reqwest::Client::new();
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

vk is used as a filesystem path – sanitise it

storage_path = base_path.join(vk) lets a malicious coordinator supply vk = "../../evil" and escape the workspace directory. Reject strings containing /, \, or .. components before using them as paths.

if vk.contains('/') || vk.contains('\\') || vk.contains("..") {
    eyre::bail!("invalid vk value");
}
🤖 Prompt for AI Agents
In crates/prover-bin/src/prover.rs around lines 61 to 66, the variable `vk` is
used directly to create a filesystem path, which can lead to directory traversal
vulnerabilities if `vk` contains characters like '/', '\\', or '..'. To fix
this, add a validation step before using `vk` in the path: check if `vk`
contains any of these forbidden substrings and if so, return an error using
`eyre::bail!("invalid vk value")`. This ensures only safe, sanitized strings are
used as path components.

Comment on lines 276 to 279
let is_evm = req.proof_type == ProofType::Bundle;
let task_handle =
tokio::task::spawn_blocking(move || handle.block_on(handler.get_proof_data(req_clone)));
tokio::task::spawn_blocking(move || handle.block_on(handler.get_proof_data(&prover_task, is_evm)));
self.current_task = Some(task_handle);
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Nested runtime execution risk

spawn_blocking + handle.block_on(...) runs a future on the same runtime from a blocking thread; if that future internally calls more blocking tasks it can deadlock. Prefer:

let handler_cloned = handler.clone();
let task_handle = tokio::task::spawn(async move {
    handler_cloned.get_proof_data(&prover_task, is_evm).await
});

and drop spawn_blocking altogether unless the proof generation is strictly synchronous.

🤖 Prompt for AI Agents
In crates/prover-bin/src/prover.rs around lines 276 to 279, the current code
uses tokio::task::spawn_blocking combined with handle.block_on to run an async
future on the same runtime from a blocking thread, which risks deadlocks if the
future itself uses blocking calls. To fix this, remove spawn_blocking and
instead clone the handler, then use tokio::task::spawn with an async block that
awaits handler.get_proof_data directly, ensuring the future runs asynchronously
on the runtime without blocking threads.

prover: Prover,
}

unsafe impl Send for UniversalHandler {}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

unsafe impl Send needs a justification or removal

Prover is forcibly marked Send via unsafe impl Send for UniversalHandler {}.
Unless you can prove scroll_zkvm_prover::Prover is genuinely thread-safe, this is undefined behaviour waiting to happen. Either:

-unsafe impl Send for UniversalHandler {}
+// SAFETY: Explain here why Prover is thread-safe (interior mutability, no raw
+// pointers, etc.) or remove this entirely and keep the type !Send.

Please document the safety contract or drop the unsafe implementation.

📝 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
unsafe impl Send for UniversalHandler {}
// SAFETY: Explain here why `UniversalHandler` (and its contained `Prover`) is
// genuinely `Send` (e.g. only interior mutability with proper synchronization,
// no raw pointers, etc.), or remove this entirely and keep the type `!Send`.
🤖 Prompt for AI Agents
In crates/prover-bin/src/zk_circuits_handler/universal.rs at line 15, the unsafe
implementation of Send for UniversalHandler lacks a safety justification. You
need to either provide a detailed comment explaining why UniversalHandler is
safe to send across threads, specifically proving that
scroll_zkvm_prover::Prover is thread-safe, or remove the unsafe impl Send
entirely to avoid undefined behavior.

@noel2004
Copy link
Member Author

noel2004 commented Aug 9, 2025

Has passed prover e2e test with dynamically downloading assets

@lispc
Copy link
Contributor

lispc commented Aug 14, 2025

reviewed. Don't force push from now on

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