Skip to content

Commit

Permalink
Merge branch 'master' into tf/parallel-workspace-info
Browse files Browse the repository at this point in the history
* master:
  chore!: Restrict packages to contain at most a single contract (#2668)
  • Loading branch information
TomAFrench committed Sep 12, 2023
2 parents 39d7763 + dc3358b commit 9b1fc23
Show file tree
Hide file tree
Showing 8 changed files with 99 additions and 107 deletions.
1 change: 0 additions & 1 deletion Cargo.lock

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

34 changes: 21 additions & 13 deletions compiler/noirc_driver/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -169,20 +169,27 @@ pub fn compile_main(
}

/// Run the frontend to check the crate for errors then compile all contracts if there were none
pub fn compile_contracts(
pub fn compile_contract(
context: &mut Context,
crate_id: CrateId,
options: &CompileOptions,
) -> CompilationResult<Vec<CompiledContract>> {
) -> CompilationResult<CompiledContract> {
let (_, warnings) = check_crate(context, crate_id, options.deny_warnings)?;

// TODO: We probably want to error if contracts is empty
let contracts = context.get_all_contracts(&crate_id);

let mut compiled_contracts = vec![];
let mut errors = warnings;

if contracts.len() > 1 {
let err = CustomDiagnostic::from_message("Packages are limited to a single contract")
.in_file(FileId::default());
return Err(vec![err]);
};

for contract in contracts {
match compile_contract(context, contract, options) {
match compile_contract_inner(context, contract, options) {
Ok(contract) => compiled_contracts.push(contract),
Err(mut more_errors) => errors.append(&mut more_errors),
}
Expand All @@ -191,19 +198,20 @@ pub fn compile_contracts(
if has_errors(&errors, options.deny_warnings) {
Err(errors)
} else {
assert_eq!(compiled_contracts.len(), 1);
let compiled_contract = compiled_contracts.remove(0);

if options.print_acir {
for compiled_contract in &compiled_contracts {
for contract_function in &compiled_contract.functions {
println!(
"Compiled ACIR for {}::{} (unoptimized):",
compiled_contract.name, contract_function.name
);
println!("{}", contract_function.bytecode);
}
for contract_function in &compiled_contract.functions {
println!(
"Compiled ACIR for {}::{} (unoptimized):",

Check warning on line 207 in compiler/noirc_driver/src/lib.rs

View workflow job for this annotation

GitHub Actions / Spellcheck / Spellcheck

Unknown word (unoptimized)
compiled_contract.name, contract_function.name
);
println!("{}", contract_function.bytecode);
}
}
// errors here is either empty or contains only warnings
Ok((compiled_contracts, errors))
Ok((compiled_contract, errors))
}
}

Expand All @@ -217,7 +225,7 @@ fn has_errors(errors: &[FileDiagnostic], deny_warnings: bool) -> bool {
}

/// Compile all of the functions associated with a Noir contract.
fn compile_contract(
fn compile_contract_inner(
context: &Context,
contract: Contract,
options: &CompileOptions,
Expand Down
1 change: 0 additions & 1 deletion compiler/wasm/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ crate-type = ["cdylib"]
[dependencies]
acvm.workspace = true
fm.workspace = true
iter-extended.workspace = true
nargo.workspace = true
noirc_driver.workspace = true
noirc_frontend.workspace = true
Expand Down
19 changes: 8 additions & 11 deletions compiler/wasm/src/compile.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
use fm::FileManager;
use gloo_utils::format::JsValueSerdeExt;
use iter_extended::try_vecmap;
use log::debug;
use noirc_driver::{
add_dep, compile_contracts, compile_main, prepare_crate, prepare_dependency, CompileOptions,
add_dep, compile_contract, compile_main, prepare_crate, prepare_dependency, CompileOptions,
};
use noirc_frontend::{graph::CrateGraph, hir::Context};
use serde::{Deserialize, Serialize};
Expand Down Expand Up @@ -116,17 +115,15 @@ pub fn compile(args: JsValue) -> JsValue {
let is_opcode_supported = acvm::pwg::default_is_opcode_supported(np_language);

if options.contracts {
let compiled_contracts =
compile_contracts(&mut context, crate_id, &options.compile_options)
.expect("Contract compilation failed")
.0;
let compiled_contract = compile_contract(&mut context, crate_id, &options.compile_options)
.expect("Contract compilation failed")
.0;

let optimized_contracts = try_vecmap(compiled_contracts, |contract| {
nargo::ops::optimize_contract(contract, np_language, &is_opcode_supported)
})
.expect("Contract optimization failed");
let optimized_contract =
nargo::ops::optimize_contract(compiled_contract, np_language, &is_opcode_supported)
.expect("Contract optimization failed");

<JsValue as JsValueSerdeExt>::from_serde(&optimized_contracts).unwrap()
<JsValue as JsValueSerdeExt>::from_serde(&optimized_contract).unwrap()
} else {
let compiled_program = compile_main(&mut context, crate_id, &options.compile_options)
.expect("Compilation failed")
Expand Down
107 changes: 45 additions & 62 deletions tooling/nargo_cli/src/cli/compile_cmd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use std::path::Path;
use acvm::acir::circuit::Opcode;
use acvm::Language;
use fm::FileManager;
use iter_extended::{try_vecmap, vecmap};
use iter_extended::vecmap;
use nargo::artifacts::contract::PreprocessedContract;
use nargo::artifacts::contract::PreprocessedContractFunction;
use nargo::artifacts::debug::DebugArtifact;
Expand Down Expand Up @@ -76,10 +76,8 @@ pub(crate) fn run(
for (package, program) in binary_packages.into_iter().zip(compiled_programs) {
save_program(program, &package, &circuit_dir, args.output_debug);
}
for (package, contracts_with_debug_artifacts) in
contract_packages.into_iter().zip(compiled_contracts)
{
save_contracts(contracts_with_debug_artifacts, &package, &circuit_dir, args.output_debug);
for (package, contract) in contract_packages.into_iter().zip(compiled_contracts) {
save_contract(contract, &package, &circuit_dir, args.output_debug);
}

Ok(())
Expand All @@ -90,19 +88,19 @@ pub(super) fn compile_workspace(
binary_packages: &[Package],
contract_packages: &[Package],
compile_options: &CompileOptions,
) -> Result<(Vec<CompiledProgram>, Vec<Vec<CompiledContract>>), CliError> {
) -> Result<(Vec<CompiledProgram>, Vec<CompiledContract>), CliError> {
let (np_language, is_opcode_supported) = backend.get_backend_info()?;

// Compile all of the packages in parallel.
let program_results: Vec<(FileManager, CompilationResult<CompiledProgram>)> = binary_packages
.par_iter()
.map(|package| compile_program(package, compile_options, np_language, &is_opcode_supported))
.collect();
let contract_results: Vec<(FileManager, CompilationResult<Vec<CompiledContract>>)> =
let contract_results: Vec<(FileManager, CompilationResult<CompiledContract>)> =
contract_packages
.par_iter()
.map(|package| {
compile_contracts(package, compile_options, np_language, &is_opcode_supported)
compile_contract(package, compile_options, np_language, &is_opcode_supported)
})
.collect();

Expand All @@ -113,7 +111,7 @@ pub(super) fn compile_workspace(
report_errors(compilation_result, &file_manager, compile_options.deny_warnings)
})
.collect::<Result<_, _>>()?;
let compiled_contracts: Vec<Vec<CompiledContract>> = contract_results
let compiled_contracts: Vec<CompiledContract> = contract_results
.into_iter()
.map(|(file_manager, compilation_result)| {
report_errors(compilation_result, &file_manager, compile_options.deny_warnings)
Expand Down Expand Up @@ -165,27 +163,26 @@ fn compile_program(
(context.file_manager, Ok((optimized_program, warnings)))
}

fn compile_contracts(
fn compile_contract(
package: &Package,
compile_options: &CompileOptions,
np_language: Language,
is_opcode_supported: &impl Fn(&Opcode) -> bool,
) -> (FileManager, CompilationResult<Vec<CompiledContract>>) {
) -> (FileManager, CompilationResult<CompiledContract>) {
let (mut context, crate_id) = prepare_package(package);
let (contracts, warnings) =
match noirc_driver::compile_contracts(&mut context, crate_id, compile_options) {
let (contract, warnings) =
match noirc_driver::compile_contract(&mut context, crate_id, compile_options) {
Ok(contracts_and_warnings) => contracts_and_warnings,
Err(errors) => {
return (context.file_manager, Err(errors));
}
};

let optimized_contracts = try_vecmap(contracts, |contract| {
let optimized_contract =
nargo::ops::optimize_contract(contract, np_language, &is_opcode_supported)
})
.expect("Backend does not support an opcode that is in the IR");
.expect("Backend does not support an opcode that is in the IR");

(context.file_manager, Ok((optimized_contracts, warnings)))
(context.file_manager, Ok((optimized_contract, warnings)))
}

fn save_program(
Expand All @@ -210,8 +207,8 @@ fn save_program(
}
}

fn save_contracts(
contracts: Vec<CompiledContract>,
fn save_contract(
contract: CompiledContract,
package: &Package,
circuit_dir: &Path,
output_debug: bool,
Expand All @@ -220,51 +217,37 @@ fn save_contracts(
// As can be seen here, It seems like a leaky abstraction where ContractFunctions (essentially CompiledPrograms)
// are compiled via nargo-core and then the PreprocessedContract is constructed here.
// This is due to EACH function needing it's own CRS, PKey, and VKey from the backend.
let preprocessed_contracts: Vec<(PreprocessedContract, DebugArtifact)> =
vecmap(contracts, |contract| {
let debug_artifact = DebugArtifact {
debug_symbols: contract
.functions
.iter()
.map(|function| function.debug.clone())
.collect(),
file_map: contract.file_map,
};

let preprocessed_functions =
vecmap(contract.functions, |func| PreprocessedContractFunction {
name: func.name,
function_type: func.function_type,
is_internal: func.is_internal,
abi: func.abi,

bytecode: func.bytecode,
});

(
PreprocessedContract {
name: contract.name,
backend: String::from(BACKEND_IDENTIFIER),
functions: preprocessed_functions,
},
debug_artifact,
)
});

for (contract, debug_artifact) in preprocessed_contracts {
save_contract_to_file(
&contract,
&format!("{}-{}", package.name, contract.name),
let debug_artifact = DebugArtifact {
debug_symbols: contract.functions.iter().map(|function| function.debug.clone()).collect(),
file_map: contract.file_map,
};

let preprocessed_functions = vecmap(contract.functions, |func| PreprocessedContractFunction {
name: func.name,
function_type: func.function_type,
is_internal: func.is_internal,
abi: func.abi,
bytecode: func.bytecode,
});

let preprocessed_contract = PreprocessedContract {
name: contract.name,
backend: String::from(BACKEND_IDENTIFIER),
functions: preprocessed_functions,
};

save_contract_to_file(
&preprocessed_contract,
&format!("{}-{}", package.name, preprocessed_contract.name),
circuit_dir,
);

if output_debug {
save_debug_artifact_to_file(
&debug_artifact,
&format!("{}-{}", package.name, preprocessed_contract.name),
circuit_dir,
);

if output_debug {
save_debug_artifact_to_file(
&debug_artifact,
&format!("{}-{}", package.name, contract.name),
circuit_dir,
);
}
}
}

Expand Down
33 changes: 14 additions & 19 deletions tooling/nargo_cli/src/cli/info_cmd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,14 +63,11 @@ pub(crate) fn run(
count_opcodes_and_gates_in_program(backend, program, package, np_language)
})?;

let contract_info = try_vecmap(compiled_contracts, |contracts| {
count_opcodes_and_gates_in_contracts(backend, contracts, np_language)
let contract_info = try_vecmap(compiled_contracts, |contract| {
count_opcodes_and_gates_in_contract(backend, contract, np_language)
})?;

let info_report = InfoReport {
programs: program_info,
contracts: contract_info.into_iter().flatten().collect(),
};
let info_report = InfoReport { programs: program_info, contracts: contract_info };

if args.json {
// Expose machine-readable JSON data.
Expand Down Expand Up @@ -176,20 +173,18 @@ fn count_opcodes_and_gates_in_program(
})
}

fn count_opcodes_and_gates_in_contracts(
fn count_opcodes_and_gates_in_contract(
backend: &Backend,
compiled_contracts: Vec<CompiledContract>,
contract: CompiledContract,
language: Language,
) -> Result<Vec<ContractInfo>, CliError> {
try_vecmap(compiled_contracts, |contract| {
let functions = try_vecmap(contract.functions, |function| -> Result<_, BackendError> {
Ok(FunctionInfo {
name: function.name,
acir_opcodes: function.bytecode.opcodes.len(),
circuit_size: backend.get_exact_circuit_size(&function.bytecode)?,
})
})?;
) -> Result<ContractInfo, CliError> {
let functions = try_vecmap(contract.functions, |function| -> Result<_, BackendError> {
Ok(FunctionInfo {
name: function.name,
acir_opcodes: function.bytecode.opcodes.len(),
circuit_size: backend.get_exact_circuit_size(&function.bytecode)?,
})
})?;

Ok(ContractInfo { name: contract.name, language, functions })
})
Ok(ContractInfo { name: contract.name, language, functions })
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[package]
name = "multiple_contracts"
type = "contract"
authors = [""]
compiler_version = "0.9.0"

[dependencies]
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
contract Foo {}


contract Bar {}

0 comments on commit 9b1fc23

Please sign in to comment.