Skip to content
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

feat(prover): integrate proving-sdk && support multiple task types #1587

Open
wants to merge 45 commits into
base: develop
Choose a base branch
from

Conversation

yiweichi
Copy link
Member

@yiweichi yiweichi commented Jan 5, 2025

Purpose or design rationale of this PR

Describe your change. Make sure to answer these three questions: What does this PR do? Why does it do it? How does it do it?

  1. Refactor prover to integrate scroll-proving-sdk.
  2. Support multiple task types in one prover process

PR title

Your PR title must follow conventional commits (as we are doing squash merge for each PR), so it must start with one of the following types:

  • build: Changes that affect the build system or external dependencies (example scopes: yarn, eslint, typescript)
  • ci: Changes to our CI configuration files and scripts (example scopes: vercel, github, cypress)
  • docs: Documentation-only changes
  • feat: A new feature
  • fix: A bug fix
  • perf: A code change that improves performance
  • refactor: A code change that doesn't fix a bug, or add a feature, or improves performance
  • style: Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc)
  • test: Adding missing tests or correcting existing tests

Deployment tag versioning

Has tag in common/version.go been updated or have you added bump-version label to this PR?

  • No, this PR doesn't involve a new deployment, git tag, docker image tag
  • Yes

Breaking change label

Does this PR have the breaking-change label?

  • No, this PR is not a breaking change
  • Yes

Summary by CodeRabbit

Based on the comprehensive summary of changes, here are the updated release notes:

  • Version Update

    • Incremented version from v4.4.86 to v4.4.87
  • Major Architectural Changes

    • Transitioned prover to an asynchronous architecture
    • Replaced multiple client and handler implementations with a more modular design
    • Simplified configuration management
  • Dependency Updates

    • Added scroll-proving-sdk dependency
    • Added async-trait dependency
  • Configuration Changes

    • Restructured prover configuration file
    • Updated configuration handling to use new SDK
    • Removed legacy configuration management code
  • Proof Generation

    • Enhanced circuit handling with asynchronous methods
    • Improved concurrency control for proof generation
    • Updated proof request and task management
  • Removed Components

    • Deleted legacy coordinator client implementations
    • Removed task processing and caching mechanisms
    • Eliminated version tracking in prover module

@yiweichi yiweichi added the bump-version Bump the version tag for deployment label Jan 5, 2025
Copy link

coderabbitai bot commented Jan 5, 2025

Walkthrough

This pull request represents a significant update to the Scroll prover system, primarily focusing on versioning, dependency management, and the restructuring of configuration files. The version number has been incremented from "v4.4.86" to "v4.4.87", reflecting a new release. Additionally, the Cargo.toml file for the prover package has been updated to include new dependencies and improve formatting. Configuration management has been restructured in config.json, while several files related to the coordinator client and task processing have been removed, indicating a shift in the architecture.

Changes

File Change Summary
common/version/version.go Version incremented from v4.4.86 to v4.4.87
prover/Cargo.toml Added scroll-proving-sdk and async-trait dependencies; reformatted existing dependencies
prover/config.json Restructured configuration with new fields and object hierarchy; removed and modified several fields
prover/src/config.rs File removed; related configuration structures and methods deleted
prover/src/coordinator_client.rs File removed; CoordinatorClient struct and methods deleted
prover/src/coordinator_client/types.rs File removed; related data structures deleted
prover/src/geth_client.rs File removed; GethClient struct and methods deleted
prover/src/key_signer.rs File removed; KeySigner struct and methods deleted
prover/src/main.rs Converted to async main function; removed multiple modules
prover/src/prover.rs Replaced Prover with LocalProver, added async methods
prover/src/task_cache.rs File removed; TaskCache struct and methods deleted
prover/src/task_processor.rs File removed; TaskProcessor struct and methods deleted
prover/src/types.rs Updated field types from TaskType to CircuitType
prover/src/utils.rs Updated function names and types to reflect CircuitType
prover/src/zk_circuits_handler.rs Transitioned to async methods; updated type handling
prover/src/zk_circuits_handler/darwin.rs Transitioned to async methods; updated concurrency management
prover/src/zk_circuits_handler/darwin_v2.rs Transitioned to async methods; updated concurrency management
prover/src/coordinator_client/api.rs File removed; Api struct and methods deleted
prover/src/coordinator_client/errors.rs File removed; ErrorCode enum and related structures deleted
prover/src/coordinator_client/listener.rs File removed; Listener trait deleted
prover/src/version.rs File removed; version management functionality deleted

Possibly related PRs

Suggested reviewers

  • georgehao
  • colinlyguo
  • sbaizet-ledger

Poem

🐰 A Prover's New Leap

With a hop and a skip, we change our tune,
Version's up high, like a bright, shining moon.
Dependencies added, the code's now a dance,
In the realm of async, we take our chance!
Prover's delight, in circuits we trust,
CodeRabbit's magic, in Rust, it's a must! ✨


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ 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.
    • Generate unit testing code for this file.
    • 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. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • 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 src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR. (Beta)
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

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

Documentation and Community

  • 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.

@yiweichi yiweichi mentioned this pull request Jan 5, 2025
13 tasks
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: 6

🧹 Nitpick comments (23)
prover/src/zk_circuits_handler.rs (3)

24-28: Introduction of async trait methods.

Defining async trait methods (get_vk, get_proof_data) fosters concurrency. Make sure to handle possible race conditions if concurrent calls rely on shared state.


47-51: Initialization of AssetsDirEnvConfig.

Handling potential initialization errors with a log and an exit. Consider returning a typed error instead of forcibly exiting, which might hamper testability or graceful recovery in production.


140-166: Async initialization of verification keys.

Looping over each builder and each ProverType is valid, but be aware of performance if multiple fork names and multiple prover types grow in number. Caching or parallelizing might be beneficial if the operation is costly.

prover/prover.rs (2)

50-51: Initialization of verification keys.

The init_vks call here returns vks but we don’t see direct usage in this code snippet. Make sure the subsequent flow references or caches these in the coordinator appropriately.


180-183: do_submit() minimal wrapper around submit_proof().

Straightforward approach. Logging extra details on success/failure might aid debugging, but not strictly required.

prover/src/prover.rs (3)

35-53: get_vks() implementation.

Extracts prover_types from the incoming circuit list. Thorough approach to building the response. If circuit definitions grow, consider parallelizing the VK retrieval.


128-139: LocalProver::new(): building the provider and setting initial state.

No immediate issues, though error handling is done via unwrap() inside. Maybe consider returning a Result<Self> to handle creation errors gracefully.


142-179: do_prove() storing a spawned handle in current_task.

• Only one handle is kept at a time.
• Potentially set tasks to fail if a new request arrives before the existing finishes.
This might be intended but double-check if multiple concurrent tasks are needed.

coordinator/internal/logic/provertask/bundle_prover_task.go (1)

90-95: Repetitive logic across multiple tasks

