From ce16c0b14565cfe1bc2c9f09ae71643d2657440b Mon Sep 17 00:00:00 2001 From: Tom French <15848336+TomAFrench@users.noreply.github.com> Date: Tue, 3 Oct 2023 23:41:57 +0100 Subject: [PATCH] feat(wasm)!: update wasm artifacts to match cli artifacts (#2973) --- .../test/browser/compile_prove_verify.test.ts | 7 ++- .../test/browser/recursion.test.ts | 6 +-- .../test/node/smart_contract_verifier.test.ts | 7 ++- compiler/wasm/src/compile.rs | 45 ++++++++++++++++++- compiler/wasm/test/browser/index.test.ts | 14 +++--- compiler/wasm/test/node/index.test.ts | 20 ++++----- compiler/wasm/test/shared.ts | 5 ++- 7 files changed, 72 insertions(+), 32 deletions(-) diff --git a/compiler/integration-tests/test/browser/compile_prove_verify.test.ts b/compiler/integration-tests/test/browser/compile_prove_verify.test.ts index 43770478ae9..e9d6d3a0f9e 100644 --- a/compiler/integration-tests/test/browser/compile_prove_verify.test.ts +++ b/compiler/integration-tests/test/browser/compile_prove_verify.test.ts @@ -49,17 +49,16 @@ test_cases.forEach((testInfo) => { const noir_source = await getFile(`${base_relative_path}/${test_case}/src/main.nr`); - let compile_output; + let noir_program; try { - compile_output = await getCircuit(noir_source); + noir_program = await getCircuit(noir_source); - expect(await compile_output, 'Compile output ').to.be.an('object'); + expect(await noir_program, 'Compile output ').to.be.an('object'); } catch (e) { expect(e, 'Compilation Step').to.not.be.an('error'); throw e; } - const noir_program = { bytecode: compile_output.circuit, abi: compile_output.abi }; const backend = new BarretenbergBackend(noir_program); const program = new Noir(noir_program, backend); diff --git a/compiler/integration-tests/test/browser/recursion.test.ts b/compiler/integration-tests/test/browser/recursion.test.ts index 6d5e976d5dc..6cfe74ae100 100644 --- a/compiler/integration-tests/test/browser/recursion.test.ts +++ b/compiler/integration-tests/test/browser/recursion.test.ts @@ -48,10 +48,9 @@ describe('It compiles noir program code, receiving circuit bytes and abi object. }); it('Should generate valid inner proof for correct input, then verify proof within a proof', async () => { - const { circuit: main_circuit, abi: main_abi } = await getCircuit(circuit_main_source); + const main_program = await getCircuit(circuit_main_source); const main_inputs = TOML.parse(circuit_main_toml); - const main_program = { bytecode: main_circuit, abi: main_abi }; const main_backend = new BarretenbergBackend(main_program); const main_witnessUint8Array = await generateWitness(main_program, main_inputs); @@ -79,8 +78,7 @@ describe('It compiles noir program code, receiving circuit bytes and abi object. logger.debug('recursion_inputs', recursion_inputs); - const { circuit: recursion_circuit, abi: recursion_abi } = await getCircuit(circuit_recursion_source); - const recursion_program = { bytecode: recursion_circuit, abi: recursion_abi }; + const recursion_program = await getCircuit(circuit_recursion_source); const recursion_backend = new BarretenbergBackend(recursion_program); diff --git a/compiler/integration-tests/test/node/smart_contract_verifier.test.ts b/compiler/integration-tests/test/node/smart_contract_verifier.test.ts index 6c15dc063d6..0cdebc0f4c7 100644 --- a/compiler/integration-tests/test/node/smart_contract_verifier.test.ts +++ b/compiler/integration-tests/test/node/smart_contract_verifier.test.ts @@ -38,17 +38,16 @@ test_cases.forEach((testInfo) => { const noir_source_path = resolve(`${base_relative_path}/${test_case}/src/main.nr`); - let compile_output; + let noir_program; try { - compile_output = await getCircuit(noir_source_path); + noir_program = await getCircuit(noir_source_path); - expect(await compile_output, 'Compile output ').to.be.an('object'); + expect(await noir_program, 'Compile output ').to.be.an('object'); } catch (e) { expect(e, 'Compilation Step').to.not.be.an('error'); throw e; } - const noir_program = { bytecode: compile_output.circuit, abi: compile_output.abi }; const backend = new BarretenbergBackend(noir_program); const program = new Noir(noir_program, backend); diff --git a/compiler/wasm/src/compile.rs b/compiler/wasm/src/compile.rs index dde2310118f..b6fc9fad573 100644 --- a/compiler/wasm/src/compile.rs +++ b/compiler/wasm/src/compile.rs @@ -1,14 +1,21 @@ use fm::FileManager; use gloo_utils::format::JsValueSerdeExt; use log::debug; +use nargo::artifacts::{ + contract::{PreprocessedContract, PreprocessedContractFunction}, + program::PreprocessedProgram, +}; use noirc_driver::{ add_dep, compile_contract, compile_main, prepare_crate, prepare_dependency, CompileOptions, + CompiledContract, CompiledProgram, }; use noirc_frontend::{graph::CrateGraph, hir::Context}; use serde::{Deserialize, Serialize}; use std::path::Path; use wasm_bindgen::prelude::*; +const BACKEND_IDENTIFIER: &str = "acvm-backend-barretenberg"; + #[derive(Debug, Serialize, Deserialize)] pub struct WASMCompileOptions { #[serde(default = "default_entry_point")] @@ -123,7 +130,9 @@ pub fn compile(args: JsValue) -> JsValue { nargo::ops::optimize_contract(compiled_contract, np_language, &is_opcode_supported) .expect("Contract optimization failed"); - ::from_serde(&optimized_contract).unwrap() + let preprocessed_contract = preprocess_contract(optimized_contract); + + ::from_serde(&preprocessed_contract).unwrap() } else { let compiled_program = compile_main(&mut context, crate_id, &options.compile_options, None, true) @@ -134,7 +143,39 @@ pub fn compile(args: JsValue) -> JsValue { nargo::ops::optimize_program(compiled_program, np_language, &is_opcode_supported) .expect("Program optimization failed"); - ::from_serde(&optimized_program).unwrap() + let preprocessed_program = preprocess_program(optimized_program); + + ::from_serde(&preprocessed_program).unwrap() + } +} + +fn preprocess_program(program: CompiledProgram) -> PreprocessedProgram { + PreprocessedProgram { + hash: program.hash, + backend: String::from(BACKEND_IDENTIFIER), + abi: program.abi, + bytecode: program.circuit, + } +} + +fn preprocess_contract(contract: CompiledContract) -> PreprocessedContract { + let preprocessed_functions = contract + .functions + .into_iter() + .map(|func| PreprocessedContractFunction { + name: func.name, + function_type: func.function_type, + is_internal: func.is_internal, + abi: func.abi, + bytecode: func.bytecode, + }) + .collect(); + + PreprocessedContract { + name: contract.name, + backend: String::from(BACKEND_IDENTIFIER), + functions: preprocessed_functions, + events: contract.events, } } diff --git a/compiler/wasm/test/browser/index.test.ts b/compiler/wasm/test/browser/index.test.ts index 5b586344f80..662aae5a666 100644 --- a/compiler/wasm/test/browser/index.test.ts +++ b/compiler/wasm/test/browser/index.test.ts @@ -16,19 +16,23 @@ async function getSource(): Promise { return getFileContent(noirSourcePath); } -async function getPrecompiledSource(): Promise { +// eslint-disable-next-line @typescript-eslint/no-explicit-any +async function getPrecompiledSource(): Promise { const compiledData = await getFileContent(nargoArtifactPath); - return JSON.parse(compiledData).bytecode; + return JSON.parse(compiledData); } describe('noir wasm compilation', () => { it('matches nargos compilation', async () => { const source = await getSource(); - const wasmCircuitBase64 = await compileNoirSource(source); + const wasmCircuit = await compileNoirSource(source); - const cliCircuitBase64 = await getPrecompiledSource(); + const cliCircuit = await getPrecompiledSource(); - expect(wasmCircuitBase64).to.equal(cliCircuitBase64); + // We don't expect the hashes to match due to how `noir_wasm` handles dependencies + expect(wasmCircuit.bytecode).to.eq(cliCircuit.bytecode); + expect(wasmCircuit.abi).to.deep.eq(cliCircuit.abi); + expect(wasmCircuit.backend).to.eq(cliCircuit.backend); }).timeout(20e3); // 20 seconds }); diff --git a/compiler/wasm/test/node/index.test.ts b/compiler/wasm/test/node/index.test.ts index 9c4bb4439fa..3ecb1bfc4b4 100644 --- a/compiler/wasm/test/node/index.test.ts +++ b/compiler/wasm/test/node/index.test.ts @@ -11,25 +11,23 @@ async function getSource(): Promise { return getFileContent(noirSourcePath); } -async function getPrecompiledSource(): Promise { +// eslint-disable-next-line @typescript-eslint/no-explicit-any +async function getPrecompiledSource(): Promise { const compiledData = await getFileContent(nargoArtifactPath); - return JSON.parse(compiledData).bytecode; + return JSON.parse(compiledData); } describe('noir wasm compilation', () => { it('matches nargos compilation', async () => { const source = await getSource(); - const wasmCircuitBase64 = await compileNoirSource(source); + const wasmCircuit = await compileNoirSource(source); - const cliCircuitBase64 = await getPrecompiledSource(); + const cliCircuit = await getPrecompiledSource(); - console.log('wasm', wasmCircuitBase64); - - console.log('cli', cliCircuitBase64); - - console.log('Compilation is a match? ', wasmCircuitBase64 === cliCircuitBase64); - - expect(wasmCircuitBase64).to.equal(cliCircuitBase64); + // We don't expect the hashes to match due to how `noir_wasm` handles dependencies + expect(wasmCircuit.bytecode).to.eq(cliCircuit.bytecode); + expect(wasmCircuit.abi).to.deep.eq(cliCircuit.abi); + expect(wasmCircuit.backend).to.eq(cliCircuit.backend); }).timeout(10e3); }); diff --git a/compiler/wasm/test/shared.ts b/compiler/wasm/test/shared.ts index d1b7831befa..eb5b414f2b5 100644 --- a/compiler/wasm/test/shared.ts +++ b/compiler/wasm/test/shared.ts @@ -4,7 +4,8 @@ import { compile } from '@noir-lang/noir_wasm'; export const noirSourcePath = '../../noir-script/src/main.nr'; export const nargoArtifactPath = '../../noir-script/target/noir_wasm_testing.json'; -export async function compileNoirSource(noir_source: string): Promise { +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export async function compileNoirSource(noir_source: string): Promise { console.log('Compiling Noir source...'); initializeResolver((id: string) => { @@ -24,7 +25,7 @@ export async function compileNoirSource(noir_source: string): Promise { console.log('Noir source compilation done.'); - return compiled_noir.circuit; + return compiled_noir; } catch (e) { console.log('Error while compiling:', e); }