use std::path::PathBuf;
use bn254_blackbox_solver::Bn254BlackBoxSolver;
use clap::Args;
use crate::{
Artifact,
errors::CliError,
execution::{self, ExecutionResults},
};
use nargo::foreign_calls::{
DefaultForeignCallBuilder, layers, transcript::ReplayForeignCallExecutor,
};
use noirc_driver::CompiledProgram;
use super::parse_and_normalize_path;
#[derive(Debug, Clone, Args)]
pub struct ExecuteCommand {
#[clap(long, short, value_parser = parse_and_normalize_path)]
pub artifact_path: PathBuf,
#[clap(long, short, value_parser = parse_and_normalize_path)]
pub prover_file: PathBuf,
#[clap(long, short, value_parser = parse_and_normalize_path)]
pub output_dir: Option<PathBuf>,
#[clap(long, short)]
pub witness_name: Option<String>,
#[clap(long)]
pub contract_fn: Option<String>,
#[clap(long, conflicts_with = "oracle_resolver")]
pub oracle_file: Option<PathBuf>,
#[clap(long, conflicts_with = "oracle_file")]
pub oracle_resolver: Option<String>,
#[clap(long, value_parser = parse_and_normalize_path)]
pub oracle_root_dir: Option<PathBuf>,
#[clap(long)]
pub oracle_package_name: Option<String>,
#[clap(long, default_value_t = false)]
pub pedantic_solving: bool,
}
pub fn run(args: ExecuteCommand) -> Result<(), CliError> {
let artifact = Artifact::read_from_file(&args.artifact_path)?;
let artifact_name = args.artifact_path.file_stem().and_then(|s| s.to_str()).unwrap_or_default();
let (circuit, circuit_name): (CompiledProgram, String) = match artifact {
Artifact::Program(program) => (program.into(), artifact_name.to_string()),
Artifact::Contract(contract) => {
let names = || contract.functions.iter().map(|f| f.name.clone()).collect::<Vec<_>>();
let Some(ref name) = args.contract_fn else {
return Err(CliError::MissingContractFn { names: names() });
};
let Some(program) = contract.function_as_compiled_program(name) else {
return Err(CliError::UnknownContractFn { name: name.clone(), names: names() });
};
(program, format!("{artifact_name}::{name}"))
}
};
match execute(&circuit, &args) {
Ok(results) => {
execution::save_and_check_witness(
&circuit,
results,
&circuit_name,
args.output_dir.as_deref(),
args.witness_name.as_deref(),
)?;
}
Err(e) => {
if let CliError::CircuitExecutionError(ref err) = e {
execution::show_diagnostic(&circuit, err);
}
return Err(e);
}
}
Ok(())
}
fn execute(circuit: &CompiledProgram, args: &ExecuteCommand) -> Result<ExecutionResults, CliError> {
let transcript_executor = match args.oracle_file {
Some(ref path) => layers::Either::Left(ReplayForeignCallExecutor::from_file(path)?),
None => layers::Either::Right(layers::Empty),
};
let mut foreign_call_executor = DefaultForeignCallBuilder {
output: std::io::stdout(),
enable_mocks: false,
resolver_url: args.oracle_resolver.clone(),
root_path: None,
package_name: None,
}
.build_with_base(transcript_executor);
let blackbox_solver = Bn254BlackBoxSolver(args.pedantic_solving);
execution::execute(circuit, &blackbox_solver, &mut foreign_call_executor, &args.prover_file)
}