The logic for fetching assigned vs. unassigned tasks in 50-task chunks appears duplicated in related files. Consider extracting this into a shared helper to maintain DRY (Don't Repeat Yourself) principles.

coordinator/internal/logic/provertask/batch_prover_task.go (1)

91-96: Dedicated methods for assigned vs. unassigned tasks

The separation of assigned vs. unassigned queries improves clarity. Consider error logging to confirm the number of tasks retrieved.

prover/src/zk_circuits_handler/darwin.rs (1)

281-285: End-to-end batch proof test coverage

Generating the batch proof with real chunk proofs improves confidence in the aggregator logic. Consider expanding coverage to negative test cases (e.g., invalid chunk proofs).

prover/src/zk_circuits_handler/darwin_v2.rs (1)

279-285: Genuine chunk traces and batch proof linking

Reading real chunk traces from disk, generating chunk proofs, and subsequently forming a batch proof validates the new concurrency approach at scale. Expanding negative scenarios could yield more robust coverage.

coordinator/internal/orm/chunk.go (3)

76-86: Consider using placeholders and clarifying the function name

  • Constructing the SQL string via fmt.Sprintf may be more prone to mistakes and could potentially pose security concerns in other contexts. Consider using GORM's chainable methods or parameterized queries (placeholders) for consistency and safety.
  • The function name is GetUnassignedChunk but returns a slice of chunks. Consider renaming it to GetUnassignedChunks to reflect this behavior accurately.

88-101: Review the comment regarding “limit”
The docstring says “retrieves unassigned chunk count based on the specified limit,” but there is no limit parameter in the signature or code. This discrepancy may cause confusion. Consider updating the docstring to remove or clarify any mention of a limit.


104-115: DRY up similar functionality
GetAssignedChunks mirrors much of the logic in GetUnassignedChunk. Consider abstracting out shared parts—like building the query or returning the chunks—into a helper function that takes the desired status (assigned vs. unassigned). This would reduce duplicative code and simplify maintenance.

coordinator/internal/orm/prover_task.go (1)

151-167: Consider using .First() and handling the no-record scenario.
Currently, the method uses .Find() with .Limit(1), which will not return an error if no record is found. This could silently return an empty struct. Consider using .First(&proverTask) and handling gorm.ErrRecordNotFound to improve clarity, ensuring the caller knows when no matching record is returned.

coordinator/internal/orm/bundle.go (3)

57-70: Mitigate potential SQL injection by using placeholders.
The raw SQL string uses fmt.Sprintf to embed parameters (e.g., proving_status, limit). Although these fields are numeric, it’s generally safer to use parameter placeholders (i.e., ?) binding where possible to reduce the risk of SQL injection.


71-83: Efficient counting approach recommendation.
The method correctly counts unassigned bundles. Consider using raw SQL placeholders or GORM chain calls to avoid string formatting. This will also keep queries consistent with GetUnassignedBundles.


86-99: Align method naming and queries with unassigned method.
This method’s logic mirrors GetUnassignedBundles but for assigned bundles. Maintain consistent patterns—particularly using placeholders and error messages—to ensure uniformity and reduce code maintenance overhead.

coordinator/internal/orm/batch.go (3)

81-93: Safeguard raw SQL in GetUnassignedBatches.
Similar to other methods, consider utilizing GORM clause builders or parameterized queries instead of fmt.Sprintf to mitigate potential SQL injection risks, even if arguments are numeric today.


95-108: Parallel the structure of your retrieval methods.
Use the same style (raw or parameter-based) for GetUnassignedBatchCount to remain consistent across your codebase. This improves maintainability and consistency.


111-122: Maintain consistent naming for debug and user-facing error messages.
To make logs more searchable and consistent, ensure that messages and method references match (i.e., “Batch.GetAssignedBatches error” consistently).

prover/Cargo.toml (1)

46-46: Consider specifying a minimum version for async-trait.

While using "0.1" allows for compatible updates, consider specifying a minimum version (e.g., "^0.1.50") to ensure known bug fixes and security patches are included.

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between f92029a and 1e2e253.

⛔ Files ignored due to path filters (1)
  • prover/Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (28)
  • common/version/version.go (1 hunks)
  • coordinator/conf/config.json (1 hunks)
  • coordinator/internal/config/config.go (1 hunks)
  • coordinator/internal/logic/provertask/batch_prover_task.go (2 hunks)
  • coordinator/internal/logic/provertask/bundle_prover_task.go (2 hunks)
  • coordinator/internal/logic/provertask/chunk_prover_task.go (2 hunks)
  • coordinator/internal/logic/provertask/prover_task.go (1 hunks)
  • coordinator/internal/orm/batch.go (1 hunks)
  • coordinator/internal/orm/bundle.go (1 hunks)
  • coordinator/internal/orm/chunk.go (1 hunks)
  • coordinator/internal/orm/prover_task.go (1 hunks)
  • prover/Cargo.toml (2 hunks)
  • prover/config.json (1 hunks)
  • prover/prover.rs (1 hunks)
  • prover/src/config.rs (0 hunks)
  • prover/src/coordinator_client.rs (0 hunks)
  • prover/src/coordinator_client/types.rs (3 hunks)
  • prover/src/geth_client.rs (0 hunks)
  • prover/src/key_signer.rs (0 hunks)
  • prover/src/main.rs (3 hunks)
  • prover/src/prover.rs (1 hunks)
  • prover/src/task_cache.rs (0 hunks)
  • prover/src/task_processor.rs (0 hunks)
  • prover/src/types.rs (2 hunks)
  • prover/src/utils.rs (2 hunks)
  • prover/src/zk_circuits_handler.rs (7 hunks)
  • prover/src/zk_circuits_handler/darwin.rs (10 hunks)
  • prover/src/zk_circuits_handler/darwin_v2.rs (10 hunks)
💤 Files with no reviewable changes (6)
  • prover/src/task_processor.rs
  • prover/src/config.rs
  • prover/src/geth_client.rs
  • prover/src/task_cache.rs
  • prover/src/key_signer.rs
  • prover/src/coordinator_client.rs
✅ Files skipped from review due to trivial changes (1)
  • common/version/version.go
🔇 Additional comments (93)
prover/src/main.rs (3)

12-13: Transitioning to LocalProver import looks consistent.

The new imports from prover::LocalProver and scroll_proving_sdk align with the updated architecture for multiple task types.


31-33: Adoption of asynchronous runtime is appropriate.

Using #[tokio::main] and calling init_tracing() is a solid move for asynchronous operations. Just ensure all downstream async calls handle errors gracefully or propagate them further if critical.


51-51: Consider error handling for the prover.run() call.

Right now, any potential error from prover.run().await is ignored. Check if error handling or logging may be necessary to diagnose potential runtime failures.

prover/src/types.rs (3)

4-4: Direct usage of CircuitType is aligned with the new approach.

Importing CircuitType from scroll_proving_sdk looks consistent with the removal of TaskType.


51-51: Replacement of TaskType with CircuitType in Task struct.

This correctly aligns with the updated circuit-based logic in the SDK. Ensure all references to task_type usage match the new type.


61-61: Refactoring ProofDetail to use CircuitType.

Consistent usage of CircuitType helps unify proof workflows. Looks good.

prover/src/zk_circuits_handler.rs (12)

5-5: Refactored import to retrieve ProverType and circuit logic from utils.

Combining multiple components in one import statement is reasonable. No issues here.


7-7: Use of async_trait::async_trait.

This trait is crucial to enable async methods in traits. The approach is correct.


10-13: Importing from scroll_proving_sdk for local config and circuit types.

The shift to using LocalProverConfig and CircuitType is consistent with the design shift. Looks good.


31-32: Type alias for CircuitsHandlerBuilder.

Clear definition. It’s helpful to unify how circuits handlers are created.


34-35: CircuitsHandlerProvider config and builder map.

This structure neatly centralizes circuit creation logic.


39-40: Tracking the current fork name and circuit.

Maintaining these as optional fields is good. Be mindful of concurrency if multiple threads query this provider.


43-44: new(config: LocalProverConfig) returning Result<Self>.

Returning a Result is correct for error propagation.


54-54: Builder closure references config for circuit paths.

Looks appropriate. Make sure the config paths exist and are validated.


75-75: Second builder closure for DarwinV2Handler.

Consistent pattern with the first builder. Good maintainability.


99-99: current_prover_type set to None initially.

Indicates no default solver type. This is fine, but watch for usage before assignment.


109-110: get_circuits_handler concurrency concerns.

Caching a single current_circuit might cause conflicts if multiple calls to this function occur in parallel for different forks. Ensure external access is well-synchronized or each request runs in a single flow.


126-130: Updating cached fields after building a new handler.

This approach is correct for reusing the same circuit. Confirm that switching from one fork name to another is thread-safe if multiple threads are possible.

prover/prover.rs (13)

1-17: Introduction of the new Prover struct for orchestrating tasks.

This file manages config, signer, coordinator client, etc. Ensure each dependency is tested or mocked for integration.


18-24: Prover<'a> fields referencing RefCell wrappers.

RefCell allows interior mutability, but can hide borrow panics at runtime if not carefully handled. Continue validating concurrency usage or consider using more explicit concurrency primitives.


26-27: new(config, coordinator_listener): aggregator approach.

Overall aggregator approach is fine—just watch for potential partial initialization if any step fails.


31-35: Conditional Geth client creation based on ProverType::Chunk.

Makes sense for tasks requiring direct chain queries. Good guard approach.


47-50: Instantiating CircuitsHandlerProvider with config, geth_client.clone().

Keep an eye on potential data races if CircuitsHandlerProvider also reads/writes the same client object.


54-55: Creation of CoordinatorClient with vks.

Indicates the new approach is to pass VKs upfront. Ensure the client is equipped to handle an updated key set if keys change at runtime.


65-66: Constructor returning Ok(prover).

Straightforward, no issues.


68-70: get_public_key() delegates to the KeySigner.

Well-structured approach. Good encapsulation.


72-114: fetch_task() logic for building a GetTaskRequest and retrieving tasks.

• Aggregates multiple TaskTypes from config.
• Conditionally retrieves block number if we have Chunk in prover_types.
• Returns an error if the block is zero or not found.
Overall logic is fine. Just ensure any concurrency scenario around coordinator calls is addressed.


116-130: prove_task(): bridging from Task to circuit handler.

Identifies ProverType from task_type with get_prover_type. Could fail gracefully if no type is found. Then retrieves a circuit handler and calls do_prove(). Good separation of concerns.


132-141: do_prove(): constructing ProofDetail.

Populates the proof detail once proof data is retrieved from the handler. Straightforward and consistent.


143-159: submit_proof() building a SubmitProofRequest.

Clean approach to sending proof data. Just remain consistent with error handling if the coordinator call fails.


161-178: submit_error() building a request with failure details.

Neat flow for capturing errors. The partial data is helpful for debugging.

prover/src/prover.rs (11)

2-2: Dependency on utils::get_prover_type.

Matches the removal of TaskType by deriving ProverType from CircuitType.


5-5: Usage of anyhow::Result.

Offers convenient error handling. Ensure distinct error contexts for deeper debugging.


6-6: Adopting async_trait::async_trait for concurrency.

Aligns with the new async-based design.


7-16: Integration with scroll_proving_sdk::prover::ProvingService.

The trait usage is consistent with the approach to unify local proving tasks. Excellent job leveraging the existing SDK.


23-27: LocalProver struct: concurrency fields with RwLock and Mutex.

Using a read-write lock for the circuits provider is reasonable. The Arc<Mutex<Option<JoinHandle>>> for the current task implies a single concurrent proof at a time. This is okay if you want to strictly serialize tasks.


30-33: is_local() returning true.

Simple trait method, correct for local usage.


54-65: prove() method with fallback on error building a ProveResponse.

Neatly handled; the error path uses build_prove_error_response with minimal overhead. Good practice.


66-74: get_circuits_handler behind a write lock.

Acquiring a write lock while building or fetching the handler is correct if the underlying data might change. Just confirm that high concurrency usage is acceptable if tasks are queued or slowed by the lock.


85-124: query_task() logic for tracking ongoing tasks.

• Removes the handle if completed, returns success or error.
• If not finished, returns TaskStatus::Proving.
• If no current task, returns a failure.
This is a straightforward approach for single-task concurrency, but ensure that multiple tasks or queries won’t conflict.


183-204: build_prove_error_response(): defaulting fields to empty or undefined.

Ensure downstream consumers handle these placeholder values properly.


206-225: build_query_task_response(): similar placeholder usage.

Same note about placeholders. Good consistent error response structure.

coordinator/internal/logic/provertask/chunk_prover_task.go (4)

7-7: Import "strings" looks appropriate

The newly introduced import for "strings" appears to be used by the code to detect external prover prefixes. This seems valid and aligns with the new logic for ExternalProverNamePrefix.


81-82: Offset initialization is valid

Initializing assignedOffset and unassignedOffset to zero provides a clear approach to interleaving assigned vs. unassigned tasks. No concerns here.


89-93: Enhanced error handling is helpful

Fetching unassigned chunks within a separate method call and handling errors distinctly can improve debugging clarity and reusability.


95-119: Confirm concurrency safety in the assignment loop

While iterating over assigned and unassigned tasks, ensure no race conditions occur if multiple goroutines invoke Assign simultaneously. Consider using proper transaction isolation or locking at the ORM level to avoid conflicting updates to the same tasks.

coordinator/internal/logic/provertask/bundle_prover_task.go (3)

7-7: Import "strings" is appropriate

This import is used to detect external prover prefixes and is consistent with the approach seen in chunk_prover_task.go.


83-84: Good practice: offset variables

Same approach as in the chunk task, storing offsets to separate assigned from unassigned tasks is consistent and maintains clarity.


97-119: Avoid re-assigning failing tasks to the same prover

This updated check prevents the same failing job from cycling to the identical prover. Verify that this logic covers all edge cases, including tasks that failed for different reasons.

coordinator/internal/logic/provertask/batch_prover_task.go (2)

83-84: Offset approach is consistent

Initializing two parallel offsets for assigned and unassigned sets is consistent with the approach in chunk_prover_task.go and bundle_prover_task.go.


97-119: Loop termination conditions

The loop breaks early if tmpBatchTask is nil; this might cause repeated nil returns if multiple offset increments exhaust both slices quickly. Ensure that this meets your design objectives for distributing tasks evenly across provers.

prover/src/zk_circuits_handler/darwin.rs (15)

2-11: Imports complement the move to async & concurrency

The introduced imports (async_trait, RwLock, CircuitType, etc.) align with the asynchronous refactor and concurrency approach, making the code thread-safe and future-proof for multi-prover usage.


42-43: Transition to RwLock for concurrency

Changing from a mutable reference or RefCell to RwLock is a solid improvement for safe concurrent access to chunk_prover and batch_prover.


76-81: Initialize RwLock as intended

Using RwLock::new to wrap the chunk or batch prover is consistent with the concurrency shift. Verify that the underlying library references are Send + Sync compatible.


90-91: Factory method pattern reiterated

new(prover_type, params_dir, assets_dir) simply delegates to new_multi, which is good for code reusability.


100-101: Use .write() for proof generation

Acquiring a write lock before generating the chunk proof is necessary because the prover modifies internal state. Ensure that read locks are used whenever possible to reduce contention.


109-111: Parsing ProveRequest input

Deserializing prove_request.input into Vec<BlockTrace> is clear and ensures the method remains decoupled from external data structures. Good usage of serde_json.


127-133: Validate chunk protocol before generating batch proof

Invoking check_protocol_of_chunks with a write lock emphasizes controlled state changes. The check for non-matching chunk protocol helps avoid producing invalid proofs.


150-153: New asynchronous method signature

Declaring gen_bundle_proof_raw as async ensures consistent concurrency across all proof generation methods. Good alignment with the rest of the codebase.


155-155: Synchronized bundle proof generation

Using write().await on batch_prover prevents concurrent writes on shared BatchProver state. This is an essential concurrency safeguard.


166-168: ProveRequest-based method parameters

Transitioning from a raw Task to ProveRequest is more flexible and decouples the request schema from the internal logic.


179-195: Asynchronous read locks for VK retrieval

Using .read().await ensures multiple concurrent read operations can proceed, as verifying the VK does not require exclusive access.


200-204: Unified entry point for proof data retrieval

get_proof_data cleanly switches among multiple circuit types. The usage of pattern matching over prove_request.circuit_type is succinct and maintainable.


249-250: Asynchronous test annotation

Using #[tokio::test] for testing is consistent with the newly introduced async logic. This approach ensures the test harness aligns with asynchronous patterns.


258-260: Chunk VK retrieval and validation

Fetching the chunk VK asynchronously and comparing it with a file-based reference is a solid end-to-end test for verifying the correctness of the loaded verifier key.


Line range hint 363-369: Consistent VK checks across circuit types

Ensuring that the on-file VK matches the runtime VK is critical for guaranteeing the circuit's correctness. Good practice for regression checks.

prover/src/zk_circuits_handler/darwin_v2.rs (15)

2-11: Asynchronous concurrency readiness

The newer imports (async_trait, RwLock, CircuitType) align with an asynchronous concurrency model, just like in darwin.rs.


42-43: Use of RwLock ensures write safety

Utilizing RwLock<ChunkProver> and RwLock<BatchProver> enforces concurrency while allowing multiple reads and exclusive writes, preventing data corruption.


76-81: Param-based RwLock initializations

Wrapping each prover in RwLock::new(...) is a natural progression to protect the state. Confirm that each underlying struct is indeed threadsafe and does not rely on thread-local references.


90-91: Convenient constructor

Delegation from new to new_multi retains DRY consistency, preventing logic duplication for single-prover vs. multi-prover configurations.


100-101: Write lock for chunk proof

Similar to DarwinHandler, using prover.write().await before modifying the chunk prover’s state. This is an essential concurrency safeguard.


109-111: Deserialization from ProveRequest

Parsing JSON input for chunk traces fosters extensibility and lowers coupling to specific data shapes. Good approach for maintaining loose coupling.


127-133: Protocol validation with RwLock

Ensuring chunk proofs conform to protocol specs under a write lock helps avoid partial modifications from concurrent tasks. This approach is consistent with concurrency best practices.


150-153: Extending async pattern to bundle proofs

The method signature for gen_bundle_proof_raw unifies all proof generation tasks (chunk, batch, bundle) under the same async pattern.


155-155: Consolidated concurrency approach for bundle proofs

Acquiring a write lock ensures no overlapping writes to the same batch prover instance, preventing race conditions or data corruption.


166-168: Simplified request-based interface

Accepting ProveRequest in gen_bundle_proof is simpler than manually constructing tasks. This fosters a uniform request pattern across proof types.


179-195: Concurrent read for VK retrieval

Multiple asynchronous read locks allow concurrent VK retrieval requests, reducing lock contention where no state mutations are needed.


200-204: Consolidated proof entry point

get_proof_data gating logic remains consistent with darwin.rs, preventing code divergence between Darwin versions.


253-254: Async tests bolster reliability

Using #[tokio::test] ensures the test environment matches the concurrency patterns used in production code. This helps catch async-specific bugs earlier.


262-264: Retrieving VK ensures robust coverage

By checking the chunk VK in tests, you validate the new concurrency model does not affect the loading and usage of verification keys.


363-369: VK consistency checks remain a crucial safeguard

Ensuring that the VK on disk matches the runtime VK is vital to preventing silent circuit mismatches. This is an essential final verification step.

prover/src/utils.rs (3)

4-5: New imports align well with updated task types
These imports support the shift to CircuitType. Everything looks consistent and correct here.


28-33: Clean rename to get_circuit_types
Renaming from get_task_types to get_circuit_types clarifies intent and aligns code with the new type system. The return values for ProverType::Chunk and ProverType::Batch are straightforward and valid.


35-40: Reverse mapping from CircuitType to ProverType
The reverse mapping logic is consistent, with CircuitType::Undefined leading to None and Bundle sharing ProverType::Batch. No issues found.

prover/src/coordinator_client/types.rs (4)

2-5: Appropriate import for CircuitType
Replacing the old TaskType import with CircuitType matches the broader refactor.


62-62: Field updated to CircuitType
Updating task_types to Vec<CircuitType> in GetTaskRequest is consistent with the new refactor and naming conventions.


70-70: Task type field uses CircuitType
GetTaskResponseData now stores task_type as CircuitType, aligning with other changes.


79-79: SubmitProofRequest uses CircuitType
Making task_type a CircuitType in SubmitProofRequest completes the transition from TaskType to CircuitType across the codebase.

coordinator/internal/config/config.go (1)

19-20: New external prover threshold
Adding ExternalProverThreshold provides clear, configurable control over external prover activation. This appears well-documented and neatly integrated.

coordinator/internal/logic/provertask/prover_task.go (1)

30-33: Simple, clear prefix for external prover naming
Defining ExternalProverNamePrefix = "external" is straightforward. If usage grows more complex, consider elevating this to a configurable value.

prover/config.json (1)

6-6: Confirm multi-prover support downstream.
Changing from a single prover_type to an array prover_types is a great step to allow multiple types. Ensure that all affected code handles this array properly (e.g., reading multiple values, passing them along, etc.).

coordinator/conf/config.json (1)

5-5: Verify external prover threshold validation.

The hardcoded threshold value needs validation checks in the code to prevent potential system instability.

✅ Verification successful

Let me gather more information about the validation of this threshold.


The external_prover_threshold is properly used as a control mechanism

The threshold value is used as intended in the codebase to control task assignment behavior:

  • In chunk_prover_task.go, it prevents task assignment when unassigned chunks are below the threshold
  • In bundle_prover_task.go, it controls bundle task assignment based on the threshold
  • In batch_prover_task.go, it manages batch task assignment using the same threshold logic

While there's no explicit validation of the threshold value itself, this is acceptable because:

  1. The value is used in simple numerical comparisons that are safe regardless of the configured number
  2. The threshold acts as a control gate rather than a critical safety parameter
  3. The implementation properly handles the configured value in all relevant prover task types
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for validation of external_prover_threshold in the codebase
rg -A 5 "external_prover_threshold" 

# Look for config validation patterns
ast-grep --pattern 'func $_(config $_) error {
  $$$
  if config.ProverManager.$_ {
    $$$
  }
  $$$
}'

