Skip to content

Commit

Permalink
chore: simplify nargo CLI to read from artifacts (#6279)
Browse files Browse the repository at this point in the history
As we're shifting towards a more artifact-focused workflow, I've
modified the nargo CLI to prioritise writing everything to file. These
can then be read from again when these programs are needed.

The aim is that as we remove these commands from the `nargo` binary, we
can ensure that we have compatibility between nargo artifacts and `bb`
  • Loading branch information
TomAFrench committed May 8, 2024
1 parent 27ac344 commit b2c019b
Show file tree
Hide file tree
Showing 10 changed files with 120 additions and 156 deletions.
6 changes: 3 additions & 3 deletions noir/noir-repo/tooling/nargo/src/artifacts/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use std::collections::{BTreeMap, HashMap};

use fm::FileId;

#[derive(Serialize, Deserialize)]
#[derive(Clone, Serialize, Deserialize)]
pub struct ContractOutputsArtifact {
pub structs: HashMap<String, Vec<AbiType>>,
pub globals: HashMap<String, Vec<AbiValue>>,
Expand All @@ -21,7 +21,7 @@ impl From<CompiledContractOutputs> for ContractOutputsArtifact {
}
}

#[derive(Serialize, Deserialize)]
#[derive(Clone, Serialize, Deserialize)]
pub struct ContractArtifact {
/// Version of noir used to compile this contract
pub noir_version: String,
Expand Down Expand Up @@ -51,7 +51,7 @@ impl From<CompiledContract> for ContractArtifact {
///
/// A contract function unlike a regular Noir program however can have additional properties.
/// One of these being a function type.
#[derive(Debug, Serialize, Deserialize)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ContractFunctionArtifact {
pub name: String,

Expand Down
27 changes: 27 additions & 0 deletions noir/noir-repo/tooling/nargo/src/artifacts/debug.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use std::{
};

pub use super::debug_vars::{DebugVars, StackFrame};
use super::{contract::ContractArtifact, program::ProgramArtifact};
use fm::{FileId, FileManager, PathString};

/// A Debug Artifact stores, for a given program, the debug info for every function
Expand Down Expand Up @@ -128,6 +129,16 @@ impl From<CompiledProgram> for DebugArtifact {
}
}

impl From<ProgramArtifact> for DebugArtifact {
fn from(program_artifact: ProgramArtifact) -> Self {
DebugArtifact {
debug_symbols: program_artifact.debug_symbols.debug_infos,
file_map: program_artifact.file_map,
warnings: Vec::new(),
}
}
}

impl From<CompiledContract> for DebugArtifact {
fn from(compiled_artifact: CompiledContract) -> Self {
let all_functions_debug: Vec<DebugInfo> = compiled_artifact
Expand All @@ -144,6 +155,22 @@ impl From<CompiledContract> for DebugArtifact {
}
}

impl From<ContractArtifact> for DebugArtifact {
fn from(compiled_artifact: ContractArtifact) -> Self {
let all_functions_debug: Vec<DebugInfo> = compiled_artifact
.functions
.into_iter()
.flat_map(|contract_function| contract_function.debug_symbols.debug_infos)
.collect();

DebugArtifact {
debug_symbols: all_functions_debug,
file_map: compiled_artifact.file_map,
warnings: Vec::new(),
}
}
}

impl<'a> Files<'a> for DebugArtifact {
type FileId = FileId;
type Name = PathString;
Expand Down
2 changes: 1 addition & 1 deletion noir/noir-repo/tooling/nargo/src/artifacts/program.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use noirc_driver::DebugFile;
use noirc_errors::debug_info::ProgramDebugInfo;
use serde::{Deserialize, Serialize};

#[derive(Serialize, Deserialize, Debug)]
#[derive(Clone, Serialize, Deserialize, Debug)]
pub struct ProgramArtifact {
pub noir_version: String,

Expand Down
29 changes: 7 additions & 22 deletions noir/noir-repo/tooling/nargo_cli/src/cli/codegen_verifier_cmd.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
use super::compile_cmd::compile_workspace_full;
use super::fs::{create_named_dir, write_to_file};
use super::NargoConfig;
use crate::backends::Backend;
use crate::cli::fs::program::read_program_from_file;
use crate::errors::CliError;

use clap::Args;
use nargo::ops::{compile_program, report_errors};
use nargo::{insert_all_files_for_workspace_into_file_manager, parse_all};
use nargo_toml::{get_package_manifest, resolve_workspace_from_toml, PackageSelection};
use noirc_driver::{file_manager_with_stdlib, CompileOptions, NOIR_ARTIFACT_VERSION_STRING};
use noirc_driver::{CompileOptions, CompiledProgram, NOIR_ARTIFACT_VERSION_STRING};
use noirc_frontend::graph::CrateName;

/// Generates a Solidity verifier smart contract for the program
Expand Down Expand Up @@ -40,28 +40,13 @@ pub(crate) fn run(
Some(NOIR_ARTIFACT_VERSION_STRING.to_string()),
)?;

let mut workspace_file_manager = file_manager_with_stdlib(&workspace.root_dir);
insert_all_files_for_workspace_into_file_manager(&workspace, &mut workspace_file_manager);
let parsed_files = parse_all(&workspace_file_manager);
// Compile the full workspace in order to generate any build artifacts.
compile_workspace_full(&workspace, &args.compile_options)?;

let binary_packages = workspace.into_iter().filter(|package| package.is_binary());
for package in binary_packages {
let compilation_result = compile_program(
&workspace_file_manager,
&parsed_files,
package,
&args.compile_options,
None,
);

let program = report_errors(
compilation_result,
&workspace_file_manager,
args.compile_options.deny_warnings,
args.compile_options.silence_warnings,
)?;

let program = nargo::ops::transform_program(program, args.compile_options.expression_width);
let program_artifact_path = workspace.package_build_path(package);
let program: CompiledProgram = read_program_from_file(program_artifact_path)?.into();

// TODO(https://github.com/noir-lang/noir/issues/4428):
// We do not expect to have a smart contract verifier for a foldable program with multiple circuits.
Expand Down
2 changes: 1 addition & 1 deletion noir/noir-repo/tooling/nargo_cli/src/cli/compile_cmd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ fn watch_workspace(workspace: &Workspace, compile_options: &CompileOptions) -> n
Ok(())
}

fn compile_workspace_full(
pub(super) fn compile_workspace_full(
workspace: &Workspace,
compile_options: &CompileOptions,
) -> Result<(), CliError> {
Expand Down
35 changes: 9 additions & 26 deletions noir/noir-repo/tooling/nargo_cli/src/cli/execute_cmd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,18 @@ use clap::Args;
use nargo::artifacts::debug::DebugArtifact;
use nargo::constants::PROVER_INPUT_FILE;
use nargo::errors::try_to_diagnose_runtime_error;
use nargo::ops::{compile_program, report_errors, DefaultForeignCallExecutor};
use nargo::ops::DefaultForeignCallExecutor;
use nargo::package::Package;
use nargo::{insert_all_files_for_workspace_into_file_manager, parse_all};
use nargo_toml::{get_package_manifest, resolve_workspace_from_toml, PackageSelection};
use noirc_abi::input_parser::{Format, InputValue};
use noirc_abi::InputMap;
use noirc_driver::{
file_manager_with_stdlib, CompileOptions, CompiledProgram, NOIR_ARTIFACT_VERSION_STRING,
};
use noirc_driver::{CompileOptions, CompiledProgram, NOIR_ARTIFACT_VERSION_STRING};
use noirc_frontend::graph::CrateName;

use super::compile_cmd::compile_workspace_full;
use super::fs::{inputs::read_inputs_from_file, witness::save_witness_to_dir};
use super::NargoConfig;
use crate::cli::fs::program::read_program_from_file;
use crate::errors::CliError;

/// Executes a circuit to calculate its return value
Expand Down Expand Up @@ -59,32 +58,16 @@ pub(crate) fn run(args: ExecuteCommand, config: NargoConfig) -> Result<(), CliEr
)?;
let target_dir = &workspace.target_directory_path();

let mut workspace_file_manager = file_manager_with_stdlib(&workspace.root_dir);
insert_all_files_for_workspace_into_file_manager(&workspace, &mut workspace_file_manager);
let parsed_files = parse_all(&workspace_file_manager);
// Compile the full workspace in order to generate any build artifacts.
compile_workspace_full(&workspace, &args.compile_options)?;

let binary_packages = workspace.into_iter().filter(|package| package.is_binary());
for package in binary_packages {
let compilation_result = compile_program(
&workspace_file_manager,
&parsed_files,
package,
&args.compile_options,
None,
);

let compiled_program = report_errors(
compilation_result,
&workspace_file_manager,
args.compile_options.deny_warnings,
args.compile_options.silence_warnings,
)?;

let compiled_program =
nargo::ops::transform_program(compiled_program, args.compile_options.expression_width);
let program_artifact_path = workspace.package_build_path(package);
let program: CompiledProgram = read_program_from_file(program_artifact_path)?.into();

let (return_value, witness_stack) = execute_program_and_decode(
compiled_program,
program,
package,
&args.prover_name,
args.oracle_resolver.as_deref(),
Expand Down
13 changes: 13 additions & 0 deletions noir/noir-repo/tooling/nargo_cli/src/cli/fs/program.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,3 +60,16 @@ pub(crate) fn read_program_from_file<P: AsRef<Path>>(

Ok(program)
}

pub(crate) fn read_contract_from_file<P: AsRef<Path>>(
circuit_path: P,
) -> Result<ContractArtifact, FilesystemError> {
let file_path = circuit_path.as_ref().with_extension("json");

let input_string =
std::fs::read(&file_path).map_err(|_| FilesystemError::PathNotValid(file_path))?;
let contract = serde_json::from_slice(&input_string)
.map_err(|err| FilesystemError::ProgramSerializationError(err.to_string()))?;

Ok(contract)
}
76 changes: 36 additions & 40 deletions noir/noir-repo/tooling/nargo_cli/src/cli/info_cmd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,11 @@ use backend_interface::BackendError;
use clap::Args;
use iter_extended::vecmap;
use nargo::{
artifacts::debug::DebugArtifact, insert_all_files_for_workspace_into_file_manager,
ops::report_errors, package::Package, parse_all,
artifacts::{contract::ContractArtifact, debug::DebugArtifact, program::ProgramArtifact},
package::Package,
};
use nargo_toml::{get_package_manifest, resolve_workspace_from_toml, PackageSelection};
use noirc_driver::{
file_manager_with_stdlib, CompileOptions, CompiledContract, CompiledProgram,
NOIR_ARTIFACT_VERSION_STRING,
};
use noirc_driver::{CompileOptions, NOIR_ARTIFACT_VERSION_STRING};
use noirc_errors::{debug_info::OpCodesCount, Location};
use noirc_frontend::graph::CrateName;
use prettytable::{row, table, Row};
Expand All @@ -22,7 +19,11 @@ use serde::Serialize;
use crate::backends::Backend;
use crate::errors::CliError;

use super::{compile_cmd::compile_workspace, NargoConfig};
use super::{
compile_cmd::compile_workspace_full,
fs::program::{read_contract_from_file, read_program_from_file},
NargoConfig,
};

/// Provides detailed information on each of a program's function (represented by a single circuit)
///
Expand Down Expand Up @@ -66,35 +67,32 @@ pub(crate) fn run(
Some(NOIR_ARTIFACT_VERSION_STRING.to_string()),
)?;

let mut workspace_file_manager = file_manager_with_stdlib(&workspace.root_dir);
insert_all_files_for_workspace_into_file_manager(&workspace, &mut workspace_file_manager);
let parsed_files = parse_all(&workspace_file_manager);

let compiled_workspace = compile_workspace(
&workspace_file_manager,
&parsed_files,
&workspace,
&args.compile_options,
);

let (compiled_programs, compiled_contracts) = report_errors(
compiled_workspace,
&workspace_file_manager,
args.compile_options.deny_warnings,
args.compile_options.silence_warnings,
)?;
// Compile the full workspace in order to generate any build artifacts.
compile_workspace_full(&workspace, &args.compile_options)?;

let compiled_programs = vecmap(compiled_programs, |program| {
nargo::ops::transform_program(program, args.compile_options.expression_width)
});
let compiled_contracts = vecmap(compiled_contracts, |contract| {
nargo::ops::transform_contract(contract, args.compile_options.expression_width)
});
let binary_packages: Vec<(Package, ProgramArtifact)> = workspace
.into_iter()
.filter(|package| package.is_binary())
.map(|package| -> Result<(Package, ProgramArtifact), CliError> {
let program_artifact_path = workspace.package_build_path(package);
let program = read_program_from_file(program_artifact_path)?;
Ok((package.clone(), program))
})
.collect::<Result<_, _>>()?;

let compiled_contracts: Vec<ContractArtifact> = workspace
.into_iter()
.filter(|package| package.is_contract())
.map(|package| {
let contract_artifact_path = workspace.package_build_path(package);
read_contract_from_file(contract_artifact_path)
})
.collect::<Result<_, _>>()?;

if args.profile_info {
for compiled_program in &compiled_programs {
for (_, compiled_program) in &binary_packages {
let debug_artifact = DebugArtifact::from(compiled_program.clone());
for function_debug in compiled_program.debug.iter() {
for function_debug in compiled_program.debug_symbols.debug_infos.iter() {
let span_opcodes = function_debug.count_span_opcodes();
print_span_opcodes(span_opcodes, &debug_artifact);
}
Expand All @@ -104,24 +102,22 @@ pub(crate) fn run(
let debug_artifact = DebugArtifact::from(compiled_contract.clone());
let functions = &compiled_contract.functions;
for contract_function in functions {
for function_debug in contract_function.debug.iter() {
for function_debug in contract_function.debug_symbols.debug_infos.iter() {
let span_opcodes = function_debug.count_span_opcodes();
print_span_opcodes(span_opcodes, &debug_artifact);
}
}
}
}

let binary_packages =
workspace.into_iter().filter(|package| package.is_binary()).zip(compiled_programs);

let program_info = binary_packages
.into_iter()
.par_bridge()
.map(|(package, program)| {
count_opcodes_and_gates_in_program(
backend,
program,
package,
&package,
args.compile_options.expression_width,
)
})
Expand Down Expand Up @@ -287,12 +283,12 @@ impl From<ContractInfo> for Vec<Row> {

fn count_opcodes_and_gates_in_program(
backend: &Backend,
compiled_program: CompiledProgram,
compiled_program: ProgramArtifact,
package: &Package,
expression_width: ExpressionWidth,
) -> Result<ProgramInfo, CliError> {
let functions = compiled_program
.program
.bytecode
.functions
.into_par_iter()
.enumerate()
Expand All @@ -314,7 +310,7 @@ fn count_opcodes_and_gates_in_program(

fn count_opcodes_and_gates_in_contract(
backend: &Backend,
contract: CompiledContract,
contract: ContractArtifact,
expression_width: ExpressionWidth,
) -> Result<ContractInfo, CliError> {
let functions = contract
Expand Down
Loading

0 comments on commit b2c019b

Please sign in to comment.