-
Notifications
You must be signed in to change notification settings - Fork 265
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Integrated native ACVM (#4903)
This PR creates a cli entrypoint for the ACVM simulator, builds it and makes it available for use in e2e tests both locally and on CI. This native simulator is used to execute sequencer-side protocol circuits, in parallel where possible.
- Loading branch information
1 parent
d4d935f
commit 3fd7025
Showing
40 changed files
with
987 additions
and
452 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
[package] | ||
name = "acvm_cli" | ||
description = "The entrypoint for executing the ACVM" | ||
# x-release-please-start-version | ||
version = "0.40.0" | ||
# x-release-please-end | ||
authors.workspace = true | ||
edition.workspace = true | ||
license.workspace = true | ||
rust-version.workspace = true | ||
repository.workspace = true | ||
|
||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html | ||
|
||
# Rename binary from `acvm_cli` to `acvm` | ||
[[bin]] | ||
name = "acvm" | ||
path = "src/main.rs" | ||
|
||
[dependencies] | ||
thiserror.workspace = true | ||
toml.workspace = true | ||
color-eyre = "0.6.2" | ||
clap.workspace = true | ||
acvm.workspace = true | ||
nargo.workspace = true | ||
const_format.workspace = true | ||
bn254_blackbox_solver.workspace = true | ||
acir.workspace = true | ||
|
||
# Logs | ||
tracing-subscriber.workspace = true | ||
tracing-appender = "0.2.3" | ||
|
||
[dev-dependencies] | ||
rand = "0.8.5" | ||
proptest = "1.2.0" | ||
paste = "1.0.14" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
use std::io::{self, Write}; | ||
|
||
use acir::circuit::Circuit; | ||
use acir::native_types::WitnessMap; | ||
use bn254_blackbox_solver::Bn254BlackBoxSolver; | ||
use clap::Args; | ||
|
||
use crate::cli::fs::inputs::{read_bytecode_from_file, read_inputs_from_file}; | ||
use crate::cli::fs::witness::save_witness_to_dir; | ||
use crate::errors::CliError; | ||
use nargo::ops::{execute_circuit, DefaultForeignCallExecutor}; | ||
|
||
use super::fs::witness::create_output_witness_string; | ||
|
||
/// Executes a circuit to calculate its return value | ||
#[derive(Debug, Clone, Args)] | ||
pub(crate) struct ExecuteCommand { | ||
/// Write the execution witness to named file | ||
#[clap(long, short)] | ||
output_witness: Option<String>, | ||
|
||
/// The name of the toml file which contains the input witness map | ||
#[clap(long, short)] | ||
input_witness: String, | ||
|
||
/// The name of the binary file containing circuit bytecode | ||
#[clap(long, short)] | ||
bytecode: String, | ||
|
||
/// The working directory | ||
#[clap(long, short)] | ||
working_directory: String, | ||
|
||
/// Set to print output witness to stdout | ||
#[clap(long, short, action)] | ||
print: bool, | ||
} | ||
|
||
fn run_command(args: ExecuteCommand) -> Result<String, CliError> { | ||
let bytecode = read_bytecode_from_file(&args.working_directory, &args.bytecode)?; | ||
let circuit_inputs = read_inputs_from_file(&args.working_directory, &args.input_witness)?; | ||
let output_witness = execute_program_from_witness(&circuit_inputs, &bytecode, None)?; | ||
let output_witness_string = create_output_witness_string(&output_witness)?; | ||
if args.output_witness.is_some() { | ||
save_witness_to_dir( | ||
&output_witness_string, | ||
&args.working_directory, | ||
&args.output_witness.unwrap(), | ||
)?; | ||
} | ||
Ok(output_witness_string) | ||
} | ||
|
||
pub(crate) fn run(args: ExecuteCommand) -> Result<String, CliError> { | ||
let print = args.print; | ||
let output_witness_string = run_command(args)?; | ||
if print { | ||
io::stdout().write_all(output_witness_string.as_bytes()).unwrap(); | ||
} | ||
Ok(output_witness_string) | ||
} | ||
|
||
pub(crate) fn execute_program_from_witness( | ||
inputs_map: &WitnessMap, | ||
bytecode: &Vec<u8>, | ||
foreign_call_resolver_url: Option<&str>, | ||
) -> Result<WitnessMap, CliError> { | ||
let blackbox_solver = Bn254BlackBoxSolver::new(); | ||
let circuit: Circuit = Circuit::deserialize_circuit(&bytecode) | ||
.map_err(|_| CliError::CircuitDeserializationError())?; | ||
let result = execute_circuit( | ||
&circuit, | ||
inputs_map.clone(), | ||
&blackbox_solver, | ||
&mut DefaultForeignCallExecutor::new(true, foreign_call_resolver_url), | ||
) | ||
.map_err(|e| CliError::CircuitExecutionError(e)); | ||
result | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
use acir::{ | ||
native_types::{Witness, WitnessMap}, | ||
FieldElement, | ||
}; | ||
use toml::Table; | ||
|
||
use crate::errors::{CliError, FilesystemError}; | ||
use std::{fs::read, path::Path}; | ||
|
||
/// Returns the circuit's parameters parsed from a toml file at the given location | ||
pub(crate) fn read_inputs_from_file<P: AsRef<Path>>( | ||
working_directory: P, | ||
file_name: &String, | ||
) -> Result<WitnessMap, CliError> { | ||
let file_path = working_directory.as_ref().join(file_name); | ||
if !file_path.exists() { | ||
return Err(CliError::FilesystemError(FilesystemError::MissingTomlFile( | ||
file_name.to_owned(), | ||
file_path, | ||
))); | ||
} | ||
|
||
let input_string = std::fs::read_to_string(file_path) | ||
.map_err(|_| FilesystemError::InvalidTomlFile(file_name.clone()))?; | ||
let input_map = input_string | ||
.parse::<Table>() | ||
.map_err(|_| FilesystemError::InvalidTomlFile(file_name.clone()))?; | ||
let mut witnesses: WitnessMap = WitnessMap::new(); | ||
for (key, value) in input_map.into_iter() { | ||
let index = | ||
Witness(key.trim().parse().map_err(|_| CliError::WitnessIndexError(key.clone()))?); | ||
if !value.is_str() { | ||
return Err(CliError::WitnessValueError(key.clone())); | ||
} | ||
let field = FieldElement::from_hex(value.as_str().unwrap()).unwrap(); | ||
witnesses.insert(index, field); | ||
} | ||
|
||
Ok(witnesses) | ||
} | ||
|
||
/// Returns the circuit's bytecode read from the file at the given location | ||
pub(crate) fn read_bytecode_from_file<P: AsRef<Path>>( | ||
working_directory: P, | ||
file_name: &String, | ||
) -> Result<Vec<u8>, FilesystemError> { | ||
let file_path = working_directory.as_ref().join(file_name); | ||
if !file_path.exists() { | ||
return Err(FilesystemError::MissingBytecodeFile(file_name.to_owned(), file_path)); | ||
} | ||
let bytecode: Vec<u8> = | ||
read(file_path).map_err(|_| FilesystemError::InvalidBytecodeFile(file_name.clone()))?; | ||
Ok(bytecode) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
pub(super) mod inputs; | ||
pub(super) mod witness; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
use std::{ | ||
collections::BTreeMap, | ||
fs::File, | ||
io::Write, | ||
path::{Path, PathBuf}, | ||
}; | ||
|
||
use acvm::acir::native_types::WitnessMap; | ||
|
||
use crate::errors::{CliError, FilesystemError}; | ||
|
||
/// Saves the provided output witnesses to a toml file created at the given location | ||
pub(crate) fn save_witness_to_dir<P: AsRef<Path>>( | ||
output_witness: &String, | ||
witness_dir: P, | ||
file_name: &String, | ||
) -> Result<PathBuf, FilesystemError> { | ||
let witness_path = witness_dir.as_ref().join(file_name); | ||
|
||
let mut file = File::create(&witness_path) | ||
.map_err(|_| FilesystemError::OutputWitnessCreationFailed(file_name.clone()))?; | ||
write!(file, "{}", output_witness) | ||
.map_err(|_| FilesystemError::OutputWitnessWriteFailed(file_name.clone()))?; | ||
|
||
Ok(witness_path) | ||
} | ||
|
||
/// Creates a toml representation of the provided witness map | ||
pub(crate) fn create_output_witness_string(witnesses: &WitnessMap) -> Result<String, CliError> { | ||
let mut witness_map: BTreeMap<String, String> = BTreeMap::new(); | ||
for (key, value) in witnesses.clone().into_iter() { | ||
witness_map.insert(key.0.to_string(), format!("0x{}", value.to_hex())); | ||
} | ||
|
||
toml::to_string(&witness_map).map_err(|_| CliError::OutputWitnessSerializationFailed()) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
use clap::{Parser, Subcommand}; | ||
use color_eyre::eyre; | ||
use const_format::formatcp; | ||
|
||
mod execute_cmd; | ||
mod fs; | ||
|
||
const ACVM_VERSION: &str = env!("CARGO_PKG_VERSION"); | ||
|
||
static VERSION_STRING: &str = formatcp!("version = {}\n", ACVM_VERSION,); | ||
|
||
#[derive(Parser, Debug)] | ||
#[command(name="acvm", author, version=VERSION_STRING, about, long_about = None)] | ||
struct ACVMCli { | ||
#[command(subcommand)] | ||
command: ACVMCommand, | ||
} | ||
|
||
#[non_exhaustive] | ||
#[derive(Subcommand, Clone, Debug)] | ||
enum ACVMCommand { | ||
Execute(execute_cmd::ExecuteCommand), | ||
} | ||
|
||
#[cfg(not(feature = "codegen-docs"))] | ||
pub(crate) fn start_cli() -> eyre::Result<()> { | ||
let ACVMCli { command } = ACVMCli::parse(); | ||
|
||
match command { | ||
ACVMCommand::Execute(args) => execute_cmd::run(args), | ||
}?; | ||
|
||
Ok(()) | ||
} | ||
|
||
#[cfg(feature = "codegen-docs")] | ||
pub(crate) fn start_cli() -> eyre::Result<()> { | ||
let markdown: String = clap_markdown::help_markdown::<NargoCli>(); | ||
println!("{markdown}"); | ||
Ok(()) | ||
} |
Oops, something went wrong.