Length of output: 1077


Script:

#!/bin/bash
# Search for validation or usage of ExternalProverThreshold
rg -A 10 "ExternalProverThreshold" 

# Look for config validation functions in config.go
ast-grep --pattern 'func $_(config $_) {
  $$$
}'

# Search for validation patterns specifically in coordinator package
rg -A 5 "validate|check.*config" coordinator/

Length of output: 11543

prover/Cargo.toml (1)

34-34: 🛠️ Refactor suggestion

Use tagged versions instead of git revisions for better reproducibility.

The scroll-proving-sdk dependency is pinned to a specific git revision (6dd13b6). While this ensures reproducibility, using tagged versions is preferred for better maintainability and security tracking.

-scroll-proving-sdk = { git = "https://github.com/scroll-tech/scroll-proving-sdk.git", rev = "6dd13b6"}
+scroll-proving-sdk = { git = "https://github.com/scroll-tech/scroll-proving-sdk.git", tag = "v0.1.0" }  # Use appropriate version tag

Also, verify if this dependency has been audited for security vulnerabilities.

prover/src/main.rs Outdated Show resolved Hide resolved
prover/prover.rs Outdated Show resolved Hide resolved
coordinator/internal/logic/provertask/chunk_prover_task.go Outdated Show resolved Hide resolved
coordinator/internal/logic/provertask/batch_prover_task.go Outdated Show resolved Hide resolved
coordinator/conf/config.json Outdated Show resolved Hide resolved
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: 1

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between fa87cfa and da6be90.

