From 9cfd9d8f5e6ad786d5b6a32337fe90530ba05a04 Mon Sep 17 00:00:00 2001 From: illuzen Date: Sat, 18 Apr 2026 14:55:55 +0800 Subject: [PATCH] setup-circuits command --- src/circuits.rs | 379 +++++++++++++++++++++++++++++++++++++ src/cli/mod.rs | 17 ++ src/cli/wormhole.rs | 91 ++++----- src/collect_rewards_lib.rs | 37 +++- src/lib.rs | 12 +- src/main.rs | 1 + 6 files changed, 468 insertions(+), 69 deletions(-) create mode 100644 src/circuits.rs diff --git a/src/circuits.rs b/src/circuits.rs new file mode 100644 index 0000000..7192c2d --- /dev/null +++ b/src/circuits.rs @@ -0,0 +1,379 @@ +//! Circuit Binary Management +//! +//! This module provides utilities for managing ZK circuit binaries used by wormhole operations. +//! Circuit binaries are large files (~1GB total) that contain proving and verification keys. +//! +//! ## Storage Locations +//! +//! Circuit binaries are searched in the following order: +//! 1. `$QUANTUS_CIRCUIT_BINS` environment variable (for custom setups) +//! 2. `~/.quantus/circuit-bins/` (standard installed location) +//! 3. `./generated-bins` (for development) +//! +//! ## Setup +//! +//! Users must run `quantus setup-circuits` before using wormhole commands. +//! This generates the circuit binaries, which takes a few minutes on first run. + +use crate::error::{QuantusError, Result}; +use indicatif::{ProgressBar, ProgressStyle}; +use std::path::{Path, PathBuf}; +use std::time::Instant; + +/// Environment variable for custom circuit bins directory +pub const CIRCUIT_BINS_ENV_VAR: &str = "QUANTUS_CIRCUIT_BINS"; + +/// Default directory name for circuit bins in user's home +pub const DEFAULT_CIRCUIT_BINS_DIR: &str = ".quantus/circuit-bins"; + +/// Development directory name (relative to CWD) +pub const DEV_CIRCUIT_BINS_DIR: &str = "generated-bins"; + +/// Required circuit binary files +pub const REQUIRED_CIRCUIT_FILES: &[&str] = &[ + "common.bin", + "verifier.bin", + "prover.bin", + "dummy_proof.bin", + "aggregated_common.bin", + "aggregated_verifier.bin", + "aggregated_prover.bin", + "config.json", +]; + +/// Get the default circuit bins directory in user's home +pub fn get_default_circuit_bins_dir() -> Option { + dirs::home_dir().map(|home| home.join(DEFAULT_CIRCUIT_BINS_DIR)) +} + +/// Check if a directory contains valid circuit binaries +pub fn is_valid_circuit_dir(dir: &Path) -> bool { + if !dir.exists() || !dir.is_dir() { + return false; + } + + // Check that all required files exist + REQUIRED_CIRCUIT_FILES.iter().all(|file| dir.join(file).exists()) +} + +/// Get the circuit bins directory, searching in order of precedence. +/// +/// Search order: +/// 1. `$QUANTUS_CIRCUIT_BINS` environment variable +/// 2. `~/.quantus/circuit-bins/` +/// 3. `./generated-bins` (development) +/// +/// Returns `None` if no valid circuit directory is found. +pub fn find_circuit_bins_dir() -> Option { + // 1. Check environment variable + if let Ok(env_path) = std::env::var(CIRCUIT_BINS_ENV_VAR) { + let path = PathBuf::from(&env_path); + if is_valid_circuit_dir(&path) { + return Some(path); + } + } + + // 2. Check user's home directory + if let Some(home_path) = get_default_circuit_bins_dir() { + if is_valid_circuit_dir(&home_path) { + return Some(home_path); + } + } + + // 3. Check development directory (relative to CWD) + let dev_path = PathBuf::from(DEV_CIRCUIT_BINS_DIR); + if is_valid_circuit_dir(&dev_path) { + return Some(dev_path); + } + + None +} + +/// Get the circuit bins directory or return a helpful error. +/// +/// This is the main function that should be used by wormhole commands. +pub fn get_circuit_bins_dir() -> Result { + find_circuit_bins_dir().ok_or_else(|| { + QuantusError::Generic( + "Circuit binaries not found. Run 'quantus setup-circuits' first.\n\ + This is a one-time setup that generates ZK proving keys (~1GB).\n\ + It may take a few minutes on first run." + .to_string(), + ) + }) +} + +/// Check if circuits exist (without returning an error) +#[allow(dead_code)] +pub fn circuits_exist() -> bool { + find_circuit_bins_dir().is_some() +} + +/// Check if an error message indicates a circuit version mismatch or corruption +pub fn is_circuit_version_error(error: &str) -> bool { + let error_lower = error.to_lowercase(); + error_lower.contains("wire partition") + || error_lower.contains("circuitconfig mismatch") + || error_lower.contains("gate_serializer") + || error_lower.contains("generator_serializer") + || error_lower.contains("deserialization failed") + || error_lower.contains("invalid circuit data") +} + +/// Wrap a circuit loading error with helpful context +pub fn wrap_circuit_error(error: E) -> QuantusError { + let error_str = error.to_string(); + + if is_circuit_version_error(&error_str) { + QuantusError::Generic(format!( + "Circuit binaries appear to be outdated or corrupted.\n\ + Run 'quantus setup-circuits --force' to regenerate them.\n\ + \n\ + Original error: {}", + error_str + )) + } else if error_str.contains("No such file") || error_str.contains("not found") { + QuantusError::Generic( + "Circuit binaries not found. Run 'quantus setup-circuits' first.\n\ + This is a one-time setup that generates ZK proving keys (~1GB).\n\ + It may take a few minutes on first run." + .to_string(), + ) + } else { + QuantusError::Generic(format!("Circuit loading error: {}", error_str)) + } +} + +/// Progress callback for circuit generation +struct GenerationProgress { + bar: ProgressBar, + start_time: Instant, +} + +impl GenerationProgress { + fn new() -> Self { + let bar = ProgressBar::new(100); + bar.set_style( + ProgressStyle::default_bar() + .template("{spinner:.green} [{bar:40.cyan/blue}] {pos}% {msg}") + .unwrap() + .progress_chars("=>-"), + ); + Self { bar, start_time: Instant::now() } + } + + fn set_message(&self, msg: &str) { + self.bar.set_message(msg.to_string()); + } + + fn set_progress(&self, percent: u64) { + self.bar.set_position(percent); + } + + fn finish(&self) { + let elapsed = self.start_time.elapsed(); + self.bar.finish_with_message(format!("Done in {:.1}s", elapsed.as_secs_f64())); + } +} + +/// Generate circuit binaries to the specified directory. +/// +/// # Arguments +/// * `output_dir` - Directory to write binaries to +/// * `num_leaf_proofs` - Number of leaf proofs per aggregation (default: 16) +/// * `force` - If true, regenerate even if circuits exist +/// +/// # Returns +/// Ok(()) on success, or an error if generation fails +pub fn generate_circuits(output_dir: &Path, num_leaf_proofs: usize, force: bool) -> Result<()> { + use colored::Colorize; + + // Check if circuits already exist + if !force && is_valid_circuit_dir(output_dir) { + println!( + "{}", + "Circuit binaries already exist. Use --force to regenerate.".bright_yellow() + ); + return Ok(()); + } + + // Create output directory + std::fs::create_dir_all(output_dir).map_err(|e| { + QuantusError::Generic(format!("Failed to create output directory {:?}: {}", output_dir, e)) + })?; + + println!("{}", "Generating ZK circuit binaries...".bright_cyan()); + println!(" Output directory: {}", output_dir.display().to_string().bright_white()); + println!(" Leaf proofs per aggregation: {}", num_leaf_proofs.to_string().bright_white()); + println!(); + + let progress = GenerationProgress::new(); + let start_time = Instant::now(); + + // Step 1: Generate leaf circuit (0-30%) + progress.set_message("Building wormhole leaf circuit..."); + progress.set_progress(5); + + // Use the circuit builder to generate all binaries + // The circuit builder handles the heavy lifting + progress.set_message("Generating leaf circuit binaries..."); + progress.set_progress(10); + + // Generate all circuit binaries using the builder + qp_wormhole_circuit_builder::generate_all_circuit_binaries( + output_dir, + true, // include prover + num_leaf_proofs, + None, // no layer-1 aggregation + ) + .map_err(|e| QuantusError::Generic(format!("Circuit generation failed: {}", e)))?; + + progress.set_progress(100); + progress.finish(); + + let elapsed = start_time.elapsed(); + + // Print summary + println!(); + println!( + "{}", + format!("Circuit binaries generated successfully in {:.1}s", elapsed.as_secs_f64()) + .bright_green() + ); + println!(); + + // Print file sizes + print_circuit_file_info(output_dir)?; + + println!(); + println!("{}", "You can now use wormhole commands.".bright_green()); + + Ok(()) +} + +/// Print information about generated circuit files +fn print_circuit_file_info(dir: &Path) -> Result<()> { + use colored::Colorize; + + let files = [ + ("common.bin", "Leaf circuit common data"), + ("verifier.bin", "Leaf circuit verifier"), + ("prover.bin", "Leaf circuit prover"), + ("dummy_proof.bin", "Dummy proof for padding"), + ("aggregated_common.bin", "Aggregated circuit common data"), + ("aggregated_verifier.bin", "Aggregated circuit verifier"), + ("aggregated_prover.bin", "Aggregated circuit prover"), + ("config.json", "Circuit configuration"), + ]; + + for (filename, description) in files { + let path = dir.join(filename); + if let Ok(metadata) = std::fs::metadata(&path) { + let size = metadata.len(); + let size_str = format_file_size(size); + println!( + " {}: {} ({})", + filename.bright_white(), + size_str.bright_cyan(), + description.dimmed() + ); + } + } + + Ok(()) +} + +/// Format a file size in human-readable form +fn format_file_size(bytes: u64) -> String { + const KB: u64 = 1024; + const MB: u64 = KB * 1024; + const GB: u64 = MB * 1024; + + if bytes >= GB { + format!("{:.2} GB", bytes as f64 / GB as f64) + } else if bytes >= MB { + format!("{:.2} MB", bytes as f64 / MB as f64) + } else if bytes >= KB { + format!("{:.2} KB", bytes as f64 / KB as f64) + } else { + format!("{} bytes", bytes) + } +} + +/// Handle the setup-circuits command +pub fn handle_setup_circuits( + force: bool, + num_leaf_proofs: usize, + output_dir: Option, +) -> Result<()> { + // Determine output directory + let output_path = if let Some(dir) = output_dir { + PathBuf::from(dir) + } else { + get_default_circuit_bins_dir().ok_or_else(|| { + QuantusError::Generic( + "Could not determine home directory. Use --output-dir to specify a location." + .to_string(), + ) + })? + }; + + generate_circuits(&output_path, num_leaf_proofs, force) +} + +#[cfg(test)] +mod tests { + use super::*; + use tempfile::tempdir; + + #[test] + fn test_is_circuit_version_error() { + assert!(is_circuit_version_error("wire partition mismatch")); + assert!(is_circuit_version_error("CircuitConfig mismatch detected")); + assert!(is_circuit_version_error("gate_serializer error")); + assert!(is_circuit_version_error("Deserialization failed for circuit")); + assert!(!is_circuit_version_error("File not found")); + assert!(!is_circuit_version_error("Network error")); + } + + #[test] + fn test_is_valid_circuit_dir_empty() { + let dir = tempdir().unwrap(); + assert!(!is_valid_circuit_dir(dir.path())); + } + + #[test] + fn test_is_valid_circuit_dir_nonexistent() { + let path = PathBuf::from("/nonexistent/path/to/circuits"); + assert!(!is_valid_circuit_dir(&path)); + } + + #[test] + fn test_format_file_size() { + assert_eq!(format_file_size(500), "500 bytes"); + assert_eq!(format_file_size(1024), "1.00 KB"); + assert_eq!(format_file_size(1024 * 1024), "1.00 MB"); + assert_eq!(format_file_size(1024 * 1024 * 1024), "1.00 GB"); + assert_eq!(format_file_size(1536), "1.50 KB"); + } + + #[test] + fn test_get_default_circuit_bins_dir() { + let dir = get_default_circuit_bins_dir(); + // Should return Some on most systems + if let Some(path) = dir { + assert!(path.to_string_lossy().contains(".quantus")); + assert!(path.to_string_lossy().contains("circuit-bins")); + } + } + + #[test] + fn test_find_circuit_bins_dir_not_found() { + // In a clean test environment without circuits, should return None + // (unless running in the quantus-cli dev directory) + let result = find_circuit_bins_dir(); + // We can't assert None because dev environment might have generated-bins + // Just verify it doesn't panic + let _ = result; + } +} diff --git a/src/cli/mod.rs b/src/cli/mod.rs index f2b2aa3..60099ce 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -174,6 +174,21 @@ pub enum Commands { #[command(subcommand)] Developer(DeveloperCommands), + /// Generate ZK circuit binaries for wormhole operations (one-time setup) + SetupCircuits { + /// Force regeneration even if circuits already exist + #[arg(long)] + force: bool, + + /// Number of leaf proofs per aggregation (default: 16) + #[arg(long, default_value = "16")] + num_leaf_proofs: usize, + + /// Custom output directory (default: ~/.quantus/circuit-bins/) + #[arg(long)] + output_dir: Option, + }, + /// Query events from blocks Events { /// Block number to query events from (full support) @@ -405,6 +420,8 @@ pub async fn execute_command( Ok(()) }, Commands::Developer(dev_cmd) => handle_developer_command(dev_cmd).await, + Commands::SetupCircuits { force, num_leaf_proofs, output_dir } => + crate::circuits::handle_setup_circuits(force, num_leaf_proofs, output_dir), Commands::Events { block, block_hash, latest: _, finalized, pallet, raw, no_decode } => events::handle_events_command( block, block_hash, finalized, pallet, raw, !no_decode, node_url, diff --git a/src/cli/wormhole.rs b/src/cli/wormhole.rs index 2313b84..c856b52 100644 --- a/src/cli/wormhole.rs +++ b/src/cli/wormhole.rs @@ -30,7 +30,6 @@ use qp_zk_circuits_common::{ }; use rand::RngCore; use sp_core::crypto::{AccountId32, Ss58Codec}; -use std::path::Path; use subxt::{ blocks::Block, ext::{ @@ -1122,18 +1121,12 @@ async fn aggregate_proofs( ) -> crate::error::Result<()> { use qp_wormhole_aggregator::aggregator::{AggregationBackend, CircuitType, Layer0Aggregator}; - use std::path::Path; - log_print!("Aggregating {} proofs...", proof_files.len()); // Load config first to validate and calculate padding needs - let bins_dir = Path::new("generated-bins"); - let agg_config = CircuitBinsConfig::load(bins_dir).map_err(|e| { - crate::error::QuantusError::Generic(format!( - "Failed to load circuit bins config from {:?}: {}", - bins_dir, e - )) - })?; + let bins_dir = crate::circuits::get_circuit_bins_dir()?; + let agg_config = CircuitBinsConfig::load(&bins_dir) + .map_err(|e| crate::circuits::wrap_circuit_error(e))?; // Validate number of proofs before doing expensive work if proof_files.len() > agg_config.num_leaf_proofs { @@ -1148,12 +1141,8 @@ async fn aggregate_proofs( log_print!(" Loading aggregator and generating {} dummy proofs...", num_padding_proofs); - let mut aggregator = Layer0Aggregator::new(bins_dir).map_err(|e| { - crate::error::QuantusError::Generic(format!( - "Failed to load aggregator from pre-built bins: {}", - e - )) - })?; + let mut aggregator = + Layer0Aggregator::new(&bins_dir).map_err(|e| crate::circuits::wrap_circuit_error(e))?; log_verbose!("Aggregation config: num_leaf_proofs={}", aggregator.batch_size()); let common_data = aggregator.load_common_data(CircuitType::Leaf).map_err(|e| { @@ -2016,11 +2005,10 @@ async fn run_multiround( log_print!("=================================================="); log_print!(""); - // Load aggregation config from generated-bins/config.json - let bins_dir = Path::new("generated-bins"); - let agg_config = CircuitBinsConfig::load(bins_dir).map_err(|e| { - crate::error::QuantusError::Generic(format!("Failed to load aggregation config: {}", e)) - })?; + // Load aggregation config + let bins_dir = crate::circuits::get_circuit_bins_dir()?; + let agg_config = + CircuitBinsConfig::load(&bins_dir).map_err(|e| crate::circuits::wrap_circuit_error(e))?; // Validate parameters validate_multiround_params(num_proofs, rounds, agg_config.num_leaf_proofs)?; @@ -2334,13 +2322,13 @@ async fn generate_proof( }; // Generate proof using wormhole_lib - let bins_dir = Path::new("generated-bins"); + let bins_dir = crate::circuits::get_circuit_bins_dir()?; let result = wormhole_lib::generate_proof( &input, &bins_dir.join("prover.bin"), &bins_dir.join("common.bin"), ) - .map_err(|e| crate::error::QuantusError::Generic(e.message))?; + .map_err(|e| crate::circuits::wrap_circuit_error(e.message))?; // Write proof to file let proof_hex = hex::encode(result.proof_bytes); @@ -2437,18 +2425,13 @@ async fn verify_aggregated_and_get_events( // Verify locally before submitting on-chain log_verbose!("Verifying aggregated proof locally before on-chain submission..."); - let bins_dir = Path::new("generated-bins"); + let bins_dir = crate::circuits::get_circuit_bins_dir()?; // Log circuit binary hashes for debugging - let common_bytes = std::fs::read(bins_dir.join("aggregated_common.bin")).map_err(|e| { - crate::error::QuantusError::Generic(format!("Failed to read aggregated_common.bin: {}", e)) - })?; - let verifier_bytes = std::fs::read(bins_dir.join("aggregated_verifier.bin")).map_err(|e| { - crate::error::QuantusError::Generic(format!( - "Failed to read aggregated_verifier.bin: {}", - e - )) - })?; + let common_bytes = std::fs::read(bins_dir.join("aggregated_common.bin")) + .map_err(|e| crate::circuits::wrap_circuit_error(e))?; + let verifier_bytes = std::fs::read(bins_dir.join("aggregated_verifier.bin")) + .map_err(|e| crate::circuits::wrap_circuit_error(e))?; println!( "[quantus-cli] Circuit binaries: common_bytes.len={}, verifier_bytes.len={}, common_hash={}, verifier_hash={}", common_bytes.len(), @@ -2461,9 +2444,7 @@ async fn verify_aggregated_and_get_events( &bins_dir.join("aggregated_verifier.bin"), &bins_dir.join("aggregated_common.bin"), ) - .map_err(|e| { - crate::error::QuantusError::Generic(format!("Failed to load aggregated verifier: {}", e)) - })?; + .map_err(|e| crate::circuits::wrap_circuit_error(e))?; let proof = qp_wormhole_verifier::ProofWithPublicInputs::< qp_wormhole_verifier::F, @@ -2601,7 +2582,7 @@ async fn parse_proof_file( log_print!("Proof size: {} bytes", proof_bytes.len()); - let bins_dir = Path::new("generated-bins"); + let bins_dir = crate::circuits::get_circuit_bins_dir()?; if aggregated { // Load aggregated verifier @@ -2609,9 +2590,7 @@ async fn parse_proof_file( &bins_dir.join("aggregated_verifier.bin"), &bins_dir.join("aggregated_common.bin"), ) - .map_err(|e| { - crate::error::QuantusError::Generic(format!("Failed to load verifier: {}", e)) - })?; + .map_err(|e| crate::circuits::wrap_circuit_error(e))?; // Deserialize proof using verifier's types let proof = qp_wormhole_verifier::ProofWithPublicInputs::< @@ -2681,9 +2660,7 @@ async fn parse_proof_file( &bins_dir.join("verifier.bin"), &bins_dir.join("common.bin"), ) - .map_err(|e| { - crate::error::QuantusError::Generic(format!("Failed to load verifier: {}", e)) - })?; + .map_err(|e| crate::circuits::wrap_circuit_error(e))?; // Deserialize proof using verifier's types let proof = qp_wormhole_verifier::ProofWithPublicInputs::< @@ -2819,13 +2796,9 @@ async fn run_dissolve( })?; // Load aggregation config - let bins_dir = std::path::Path::new("generated-bins"); - let agg_config = CircuitBinsConfig::load(bins_dir).map_err(|e| { - crate::error::QuantusError::Generic(format!( - "Failed to load aggregation circuit config: {}", - e - )) - })?; + let bins_dir = crate::circuits::get_circuit_bins_dir()?; + let agg_config = + CircuitBinsConfig::load(&bins_dir).map_err(|e| crate::circuits::wrap_circuit_error(e))?; // === Layer 0: Initial funding === log_print!("{}", "Layer 0: Initial funding".bright_yellow()); @@ -3173,12 +3146,15 @@ async fn run_collect_rewards( } } + // Get circuit bins directory (will error with helpful message if not found) + let bins_dir = crate::circuits::get_circuit_bins_dir()?; + let config = CollectRewardsConfig { credential, destination_address: destination_address.clone(), subsquid_url, node_url: node_url.to_string(), - bins_dir: "generated-bins".to_string(), + bins_dir: bins_dir.to_string_lossy().to_string(), amount: amount_planck, dry_run, at_block, @@ -3222,14 +3198,13 @@ async fn run_collect_rewards( fn aggregate_proofs_to_file(proof_files: &[String], output_file: &str) -> crate::error::Result<()> { use qp_wormhole_aggregator::aggregator::Layer0Aggregator; - let bins_dir = std::path::Path::new("generated-bins"); - let mut aggregator = Layer0Aggregator::new(bins_dir).map_err(|e| { - crate::error::QuantusError::Generic(format!("Failed to create aggregator: {}", e)) - })?; + let bins_dir = crate::circuits::get_circuit_bins_dir()?; + let mut aggregator = + Layer0Aggregator::new(&bins_dir).map_err(|e| crate::circuits::wrap_circuit_error(e))?; - let common_data = aggregator.load_common_data(CircuitType::Leaf).map_err(|e| { - crate::error::QuantusError::Generic(format!("Failed to load common data: {}", e)) - })?; + let common_data = aggregator + .load_common_data(CircuitType::Leaf) + .map_err(|e| crate::circuits::wrap_circuit_error(e))?; for proof_file in proof_files { let proof_bytes = read_hex_proof_file_to_bytes(proof_file)?; diff --git a/src/collect_rewards_lib.rs b/src/collect_rewards_lib.rs index 9402d65..c640d39 100644 --- a/src/collect_rewards_lib.rs +++ b/src/collect_rewards_lib.rs @@ -121,6 +121,30 @@ impl From for CollectRewardsError { } } +/// Wrap a circuit-related error with helpful context +fn wrap_circuit_error(error: E) -> CollectRewardsError { + let error_str = error.to_string(); + + if crate::circuits::is_circuit_version_error(&error_str) { + CollectRewardsError::from(format!( + "Circuit binaries appear to be outdated or corrupted.\n\ + Run 'quantus setup-circuits --force' to regenerate them.\n\ + \n\ + Original error: {}", + error_str + )) + } else if error_str.contains("No such file") || error_str.contains("not found") { + CollectRewardsError::from( + "Circuit binaries not found. Run 'quantus setup-circuits' first.\n\ + This is a one-time setup that generates ZK proving keys (~1GB).\n\ + It may take a few minutes on first run." + .to_string(), + ) + } else { + CollectRewardsError::from(format!("Circuit loading error: {}", error_str)) + } +} + /// Information about a pending transfer found via Subsquid #[derive(Debug, Clone)] #[allow(dead_code)] @@ -786,9 +810,7 @@ fn decode_input_amount_from_leaf(leaf_data: &[u8]) -> Result { /// Aggregate proof bytes into a single aggregated proof fn aggregate_proof_bytes(proof_bytes_list: &[Vec], bins_dir: &Path) -> Result> { // Load config to validate - let agg_config = CircuitBinsConfig::load(bins_dir).map_err(|e| { - CollectRewardsError::from(format!("Failed to load circuit bins config: {}", e)) - })?; + let agg_config = CircuitBinsConfig::load(bins_dir).map_err(wrap_circuit_error)?; if proof_bytes_list.len() > agg_config.num_leaf_proofs { return Err(CollectRewardsError::from(format!( @@ -798,12 +820,9 @@ fn aggregate_proof_bytes(proof_bytes_list: &[Vec], bins_dir: &Path) -> Resul ))); } - let mut aggregator = Layer0Aggregator::new(bins_dir) - .map_err(|e| CollectRewardsError::from(format!("Failed to load aggregator: {}", e)))?; + let mut aggregator = Layer0Aggregator::new(bins_dir).map_err(wrap_circuit_error)?; - let common_data = aggregator.load_common_data(CircuitType::Leaf).map_err(|e| { - CollectRewardsError::from(format!("Failed to load leaf circuit data: {}", e)) - })?; + let common_data = aggregator.load_common_data(CircuitType::Leaf).map_err(wrap_circuit_error)?; // Add proofs for proof_bytes in proof_bytes_list { @@ -836,7 +855,7 @@ async fn submit_and_get_events( &bins_dir.join("aggregated_verifier.bin"), &bins_dir.join("aggregated_common.bin"), ) - .map_err(|e| CollectRewardsError::from(format!("Failed to load verifier: {}", e)))?; + .map_err(wrap_circuit_error)?; let proof = qp_wormhole_verifier::ProofWithPublicInputs::< qp_wormhole_verifier::F, diff --git a/src/lib.rs b/src/lib.rs index 4bc9e9c..cfd5505 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,6 +5,7 @@ //! the Quantus blockchain. pub mod chain; +pub mod circuits; pub mod cli; pub mod collect_rewards_lib; pub mod config; @@ -50,8 +51,15 @@ pub use wormhole_lib::{ // Re-export collect rewards library for SDK usage pub use collect_rewards_lib::{ collect_rewards, query_pending_transfers, query_pending_transfers_for_address, - CollectRewardsConfig, CollectRewardsError, CollectRewardsResult, NoOpProgress, PendingTransfer, - ProgressCallback, QueryPendingTransfersResult, WithdrawalBatch, + resolve_credential, CollectRewardsConfig, CollectRewardsError, CollectRewardsResult, NoOpProgress, + PendingTransfer, ProgressCallback, QueryPendingTransfersResult, WithdrawalBatch, + WormholeCredential, +}; + +// Re-export circuit management for SDK usage +pub use circuits::{ + find_circuit_bins_dir, generate_circuits, get_circuit_bins_dir, get_default_circuit_bins_dir, + is_valid_circuit_dir, CIRCUIT_BINS_ENV_VAR, }; /// Library version diff --git a/src/main.rs b/src/main.rs index 872c886..898eaf2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -9,6 +9,7 @@ use clap::Parser; use colored::Colorize; mod chain; +mod circuits; mod cli; mod collect_rewards_lib; mod config;