Skip to content

Commit

Permalink
feat: make noirc_driver aware of contracts (#999)
Browse files Browse the repository at this point in the history
* feat: make `noirc_driver` aware of contracts

* feat: use new `compile_contracts` method in `wasm`
  • Loading branch information
TomAFrench authored Mar 20, 2023
1 parent 1e6761b commit c21afca
Show file tree
Hide file tree
Showing 6 changed files with 62 additions and 65 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

59 changes: 6 additions & 53 deletions crates/nargo/src/cli/compile_cmd.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
use acvm::ProofSystemCompiler;
use iter_extended::{try_btree_map, try_vecmap};
use noirc_driver::{CompileOptions, CompiledProgram, Driver};
use noirc_frontend::{hir::def_map::Contract, node_interner::FuncId};
use std::collections::BTreeMap;
use std::path::Path;

use clap::Args;
Expand All @@ -28,24 +25,15 @@ pub(crate) struct CompileCommand {
compile_options: CompileOptions,
}

struct CompiledContract {
/// The name of the contract.
name: String,
/// Each of the contract's functions are compiled into a separate `CompiledProgram`
/// stored in this `BTreeMap`.
functions: BTreeMap<String, CompiledProgram>,
}

pub(crate) fn run(args: CompileCommand, config: NargoConfig) -> Result<(), CliError> {
let driver = check_crate(&config.program_dir, &args.compile_options)?;

let circuit_dir = config.program_dir.join(TARGET_DIR);

// If contracts is set we're compiling every function in a 'contract' rather than just 'main'.
if args.contracts {
let compiled_contracts = try_vecmap(driver.get_all_contracts(), |contract| {
compile_contract(&driver, contract, &args.compile_options)
})?;
let mut driver = setup_driver(&config.program_dir)?;
let compiled_contracts = driver
.compile_contracts(&args.compile_options)
.map_err(|_| CliError::CompilationError)?;

// Flatten each contract into a list of its functions, each being assigned a unique name.
let compiled_programs = compiled_contracts.into_iter().flat_map(|contract| {
Expand All @@ -61,8 +49,7 @@ pub(crate) fn run(args: CompileCommand, config: NargoConfig) -> Result<(), CliEr
}
Ok(())
} else {
let main = driver.main_function().map_err(|_| CliError::CompilationError)?;
let program = compile_program(&driver, main, &args.compile_options, &args.circuit_name)?;
let program = compile_circuit(&config.program_dir, &args.compile_options)?;
save_and_preprocess_program(&program, &args.circuit_name, &circuit_dir)
}
}
Expand All @@ -72,40 +59,6 @@ fn setup_driver(program_dir: &Path) -> Result<Driver, DependencyResolutionError>
Resolver::resolve_root_manifest(program_dir, backend.np_language())
}

fn check_crate(program_dir: &Path, options: &CompileOptions) -> Result<Driver, CliError> {
let mut driver = setup_driver(program_dir)?;
driver.check_crate(options).map_err(|_| CliError::CompilationError)?;
Ok(driver)
}

/// Compiles all of the functions associated with a Noir contract.
fn compile_contract(
driver: &Driver,
contract: Contract,
compile_options: &CompileOptions,
) -> Result<CompiledContract, CliError> {
let functions = try_btree_map(&contract.functions, |function| {
let function_name = driver.function_name(*function).to_owned();
let program_id = format!("{}-{}", contract.name, function_name);

compile_program(driver, *function, compile_options, &program_id)
.map(|program| (function_name, program))
})?;

Ok(CompiledContract { name: contract.name, functions })
}

fn compile_program(
driver: &Driver,
main: FuncId,
compile_options: &CompileOptions,
program_id: &str,
) -> Result<CompiledProgram, CliError> {
driver
.compile_no_check(compile_options, main)
.map_err(|_| CliError::Generic(format!("'{}' failed to compile", program_id)))
}

/// Save a program to disk along with proving and verification keys.
fn save_and_preprocess_program(
compiled_program: &CompiledProgram,
Expand All @@ -120,7 +73,7 @@ fn save_and_preprocess_program(
pub(crate) fn compile_circuit(
program_dir: &Path,
compile_options: &CompileOptions,
) -> Result<noirc_driver::CompiledProgram, CliError> {
) -> Result<CompiledProgram, CliError> {
let mut driver = setup_driver(program_dir)?;
driver.compile_main(compile_options).map_err(|_| CliError::CompilationError)
}
1 change: 1 addition & 0 deletions crates/noirc_driver/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ edition.workspace = true

[dependencies]
clap.workspace = true
iter-extended.workspace = true
noirc_errors.workspace = true
noirc_frontend.workspace = true
noirc_evaluator.workspace = true
Expand Down
11 changes: 11 additions & 0 deletions crates/noirc_driver/src/contract.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
use std::collections::BTreeMap;

use crate::CompiledProgram;

pub struct CompiledContract {
/// The name of the contract.
pub name: String,
/// Each of the contract's functions are compiled into a separate `CompiledProgram`
/// stored in this `BTreeMap`.
pub functions: BTreeMap<String, CompiledProgram>,
}
29 changes: 29 additions & 0 deletions crates/noirc_driver/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
use acvm::Language;
use clap::Args;
use fm::FileType;
use iter_extended::{try_btree_map, try_vecmap};
use noirc_abi::FunctionSignature;
use noirc_errors::{reporter, ReportedError};
use noirc_evaluator::create_circuit;
Expand All @@ -16,7 +17,10 @@ use noirc_frontend::node_interner::FuncId;
use serde::{Deserialize, Serialize};
use std::path::{Path, PathBuf};

mod contract;
mod program;

pub use contract::CompiledContract;
pub use program::CompiledProgram;

pub struct Driver {
Expand Down Expand Up @@ -181,6 +185,31 @@ impl Driver {
self.compile_no_check(options, main)
}

/// Run the frontend to check the crate for errors then compile all contracts if there were none
pub fn compile_contracts(
&mut self,
options: &CompileOptions,
) -> Result<Vec<CompiledContract>, ReportedError> {
self.check_crate(options)?;
let contracts = self.get_all_contracts();
try_vecmap(contracts, |contract| self.compile_contract(contract, options))
}

/// Compile all of the functions associated with a Noir contract.
fn compile_contract(
&self,
contract: Contract,
options: &CompileOptions,
) -> Result<CompiledContract, ReportedError> {
let functions = try_btree_map(&contract.functions, |function| {
let function_name = self.function_name(*function).to_owned();

self.compile_no_check(options, *function).map(|program| (function_name, program))
})?;

Ok(CompiledContract { name: contract.name, functions })
}

/// Returns the FuncId of the 'main' funciton.
/// - Expects check_crate to be called beforehand
/// - Panics if no main function is found
Expand Down
26 changes: 14 additions & 12 deletions crates/wasm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,18 +64,20 @@ pub fn compile(args: JsValue) -> JsValue {
driver.check_crate(&options.compile_options).unwrap_or_else(|_| panic!("Crate check failed"));

if options.contracts {
let mut collected_compiled_programs = vec![];

for contract in driver.get_all_contracts() {
contract.functions.into_iter().for_each(|function| {
let name = driver.function_name(function);
let key = format!("{}-{name}", &contract.name);
let compiled_program = driver
.compile_no_check(&options.compile_options, function)
.unwrap_or_else(|_| panic!("Compilation of `{key}` failed"));
collected_compiled_programs.push((key, compiled_program));
});
}
let compiled_contracts = driver
.compile_contracts(&options.compile_options)
.unwrap_or_else(|_| panic!("Contract compilation failed"));

// Flatten each contract into a list of its functions, each being assigned a unique name.
let collected_compiled_programs: Vec<_> = compiled_contracts
.into_iter()
.flat_map(|contract| {
contract.functions.into_iter().map(move |(function, program)| {
let program_name = format!("{}-{}", &contract.name, function);
(program_name, program)
})
})
.collect();

<JsValue as JsValueSerdeExt>::from_serde(&collected_compiled_programs).unwrap()
} else {
Expand Down

0 comments on commit c21afca

Please sign in to comment.