⛔ Files ignored due to path filters (1)
  • prover/Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (1)
  • prover/src/main.rs (3 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (2)
  • GitHub Check: fmt
  • GitHub Check: tests
🔇 Additional comments (3)
prover/src/main.rs (3)

12-13: LGTM! Clean integration of scroll-proving-sdk.

The imports are well-organized and correctly bring in the necessary components from the scroll-proving-sdk.


Line range hint 15-30: LGTM! Well-structured argument parsing.

The command-line argument handling is clean and follows Rust best practices using clap.


31-32: LGTM! Robust error handling implementation.

The code properly handles errors using anyhow::Result and safely handles the optional local prover configuration, addressing the previous review comment about unwrap().

Also applies to: 44-50

prover/src/main.rs Show resolved Hide resolved
@yiweichi yiweichi requested a review from georgehao January 6, 2025 13:27
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: 2

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 2acb405 and 6ce5688.

⛔ Files ignored due to path filters (1)
  • prover/Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (2)
  • prover/Cargo.toml (2 hunks)
  • prover/config.json (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • prover/Cargo.toml
🔇 Additional comments (3)
prover/config.json (3)

30-30: Validate database path handling.

The db_path includes the prover name for uniqueness, but ensure:

  1. The path is properly resolved relative to the application root
  2. The directory exists or is created with appropriate permissions

2-3: Verify the security implications of removed keystore configuration.

The removal of keystore_path and keystore_password fields raises security concerns. Please clarify:

  1. How are prover credentials now managed?
  2. Is the new keys_dir a replacement for the keystore functionality?

18-28: Verify circuit version compatibility.

The configuration includes both low and high version circuits with different hard fork names. Please ensure:

  1. The specified circuit version "v0.13.1" is compatible with both hard forks
  2. The params and assets paths are correctly configured for each version
✅ Verification successful

Circuit version compatibility verified.

The codebase implements version compatibility through separate handlers (DarwinHandler for "bernoulli" and DarwinV2Handler for "curie"), each designed for its specific circuit version. The shared path structure ("params" and "assets") is validated during handler initialization, ensuring correct configuration for both versions.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for version compatibility checks and path validations
rg -A 5 'version|compatibility|hard_fork' --type rust

# Search for path validation logic
ast-grep --pattern 'fn $_(params_path: $_) {
  $$$
}'

Length of output: 11033


Script:

#!/bin/bash
# Search for Darwin handler implementations and version checks
ast-grep --pattern 'impl $_ for DarwinHandler {
  $$$
}'

ast-grep --pattern 'impl $_ for DarwinV2Handler {
  $$$
}'

# Search for version compatibility checks
rg -A 5 'ZK_VERSION|DEFAULT_ZK_VERSION' --type rust

# Search for path validation in handlers
rg -A 10 'fn new.*params_path.*assets_path' --type rust

Length of output: 5970


Script:

#!/bin/bash
# Search for handler constructors and initialization
rg -A 10 'impl (Darwin|DarwinV2)Handler' --type rust

# Search for version compatibility checks in the codebase
rg -A 5 'compatibility|supported.*version|version.*check' --type rust

# Search for path validation during initialization
rg -A 10 'fn new.*DarwinHandler|fn new.*DarwinV2Handler' --type rust

Length of output: 1913


Script:

#!/bin/bash
# Search for circuit version usage and validation
rg -A 5 'circuit.*version|version.*circuit' --type rust

# Search for path validation in implementation
rg -A 10 'params_dir.*assets_dir|validate.*path' --type rust

# Search for version-specific configurations
ast-grep --pattern 'struct $_ {
  $$$
  version: $_,
  $$$
}'

Length of output: 7476

prover/config.json Outdated Show resolved Hide resolved
prover/config.json Show resolved Hide resolved
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: 1

🧹 Nitpick comments (1)
prover/config.json (1)

17-26: Consolidate duplicate configuration paths.

Both low_version_circuit and high_version_circuit configurations contain identical params_path and assets_path. Consider moving these common paths to a shared configuration section.

   "prover": {
     "circuit_type": [1,2,3],
     "circuit_version": "v0.13.1",
+    "common": {
+      "params_path": "params",
+      "assets_path": "assets"
+    },
     "local": {
       "low_version_circuit": {
-        "hard_fork_name": "bernoulli",
-        "params_path": "params",
-        "assets_path": "assets"
+        "hard_fork_name": "bernoulli"
       },
       "high_version_circuit": {
-        "hard_fork_name": "curie",
-        "params_path": "params",
-        "assets_path": "assets"
+        "hard_fork_name": "curie"
       }
     }
   }
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between f431966 and f9b9fd5.

📒 Files selected for processing (1)
  • prover/config.json (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (2)
  • GitHub Check: clippy
  • GitHub Check: tests
🔇 Additional comments (3)
prover/config.json (3)

4-8: Environment-specific configuration needs implementation.

The coordinator's base_url is hardcoded to localhost, which may not work in different environments.


14-15: Document circuit types and consider using named constants.

The circuit_type array uses magic numbers [1,2,3] without clear documentation.


2-3: Consider using absolute paths for critical directories.

The keys_dir path is specified as a relative path. This could lead to runtime issues if the working directory changes.

Run this script to check if there are any path resolution handlers in the codebase:

prover/config.json Show resolved Hide resolved
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: 2

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between f9b9fd5 and fc8856c.

📒 Files selected for processing (2)
  • prover/config.json (1 hunks)
  • prover/prover.test (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • prover/prover.test
⏰ Context from checks skipped due to timeout of 90000ms (2)
  • GitHub Check: clippy
  • GitHub Check: tests
🔇 Additional comments (5)
prover/config.json (5)

4-8: Environment-specific configuration needed

The coordinator's base_url is hardcoded to localhost, which won't work in different environments.


14-14: Document circuit types and use constants

The circuit_types array uses magic numbers [1,2,3] without clear documentation.


15-15: Add semantic version validation

The circuit_version field needs proper semantic version validation.


2-3: Verify security implications of authentication changes

The removal of keystore_path and keystore_password fields suggests a change in the authentication mechanism. Please ensure:

  1. The new authentication method is properly documented
  2. Sensitive credentials are handled securely
✅ Verification successful

Authentication changes verified as secure refactoring

The changes represent a simplification of the configuration while maintaining proper security:

  • eth-keystore crate (v0.5.0) is used for secure key management
  • Unique prover identification is preserved through prover_name_prefix
  • keys_dir provides a standardized approach to key storage
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for new authentication mechanism
rg -A 5 "auth|credentials|keystore|password" --type rust

# Check if keys_dir is used securely
rg -A 5 "keys_dir" --type rust

Length of output: 89


Script:

#!/bin/bash
# Find what type of files exist in prover directory
fd . prover --type f

# Search for authentication-related terms in all files
rg -A 5 "auth|credentials|keystore|password|keys_dir" prover/

# Search for prover name prefix usage
rg -A 5 "prover.*name.*prefix|prover-1" prover/

Length of output: 2783


29-29: Verify database path handling

Ensure that:

  1. The database path is properly validated and created
  2. The path remains unique when multiple prover instances are running

prover/config.json Show resolved Hide resolved
prover/config.json Show resolved Hide resolved
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: 4

🔭 Outside diff range comments (1)
prover/src/zk_circuits_handler/darwin.rs (1)

Line range hint 293-305: Implement make_batch_task_detail function.

The make_batch_task_detail function is currently a stub, which affects test functionality. This needs to be implemented to enable proper testing of batch operations.

Would you like me to help implement this function with proper batch task detail construction?

♻️ Duplicate comments (1)
prover/src/main.rs (1)

66-66: ⚠️ Potential issue

Handle the result from prover.run().

The result from prover.run().await is being ignored. This could hide potential errors during execution.

Apply this diff to properly handle the result:

-    prover.run().await;
+    prover.run().await?;
🧹 Nitpick comments (5)
prover/src/main.rs (1)

45-52: Consider extracting prover type initialization to a separate function.

The prover type initialization logic could be moved to a utility function for better readability and reusability.

+fn extract_prover_types(circuit_types: &[CircuitType]) -> Vec<ProverType> {
+    let mut prover_types = vec![];
+    circuit_types.iter().for_each(|circuit_type| {
+        if let Some(pt) = get_prover_type(*circuit_type) {
+            if !prover_types.contains(&pt) {
+                prover_types.push(pt);
+            }
+        }
+    });
+    prover_types
+}
+
 let cfg: Config = Config::from_file(args.config_file)?;
-let mut prover_types = vec![];
-cfg.prover.circuit_types.iter().for_each(|circuit_type| {
-    if let Some(pt) = get_prover_type(*circuit_type) {
-        if !prover_types.contains(&pt) {
-            prover_types.push(pt);
-        }
-    }
-});
+let prover_types = extract_prover_types(&cfg.prover.circuit_types);
prover/src/zk_circuits_handler.rs (1)

131-157: Optimize prover_types cloning in init_vks.

The method clones prover_types for each iteration of the outer loop. Consider passing a reference instead.

-    pub async fn init_vks(
+    pub async fn init_vks<'a>(
         &self,
         config: &LocalProverConfig,
-        prover_types: Vec<ProverType>,
+        prover_types: &'a [ProverType],
     ) -> Vec<String> {
         let mut vks: Vec<String> = Vec::new();
         for (hard_fork_name, build) in self.circuits_handler_builder_map.iter() {
             let handler =
-                build(prover_types.clone(), config).expect("failed to build circuits handler");
+                build(prover_types.to_vec(), config).expect("failed to build circuits handler");

-            for prover_type in prover_types.iter() {
+            for prover_type in prover_types {
prover/src/zk_circuits_handler/darwin_v2.rs (3)

94-105: Improve error handling in gen_chunk_proof_raw.

The unreachable!() error message could be more descriptive to aid debugging.

-        unreachable!("please check errors in proof_type logic")
+        bail!("ChunkProver not initialized. Ensure ProverType::Chunk was included during initialization")

Line range hint 127-137: Consider adding detailed error context for batch proof validation.

The error messages could provide more context about the validation failure.

-                bail!("non-match chunk protocol")
+                bail!("Chunk proofs do not match the expected protocol version or parameters")

Line range hint 254-295: Consider improving test reliability and maintainability.

The test has several areas that could be improved:

  1. Heavy reliance on file system operations makes tests environment-dependent
  2. Hard-coded paths could cause issues in different environments
  3. Lack of smaller, focused test cases

Consider:

  • Adding smaller unit tests for individual components
  • Using in-memory test data where possible
  • Adding test setup validation
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between fc8856c and 5ee0d7a.

⛔ Files ignored due to path filters (1)
  • prover/Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (9)
  • prover/Cargo.toml (2 hunks)
  • prover/src/config.rs (0 hunks)
  • prover/src/main.rs (2 hunks)
  • prover/src/prover.rs (1 hunks)
  • prover/src/utils.rs (1 hunks)
  • prover/src/version.rs (0 hunks)
  • prover/src/zk_circuits_handler.rs (5 hunks)
  • prover/src/zk_circuits_handler/darwin.rs (11 hunks)
  • prover/src/zk_circuits_handler/darwin_v2.rs (11 hunks)
💤 Files with no reviewable changes (2)
  • prover/src/config.rs
  • prover/src/version.rs
🚧 Files skipped from review as they are similar to previous changes (1)
  • prover/Cargo.toml
⏰ Context from checks skipped due to timeout of 90000ms (2)
  • GitHub Check: clippy
  • GitHub Check: tests
🔇 Additional comments (8)
prover/src/utils.rs (1)

1-17: LGTM! Clean and well-structured utility functions.

The mapping between ProverType and CircuitType is consistent and handles all cases appropriately. The bidirectional mapping ensures proper type conversion in both directions.

prover/src/main.rs (1)

54-59: LGTM! Good error handling.

The use of ok_or_else for handling missing configuration is a clean approach.

prover/src/zk_circuits_handler.rs (2)

24-28: LGTM! Well-designed trait with proper async support.

The trait is correctly marked with async_trait and includes necessary bounds for thread safety (Send + Sync).


36-40: LGTM! Thread-safe state management.

The use of RwLock for the circuit handler and caching of the current circuit/fork name is appropriate for concurrent access.

prover/src/prover.rs (1)

24-29: LGTM! Well-structured concurrent state management.

The struct uses appropriate synchronization primitives (RwLock and Arc<Mutex>) for thread-safe access to shared state.

prover/src/zk_circuits_handler/darwin.rs (1)

42-43: LGTM! Proper concurrent access to provers.

The use of RwLock for both provers enables safe concurrent access while allowing multiple readers.

prover/src/zk_circuits_handler/darwin_v2.rs (2)

2-8: LGTM! Dependencies align with architectural changes.

The addition of async-trait, RwLock, and SDK imports properly supports the transition to an asynchronous architecture with improved concurrency control.


42-43: LGTM! Proper concurrent access control.

The transition from RefCell to RwLock enables safe concurrent access to the provers, which is essential for handling multiple task types simultaneously.

prover/src/prover.rs Outdated Show resolved Hide resolved
prover/src/zk_circuits_handler/darwin.rs Show resolved Hide resolved
prover/src/zk_circuits_handler/darwin_v2.rs Show resolved Hide resolved
prover/src/zk_circuits_handler/darwin_v2.rs Show resolved Hide resolved
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: 1

♻️ Duplicate comments (1)
prover/src/main.rs (1)

67-67: ⚠️ Potential issue

Handle the result from prover.run().

The result from prover.run().await is being ignored. This could hide potential errors during execution.

Apply this diff to properly handle the result:

-    prover.run().await;
+    prover.run().await?;
🧹 Nitpick comments (6)
prover/src/main.rs (3)

35-37: Consider adding context to errors.

While the async transition is well-implemented, consider wrapping the Result with additional context using .context() to provide more detailed error information.

-async fn main() -> anyhow::Result<()> {
+async fn main() -> anyhow::Result<()> {
+    // Add this at specific error points
+    foo().context("Failed to initialize prover")?;

42-43: Consider using std::process::exit with status code.

For better error handling conventions, consider using a non-zero exit code for error cases.

-        println!("version is {}", get_version());
-        std::process::exit(0);
+        println!("Version: {}", get_version());
+        std::process::exit(exitcode::OK);

46-53: Consider using more idiomatic Rust collections operations.

The circuit type filtering could be more concise using iterators and collections.

-    let mut prover_types = vec![];
-    cfg.prover.circuit_types.iter().for_each(|circuit_type| {
-        if let Some(pt) = get_prover_type(*circuit_type) {
-            if !prover_types.contains(&pt) {
-                prover_types.push(pt);
-            }
-        }
-    });
+    let prover_types: Vec<_> = cfg.prover.circuit_types
+        .iter()
+        .filter_map(|&circuit_type| get_prover_type(circuit_type))
+        .collect::<std::collections::HashSet<_>>()
+        .into_iter()
+        .collect();
prover/src/zk_circuits_handler.rs (3)

Line range hint 52-87: Consider unifying handler builders to reduce code duplication.

The handler_builder and next_handler_builder functions share identical structure with only implementation details differing. Consider refactoring to reduce duplication:

enum HandlerVersion {
    Low(LocalProverConfig),
    High(LocalProverConfig),
}

fn create_handler(
    version: HandlerVersion,
    prover_types: Vec<ProverType>,
) -> Result<Box<dyn CircuitsHandler>> {
    match version {
        HandlerVersion::Low(config) => {
            AssetsDirEnvConfig::enable_first();
            DarwinHandler::new(
                prover_types,
                &config.low_version_circuit.params_path,
                &config.low_version_circuit.assets_path,
            )
        }
        HandlerVersion::High(config) => {
            AssetsDirEnvConfig::enable_second();
            DarwinV2Handler::new(
                prover_types,
                &config.high_version_circuit.params_path,
                &config.high_version_circuit.assets_path,
            )
        }
    }.map(|handler| Box::new(handler) as Box<dyn CircuitsHandler>)
}

Line range hint 107-134: Improve error messages in get_circuits_handler.

The error messages "missing cached handler" and "missing builder" could be more descriptive:

-                    bail!("missing cached handler, there must be something wrong.")
+                    bail!("Cached circuit handler is unexpectedly None for fork: {}", hard_fork_name)
-                    bail!("missing builder, there must be something wrong.")
+                    bail!("No circuit handler builder found for fork: {}", hard_fork_name)

138-164: Consider parallel VK initialization for better performance.

The init_vks method processes each handler and circuit type sequentially. Consider using parallel execution with futures::stream::StreamExt:

use futures::stream::{self, StreamExt};

pub async fn init_vks(
    &self,
    config: &LocalProverConfig,
    prover_types: Vec<ProverType>,
) -> Vec<String> {
    stream::iter(self.circuits_handler_builder_map.iter())
        .flat_map(|(hard_fork_name, build)| {
            let handler = build(prover_types.clone(), config)
                .expect("failed to build circuits handler");
            stream::iter(prover_types.iter())
                .flat_map(move |prover_type| {
                    let handler = handler.clone();
                    stream::iter(get_circuit_types(*prover_type))
                        .map(move |task_type| (hard_fork_name, handler.clone(), task_type))
                })
        })
        .map(|(hard_fork_name, handler, task_type)| async move {
            if let Some(vk) = handler.get_vk(task_type).await {
                let encoded = utils::encode_vk(vk);
                log::info!(
                    "vk for {hard_fork_name}, is {encoded}, task_type: {:?}",
                    task_type
                );
                Some(encoded)
            } else {
                None
            }
        })
        .buffer_unordered(4) // Limit concurrent tasks
        .filter_map(|opt_vk| async move { opt_vk })
        .collect()
        .await
}
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 5ee0d7a and 4c83394.

📒 Files selected for processing (3)
  • prover/src/config.rs (0 hunks)
  • prover/src/main.rs (2 hunks)
  • prover/src/zk_circuits_handler.rs (5 hunks)
💤 Files with no reviewable changes (1)
  • prover/src/config.rs
⏰ Context from checks skipped due to timeout of 90000ms (2)
  • GitHub Check: compile
  • GitHub Check: tests
🔇 Additional comments (3)
prover/src/main.rs (2)

11-17: LGTM! Clean SDK integration.

The imports are well-organized, properly scoped, and the SDK integration follows Rust best practices.


55-65: LGTM! Improved error handling.

The code now properly handles the case of missing local prover configuration without using unwrap(), addressing the concerns raised in the previous review.

prover/src/zk_circuits_handler.rs (1)

24-28: LGTM! Thread-safe async trait implementation.

The trait has been properly updated to support async operations and thread safety with Send + Sync bounds. The transition from TaskType to CircuitType aligns well with the SDK integration.

prover/src/zk_circuits_handler.rs Outdated Show resolved Hide resolved
prover/Cargo.toml Show resolved Hide resolved
prover/prover.test Outdated Show resolved Hide resolved
prover/src/prover.rs Outdated Show resolved Hide resolved
prover/src/prover.rs Outdated Show resolved Hide resolved
prover/src/task_cache.rs Outdated Show resolved Hide resolved
@yiweichi yiweichi requested a review from Thegaram January 16, 2025 09:06
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: 3

♻️ Duplicate comments (1)
prover/src/prover.rs (1)

180-181: ⚠️ Potential issue

Address TODO comments in error response builders.

Both response builders use CircuitType::Undefined as a placeholder. This should be replaced with the actual circuit type from the request.

Also applies to: 203-204

🧹 Nitpick comments (2)
prover/src/prover.rs (2)

24-30: Remove commented-out code.

Line 129 contains commented-out code that should be removed if no longer needed.

-            // result: Arc::new(Mutex::new(Err(anyhow::Error::msg("prover not started")))),

138-142: Consider using a more robust task ID generation strategy.

The current task ID generation might not be suitable for distributed environments. Consider using UUIDs or a more robust distributed ID generation system.

-        let task_id = {
-            let mut next_task_id = self.next_task_id.lock().unwrap();
-            *next_task_id += 1;
-            *next_task_id
-        };
+        let task_id = uuid::Uuid::new_v4().to_string();
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 76a85a4 and 215a503.

⛔ Files ignored due to path filters (1)
  • prover/Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (2)
  • prover/Cargo.toml (2 hunks)
  • prover/src/prover.rs (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • prover/Cargo.toml
⏰ Context from checks skipped due to timeout of 90000ms (2)
  • GitHub Check: clippy
  • GitHub Check: tests

prover/src/prover.rs Outdated Show resolved Hide resolved
prover/src/prover.rs Outdated Show resolved Hide resolved
prover/src/prover.rs Outdated Show resolved Hide resolved
prover/Cargo.toml Outdated Show resolved Hide resolved
prover/src/prover.rs Show resolved Hide resolved
prover/src/prover.rs Outdated Show resolved Hide resolved
prover/src/prover.rs Show resolved Hide resolved
prover/src/prover.rs Outdated Show resolved Hide resolved
prover/src/prover.rs Outdated Show resolved Hide resolved
prover/src/prover.rs Outdated Show resolved Hide resolved
prover/src/prover.rs Outdated Show resolved Hide resolved
prover/src/zk_circuits_handler.rs Outdated Show resolved Hide resolved
prover/src/zk_circuits_handler.rs Outdated Show resolved Hide resolved
@yiweichi yiweichi requested a review from georgehao January 21, 2025 18:45
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: 0

🧹 Nitpick comments (6)
prover/src/zk_circuits_handler.rs (4)

24-28: Add documentation for the CircuitsHandler trait.

Consider adding documentation comments to describe:

  • The purpose of the trait
  • Expected behavior of each method
  • Error conditions and handling
+/// Handles circuit-related operations for the prover.
 #[async_trait]
 pub trait CircuitsHandler: Send + Sync {
+    /// Retrieves the verification key for the given circuit type.
+    /// Returns None if the key is not available.
     async fn get_vk(&self, task_type: CircuitType) -> Option<Vec<u8>>;

+    /// Generates proof data for the given prove request.
+    /// Returns the proof as a string or an error if proving fails.
     async fn get_proof_data(&self, prove_request: ProveRequest) -> Result<String>;
 }

47-49: Improve panic error message.

The error message could be more descriptive about what failed during initialization.

-            panic!("AssetsDirEnvConfig init failed: {:#}", e);
+            panic!("Failed to initialize AssetsDirEnvConfig. This is required for circuit proving. Error: {:#}", e);

124-129: Improve error handling in handler creation.

The current error handling could provide more context about what failed.

-                    let handler = builder(prover_types, &self.config)
-                        .expect("failed to build circuits handler");
+                    let handler = builder(prover_types, &self.config)
+                        .map_err(|e| anyhow::anyhow!(
+                            "Failed to build circuits handler for fork '{}': {}", 
+                            hard_fork_name, e
+                        ))?;

137-163: Improve VK initialization robustness and performance.

The current implementation has several areas for improvement:

  1. No error propagation from the build operation
  2. Silent failures when VK is empty
  3. Nested loops could be refactored for better readability

Consider refactoring to:

     pub async fn init_vks(
         &self,
         config: &LocalProverConfig,
         prover_types: Vec<ProverType>,
-    ) -> Vec<String> {
+    ) -> Result<Vec<String>> {
         let mut vks = Vec::new();
         for (hard_fork_name, build) in self.circuits_handler_builder_map.iter() {
-            let handler =
-                build(prover_types.clone(), config).expect("failed to build circuits handler");
+            let handler = build(prover_types.clone(), config)
+                .map_err(|e| anyhow::anyhow!(
+                    "Failed to build circuits handler for fork '{}': {}", 
+                    hard_fork_name, e
+                ))?;

             for prover_type in prover_types.iter() {
                 for task_type in get_circuit_types(*prover_type).into_iter() {
                     let vk = handler
                         .get_vk(task_type)
                         .await
-                        .map_or("".to_string(), utils::encode_vk);
+                        .ok_or_else(|| anyhow::anyhow!(
+                            "Missing VK for fork '{}', task type '{:?}'",
+                            hard_fork_name, task_type
+                        ))?;
+                    let encoded_vk = utils::encode_vk(vk);
                     log::info!(
                         "vk for {hard_fork_name}, is {vk}, task_type: {:?}",
                         task_type
                     );
-                    if !vk.is_empty() {
-                        vks.push(vk)
-                    }
+                    vks.push(encoded_vk);
                 }
             }
         }
-        vks
+        Ok(vks)
     }
prover/src/prover.rs (2)

73-112: Simplify task status management.

The current implementation has several areas for improvement:

  1. Multiple lock acquisitions
  2. Complex nested if-else structure
  3. Repetitive response building

Consider using a more concise approach:

     async fn query_task(&self, req: QueryTaskRequest) -> QueryTaskResponse {
-        let handle = self.current_task.lock().unwrap().take();
-        if let Some(handle) = handle {
-            if handle.is_finished() {
-                return match handle.await {
-                    Ok(Ok(proof)) => QueryTaskResponse {
-                        task_id: req.task_id,
-                        status: TaskStatus::Success,
-                        proof: Some(proof),
-                        ..Default::default()
-                    },
-                    Ok(Err(e)) => QueryTaskResponse {
-                        task_id: req.task_id,
-                        status: TaskStatus::Failed,
-                        error: Some(format!("proving task failed: {}", e)),
-                        ..Default::default()
-                    },
-                    Err(e) => QueryTaskResponse {
-                        task_id: req.task_id,
-                        status: TaskStatus::Failed,
-                        error: Some(format!("proving task panicked: {}", e)),
-                        ..Default::default()
-                    },
-                };
-            } else {
-                *self.current_task.lock().unwrap() = Some(handle);
-                return QueryTaskResponse {
-                    task_id: req.task_id,
-                    status: TaskStatus::Proving,
-                    ..Default::default()
-                };
-            }
-        }
-        // If no handle is found
-        QueryTaskResponse {
-            task_id: req.task_id,
-            status: TaskStatus::Failed,
-            error: Some("no proving task is running".to_string()),
-            ..Default::default()
-        }
+        let mut response = QueryTaskResponse {
+            task_id: req.task_id,
+            ..Default::default()
+        };
+
+        let mut guard = self.current_task.lock().expect("Failed to acquire task lock");
+        
+        match guard.take() {
+            Some(handle) => {
+                if handle.is_finished() {
+                    match handle.await {
+                        Ok(Ok(proof)) => {
+                            response.status = TaskStatus::Success;
+                            response.proof = Some(proof);
+                        }
+                        Ok(Err(e)) => {
+                            response.status = TaskStatus::Failed;
+                            response.error = Some(format!("Proving task failed: {}", e));
+                        }
+                        Err(e) => {
+                            response.status = TaskStatus::Failed;
+                            response.error = Some(format!("Proving task panicked: {}", e));
+                        }
+                    }
+                } else {
+                    *guard = Some(handle);
+                    response.status = TaskStatus::Proving;
+                }
+            }
+            None => {
+                response.status = TaskStatus::Failed;
+                response.error = Some("No proving task is running".to_string());
+            }
+        }
+        
+        response
     }

130-165: Improve error handling and timing accuracy in proof generation.

The current implementation has several areas for improvement:

  1. Unwrap usage for system time
  2. Manual timestamp calculation
  3. No error handling for mutex operations

Consider these improvements:

     async fn do_prove(
         &self,
         req: ProveRequest,
         handler: Arc<Box<dyn CircuitsHandler>>,
     ) -> Result<ProveResponse> {
         let task_id = {
-            let mut next_task_id = self.next_task_id.lock().unwrap();
+            let mut next_task_id = self.next_task_id.lock()
+                .map_err(|e| anyhow::anyhow!("Failed to acquire task ID lock: {}", e))?;
             *next_task_id += 1;
             *next_task_id
         };

-        let duration = SystemTime::now().duration_since(UNIX_EPOCH).unwrap();
-        let created_at = duration.as_secs() as f64 + duration.subsec_nanos() as f64 * 1e-9;
+        let created_at = SystemTime::now()
+            .duration_since(UNIX_EPOCH)
+            .map_err(|e| anyhow::anyhow!("Failed to get system time: {}", e))?
+            .as_secs_f64();

         // ... rest of the implementation ...
     }
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 215a503 and 7c57b0a.

⛔ Files ignored due to path filters (1)
  • prover/Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (3)
  • prover/Cargo.toml (2 hunks)
  • prover/src/prover.rs (1 hunks)
  • prover/src/zk_circuits_handler.rs (5 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • prover/Cargo.toml
⏰ Context from checks skipped due to timeout of 90000ms (2)
  • GitHub Check: fmt
  • GitHub Check: tests
🔇 Additional comments (1)
prover/src/prover.rs (1)

144-148: ⚠️ Potential issue

Critical: Avoid blocking the tokio runtime.

Using block_on inside a spawn_blocking task can lead to deadlocks and performance issues. This needs to be redesigned to properly handle async operations.

Consider restructuring to:

-        let req_clone = req.clone();
-        let handle = Handle::current();
-        let task_handle =
-            tokio::task::spawn_blocking(move || handle.block_on(handler.get_proof_data(req_clone)));
+        let task_handle = tokio::spawn(handler.get_proof_data(req));

This change:

  1. Removes the blocking operation
  2. Properly utilizes tokio's async runtime
  3. Prevents potential deadlocks

Likely invalid or redundant comment.

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: 1

🧹 Nitpick comments (1)
prover/src/prover.rs (1)

141-142: Use chrono for timestamp handling.

Using raw SystemTime and manual float conversion is error-prone. Consider using the chrono crate for better timestamp handling.

-        let duration = SystemTime::now().duration_since(UNIX_EPOCH).unwrap();
-        let created_at = duration.as_secs() as f64 + duration.subsec_nanos() as f64 * 1e-9;
+        let created_at = chrono::Utc::now().timestamp_nanos() as f64 * 1e-9;
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 7c57b0a and ef15752.

⛔ Files ignored due to path filters (1)
  • prover/Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (2)
  • prover/Cargo.toml (2 hunks)
  • prover/src/prover.rs (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • prover/Cargo.toml
⏰ Context from checks skipped due to timeout of 90000ms (2)
  • GitHub Check: fmt
  • GitHub Check: tests
🔇 Additional comments (3)
prover/src/prover.rs (3)

24-29: LGTM! Well-designed thread-safe state management.

The struct uses appropriate synchronization primitives:

  • RwLock for circuits_handler_provider enables concurrent reads
  • Arc<Mutex> for task management fields ensures safe sharing across threads

56-61: ⚠️ Potential issue

Replace expect() with proper error handling.

Using expect() can cause panics. Consider propagating the error using ? operator with a descriptive error message.

-            .expect("failed to get circuit handler");
+            .map_err(|e| anyhow::anyhow!("failed to get circuit handler: {}", e))?;

Likely invalid or redundant comment.


73-112: 🛠️ Refactor suggestion

Improve task state management in query_task.

The current implementation has several issues:

  1. Multiple unwrap() calls that could panic
  2. Taking ownership of the handle on every query is inefficient
  3. Complex nested match structure

Consider this safer implementation:

     async fn query_task(&self, req: QueryTaskRequest) -> QueryTaskResponse {
-        let handle = self.current_task.lock().unwrap().take();
+        let handle = self.current_task
+            .lock()
+            .map_err(|e| format!("failed to acquire lock: {}", e))?
+            .take();
+
         if let Some(handle) = handle {
             if handle.is_finished() {
                 return match handle.await {
                     Ok(Ok(proof)) => QueryTaskResponse {
                         task_id: req.task_id,
                         status: TaskStatus::Success,
                         proof: Some(proof),
                         ..Default::default()
                     },
                     Ok(Err(e)) => QueryTaskResponse {
                         task_id: req.task_id,
                         status: TaskStatus::Failed,
                         error: Some(format!("proving task failed: {}", e)),
                         ..Default::default()
                     },
                     Err(e) => QueryTaskResponse {
                         task_id: req.task_id,
                         status: TaskStatus::Failed,
                         error: Some(format!("proving task panicked: {}", e)),
                         ..Default::default()
                     },
                 };
             } else {
-                *self.current_task.lock().unwrap() = Some(handle);
+                if let Ok(mut guard) = self.current_task.lock() {
+                    *guard = Some(handle);
+                }
                 return QueryTaskResponse {
                     task_id: req.task_id,
                     status: TaskStatus::Proving,
                     ..Default::default()
                 };
             }
         }

Likely invalid or redundant comment.

prover/src/prover.rs Show resolved Hide resolved
@yiweichi
Copy link
Member Author

raised a pr here to resolve the ci failing.

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: 3

🧹 Nitpick comments (3)
prover/src/main.rs (1)

45-57: Improve error handling in circuit type initialization.

The code could benefit from more descriptive error handling when processing circuit types.

Consider this improvement:

-    let mut prover_types = vec![];
-    cfg.sdk_config
-        .prover
-        .circuit_types
-        .iter()
-        .for_each(|circuit_type| {
-            if let Some(pt) = get_prover_type(*circuit_type) {
-                if !prover_types.contains(&pt) {
-                    prover_types.push(pt);
-                }
-            }
-        });
+    let prover_types: Vec<_> = cfg.sdk_config
+        .prover
+        .circuit_types
+        .iter()
+        .filter_map(|&circuit_type| get_prover_type(circuit_type))
+        .collect::<std::collections::HashSet<_>>()
+        .into_iter()
+        .collect();
+    
+    if prover_types.is_empty() {
+        return Err(anyhow::anyhow!("No valid prover types found in configuration"));
+    }
prover/src/zk_circuits_handler.rs (1)

137-163: Improve error handling and performance in init_vks.

The current implementation silently ignores errors and could be more efficient.

Consider this improvement:

     pub async fn init_vks(
         &self,
         config: &LocalProverConfig,
         prover_types: Vec<ProverType>,
-    ) -> Vec<String> {
-        let mut vks = Vec::new();
+    ) -> Result<Vec<String>> {
+        let mut vks = Vec::with_capacity(
+            self.circuits_handler_builder_map.len() * prover_types.len()
+        );

         for (hard_fork_name, build) in self.circuits_handler_builder_map.iter() {
             let handler =
-                build(prover_types.clone(), config).expect("failed to build circuits handler");
+                build(prover_types.clone(), config)
+                    .map_err(|e| anyhow::anyhow!(
+                        "Failed to build circuits handler for {}: {}", 
+                        hard_fork_name, e
+                    ))?;

             for prover_type in prover_types.iter() {
                 for task_type in get_circuit_types(*prover_type).into_iter() {
                     let vk = handler
                         .get_vk(task_type)
                         .await
                         .map_or("".to_string(), utils::encode_vk);
                     
                     if !vk.is_empty() {
                         vks.push(vk)
                     } else {
+                        log::warn!(
+                            "No VK found for {}, task_type: {:?}",
+                            hard_fork_name, task_type
+                        );
                     }
                 }
             }
         }
-        vks
+        Ok(vks)
     }
prover/src/prover.rs (1)

85-100: Improve error handling in prove method.

The error handling could be more descriptive and the clone operations could be optimized.

Apply these improvements:

     async fn prove(&self, req: ProveRequest) -> ProveResponse {
         let handler = self
             .circuits_handler_provider
             .write()
             .await
-            .get_circuits_handler(&req.hard_fork_name, self.prover_types.clone())
-            .expect("failed to get circuit handler");
+            .get_circuits_handler(&req.hard_fork_name, &self.prover_types)
+            .map_err(|e| {
+                log::error!("Failed to get circuit handler: {}", e);
+                anyhow::anyhow!("Circuit handler initialization failed: {}", e)
+            })?;

         match self.do_prove(req, handler).await {
             Ok(resp) => resp,
             Err(e) => {
+                log::error!("Proving failed: {}", e);
                 ProveResponse {
                     status: TaskStatus::Failed,
                     error: Some(format!("failed to request proof: {}", e)),
                     ..Default::default()
                 }
             }
         }
     }
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between ef15752 and 7c38ac6.

⛔ Files ignored due to path filters (1)
  • prover/Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (4)
  • prover/Cargo.toml (3 hunks)
  • prover/src/main.rs (2 hunks)
  • prover/src/prover.rs (1 hunks)
  • prover/src/zk_circuits_handler.rs (5 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • prover/Cargo.toml
⏰ Context from checks skipped due to timeout of 90000ms (2)
  • GitHub Check: fmt
  • GitHub Check: tests
🔇 Additional comments (1)
prover/src/zk_circuits_handler.rs (1)

47-49: ⚠️ Potential issue

Replace panic with proper error handling.

Using panic! in library code makes it harder to handle errors gracefully in the calling code.

Apply this diff to propagate the error instead:

-        if let Err(e) = AssetsDirEnvConfig::init() {
-            panic!("AssetsDirEnvConfig init failed: {:#}", e);
-        }
+        AssetsDirEnvConfig::init().map_err(|e| {
+            anyhow::anyhow!("AssetsDirEnvConfig initialization failed: {:#}", e)
+        })?;

Likely invalid or redundant comment.

Comment on lines +34 to +35
#[tokio::main]
async fn main() -> anyhow::Result<()> {
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Critical: Handle the result from prover.run().

The result from prover.run().await is being ignored. This could hide potential errors during execution.

Apply this diff to properly handle the result:

-    prover.run().await;
+    prover.run().await?;

Also applies to: 65-65

Comment on lines +174 to +177
let req_clone = req.clone();
let handle = Handle::current();
let task_handle =
tokio::task::spawn_blocking(move || handle.block_on(handler.get_proof_data(req_clone)));
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Critical: Avoid blocking operations in async context.

Using block_on inside a spawn_blocking task can block other tasks in the runtime. This needs to be redesigned to properly handle async operations.

Consider this non-blocking approach:

-        let req_clone = req.clone();
-        let handle = Handle::current();
-        let task_handle =
-            tokio::task::spawn_blocking(move || handle.block_on(handler.get_proof_data(req_clone)));
+        let task_handle = tokio::spawn(async move {
+            handler.get_proof_data(req).await
+        });

For CPU-intensive operations, consider using a dedicated thread pool:

let (tx, rx) = tokio::sync::oneshot::channel();
let req_clone = req.clone();
let handler_clone = handler.clone();

std::thread::spawn(move || {
    let runtime = tokio::runtime::Builder::new_current_thread()
        .enable_all()
        .build()
        .expect("Failed to create runtime");
    
    let result = runtime.block_on(handler_clone.get_proof_data(req_clone));
    let _ = tx.send(result);
});

let task_handle = tokio::spawn(async move {
    rx.await.expect("thread panicked")
});

Comment on lines +103 to +142
async fn query_task(&self, req: QueryTaskRequest) -> QueryTaskResponse {
let handle = self.current_task.lock().unwrap().take();
if let Some(handle) = handle {
if handle.is_finished() {
return match handle.await {
Ok(Ok(proof)) => QueryTaskResponse {
task_id: req.task_id,
status: TaskStatus::Success,
proof: Some(proof),
..Default::default()
},
Ok(Err(e)) => QueryTaskResponse {
task_id: req.task_id,
status: TaskStatus::Failed,
error: Some(format!("proving task failed: {}", e)),
..Default::default()
},
Err(e) => QueryTaskResponse {
task_id: req.task_id,
status: TaskStatus::Failed,
error: Some(format!("proving task panicked: {}", e)),
..Default::default()
},
};
} else {
*self.current_task.lock().unwrap() = Some(handle);
return QueryTaskResponse {
task_id: req.task_id,
status: TaskStatus::Proving,
..Default::default()
};
}
}
// If no handle is found
QueryTaskResponse {
task_id: req.task_id,
status: TaskStatus::Failed,
error: Some("no proving task is running".to_string()),
..Default::default()
};

proof_detail.proof_data = handler.get_proof_data(task.task_type, task)?;
Ok(proof_detail)
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Improve task state management.

The current implementation has several issues:

  1. Taking ownership of the handle on every query is inefficient
  2. Error states could be more descriptive
  3. Task status transitions could be clearer

Consider implementing a proper state machine:

#[derive(Debug)]
enum TaskState {
    NotStarted,
    Running(JoinHandle<Result<String>>),
    Completed(Result<String>),
    Failed(String),
}

impl TaskState {
    fn is_terminal(&self) -> bool {
        matches!(self, Self::Completed(_) | Self::Failed(_))
    }
}

// Then modify query_task to use this state machine

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bump-version Bump the version tag for deployment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants