From b87561a813574e47864b7001e73b9a995c28381c Mon Sep 17 00:00:00 2001 From: Santiago Palladino Date: Tue, 9 Jan 2024 16:14:05 -0300 Subject: [PATCH 01/16] Update nargo and noir-wasm --- noir/Cargo.lock | 8 +- noir/Cargo.toml | 1 + noir/acvm-repo/acir/Cargo.toml | 2 +- noir/compiler/noirc_errors/Cargo.toml | 5 +- noir/compiler/noirc_errors/src/debug_info.rs | 48 +++++++++++- noir/compiler/wasm/Cargo.toml | 1 + noir/compiler/wasm/package.json | 4 + noir/compiler/wasm/src/compile.rs | 70 +++++++----------- noir/compiler/wasm/src/types/noir_artifact.ts | 41 +++++----- .../compiler/node/compile_with_deps.test.ts | 72 ++++++++++++++++-- noir/tooling/nargo/src/artifacts/contract.rs | 29 +++++++- noir/tooling/nargo/src/artifacts/program.rs | 30 ++++++++ noir/tooling/nargo_cli/src/cli/compile_cmd.rs | 74 ++----------------- noir/tooling/nargo_cli/src/cli/fs/program.rs | 24 +----- noir/yarn.lock | 16 ++++ 15 files changed, 255 insertions(+), 170 deletions(-) diff --git a/noir/Cargo.lock b/noir/Cargo.lock index 438d74b1b2d..f6ca8463782 100644 --- a/noir/Cargo.lock +++ b/noir/Cargo.lock @@ -1664,9 +1664,9 @@ dependencies = [ [[package]] name = "flate2" -version = "1.0.26" +version = "1.0.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b9429470923de8e8cbd4d2dc513535400b4b3fef0319fb5c4e1f520a7bef743" +checksum = "46303f565772937ffe1d394a4fac6f411c6013172fadde9dcdb1e147a086940e" dependencies = [ "crc32fast", "miniz_oxide", @@ -2871,6 +2871,7 @@ dependencies = [ "nargo", "noirc_driver", "noirc_errors", + "noirc_evaluator", "noirc_frontend", "rust-embed", "serde", @@ -2938,11 +2939,14 @@ name = "noirc_errors" version = "0.22.0" dependencies = [ "acvm", + "base64 0.21.2", "chumsky", "codespan", "codespan-reporting", + "flate2", "fm", "serde", + "serde_json", "serde_with", "tracing", ] diff --git a/noir/Cargo.toml b/noir/Cargo.toml index 05139934c62..f0fc7249efc 100644 --- a/noir/Cargo.toml +++ b/noir/Cargo.toml @@ -123,6 +123,7 @@ num-traits = "0.2" similar-asserts = "1.5.0" tempfile = "3.6.0" jsonrpc = { version = "0.16.0", features = ["minreq_http"] } +flate2 = "1.0.24" tracing = "0.1.40" tracing-web = "0.1.3" diff --git a/noir/acvm-repo/acir/Cargo.toml b/noir/acvm-repo/acir/Cargo.toml index a0877120a58..b44c64dd838 100644 --- a/noir/acvm-repo/acir/Cargo.toml +++ b/noir/acvm-repo/acir/Cargo.toml @@ -17,7 +17,7 @@ acir_field.workspace = true brillig.workspace = true serde.workspace = true thiserror.workspace = true -flate2 = "1.0.24" +flate2.workspace = true bincode.workspace = true base64.workspace = true diff --git a/noir/compiler/noirc_errors/Cargo.toml b/noir/compiler/noirc_errors/Cargo.toml index 02e97b2c670..935137ba2fc 100644 --- a/noir/compiler/noirc_errors/Cargo.toml +++ b/noir/compiler/noirc_errors/Cargo.toml @@ -15,4 +15,7 @@ fm.workspace = true chumsky.workspace = true serde.workspace = true serde_with = "3.2.0" -tracing.workspace = true \ No newline at end of file +tracing.workspace = true +flate2.workspace = true +serde_json.workspace = true +base64.workspace = true \ No newline at end of file diff --git a/noir/compiler/noirc_errors/src/debug_info.rs b/noir/compiler/noirc_errors/src/debug_info.rs index ee40ced19bf..a15119943c1 100644 --- a/noir/compiler/noirc_errors/src/debug_info.rs +++ b/noir/compiler/noirc_errors/src/debug_info.rs @@ -1,14 +1,24 @@ use acvm::acir::circuit::OpcodeLocation; use acvm::compiler::AcirTransformationMap; +use base64::Engine; +use flate2::read::DeflateDecoder; +use flate2::write::DeflateEncoder; +use flate2::Compression; +use serde::Deserializer; +use serde::Serializer; use serde_with::serde_as; use serde_with::DisplayFromStr; use std::collections::BTreeMap; use std::collections::HashMap; +use std::io::Read; +use std::io::Write; use std::mem; use crate::Location; -use serde::{Deserialize, Serialize}; +use serde::{ + de::Error as DeserializationError, ser::Error as SerializationError, Deserialize, Serialize, +}; #[serde_as] #[derive(Default, Debug, Clone, Deserialize, Serialize)] @@ -86,4 +96,40 @@ impl DebugInfo { counted_opcodes } + + pub fn serialize_compressed_base64_json( + debug_info: &DebugInfo, + s: S, + ) -> Result + where + S: Serializer, + { + let json_str = serde_json::to_string(debug_info).map_err(S::Error::custom)?; + + let mut encoder = DeflateEncoder::new(Vec::new(), Compression::default()); + encoder.write_all(json_str.as_bytes()).map_err(S::Error::custom)?; + let compressed_data = encoder.finish().map_err(S::Error::custom)?; + + let encoded_b64 = base64::prelude::BASE64_STANDARD.encode(&compressed_data); + s.serialize_str(&encoded_b64) + } + + pub fn deserialize_compressed_base64_json<'de, D>( + deserializer: D, + ) -> Result + where + D: Deserializer<'de>, + { + let encoded_b64: String = Deserialize::deserialize(deserializer)?; + + let compressed_data = + base64::prelude::BASE64_STANDARD.decode(&encoded_b64).map_err(D::Error::custom)?; + + let mut decoder = DeflateDecoder::new(&compressed_data[..]); + let mut decompressed_data = Vec::new(); + decoder.read_to_end(&mut decompressed_data).map_err(D::Error::custom)?; + + let json_str = String::from_utf8(decompressed_data).map_err(D::Error::custom)?; + serde_json::from_str(&json_str).map_err(D::Error::custom) + } } diff --git a/noir/compiler/wasm/Cargo.toml b/noir/compiler/wasm/Cargo.toml index 7af26269106..a20efeeed8a 100644 --- a/noir/compiler/wasm/Cargo.toml +++ b/noir/compiler/wasm/Cargo.toml @@ -18,6 +18,7 @@ nargo.workspace = true noirc_driver.workspace = true noirc_frontend.workspace = true noirc_errors.workspace = true +noirc_evaluator.workspace = true wasm-bindgen.workspace = true serde.workspace = true js-sys.workspace = true diff --git a/noir/compiler/wasm/package.json b/noir/compiler/wasm/package.json index 4a71d8aa77d..7cdf78b0ffd 100644 --- a/noir/compiler/wasm/package.json +++ b/noir/compiler/wasm/package.json @@ -48,6 +48,7 @@ "@types/mocha": "^10.0.6", "@types/mocha-each": "^2", "@types/node": "^20.10.5", + "@types/pako": "^2", "@types/path-browserify": "^1", "@types/readable-stream": "^4", "@types/sinon": "^17", @@ -75,5 +76,8 @@ "url": "^0.11.3", "webpack": "^5.49.0", "webpack-cli": "^4.7.2" + }, + "dependencies": { + "pako": "^2.1.0" } } diff --git a/noir/compiler/wasm/src/compile.rs b/noir/compiler/wasm/src/compile.rs index 54fdccf1369..c94392adf83 100644 --- a/noir/compiler/wasm/src/compile.rs +++ b/noir/compiler/wasm/src/compile.rs @@ -3,7 +3,6 @@ use gloo_utils::format::JsValueSerdeExt; use js_sys::{JsString, Object}; use nargo::artifacts::{ contract::{ContractArtifact, ContractFunctionArtifact}, - debug::DebugArtifact, program::ProgramArtifact, }; use noirc_driver::{ @@ -11,6 +10,7 @@ use noirc_driver::{ prepare_dependency, CompileOptions, CompiledContract, CompiledProgram, NOIR_ARTIFACT_VERSION_STRING, }; +use noirc_evaluator::errors::SsaReport; use noirc_frontend::{ graph::{CrateId, CrateName}, hir::Context, @@ -28,35 +28,30 @@ export type DependencyGraph = { library_dependencies: Readonly>; } -export type CompiledContract = { +export type ContractArtifact = { noir_version: string; name: string; functions: Array; events: Array; + file_map: Record; }; -export type CompiledProgram = { +export type ProgramArtifact = { noir_version: string; + hash: number; abi: any; bytecode: string; + debug_symbols: any; + file_map: Record; } -export type DebugArtifact = { - debug_symbols: Array; - file_map: Record; - warnings: Array; -}; +type WarningsCompileResult = { warnings: Array; }; -export type CompileResult = ( - | { - contract: CompiledContract; - debug: DebugArtifact; - } - | { - program: CompiledProgram; - debug: DebugArtifact; - } -); +export type ContractCompileResult = { contract: CompiledContract; } & WarningsCompileResult; + +export type ProgramCompileResult = { program: CompiledProgram; } & WarningsCompileResult; + +export type CompileResult = ContractCompileResult | ProgramCompileResult; "#; #[wasm_bindgen] @@ -76,38 +71,36 @@ extern "C" { impl JsCompileResult { const CONTRACT_PROP: &'static str = "contract"; const PROGRAM_PROP: &'static str = "program"; - const DEBUG_PROP: &'static str = "debug"; + const WARNINGS_PROP: &'static str = "warnings"; pub fn new(resp: CompileResult) -> JsCompileResult { let obj = JsCompileResult::constructor(); match resp { - CompileResult::Contract { contract, debug } => { + CompileResult::Contract { contract, warnings } => { js_sys::Reflect::set( &obj, &JsString::from(JsCompileResult::CONTRACT_PROP), &::from_serde(&contract).unwrap(), ) .unwrap(); - js_sys::Reflect::set( &obj, - &JsString::from(JsCompileResult::DEBUG_PROP), - &::from_serde(&debug).unwrap(), + &JsString::from(JsCompileResult::WARNINGS_PROP), + &::from_serde(&warnings).unwrap(), ) .unwrap(); } - CompileResult::Program { program, debug } => { + CompileResult::Program { program, warnings } => { js_sys::Reflect::set( &obj, &JsString::from(JsCompileResult::PROGRAM_PROP), &::from_serde(&program).unwrap(), ) .unwrap(); - js_sys::Reflect::set( &obj, - &JsString::from(JsCompileResult::DEBUG_PROP), - &::from_serde(&debug).unwrap(), + &JsString::from(JsCompileResult::WARNINGS_PROP), + &::from_serde(&warnings).unwrap(), ) .unwrap(); } @@ -148,8 +141,8 @@ impl PathToFileSourceMap { } pub enum CompileResult { - Contract { contract: ContractArtifact, debug: DebugArtifact }, - Program { program: ProgramArtifact, debug: DebugArtifact }, + Contract { contract: ContractArtifact, warnings: Vec }, + Program { program: ProgramArtifact, warnings: Vec }, } #[wasm_bindgen] @@ -273,31 +266,22 @@ fn add_noir_lib(context: &mut Context, library_name: &CrateName) -> CrateId { } pub(crate) fn generate_program_artifact(program: CompiledProgram) -> CompileResult { - let debug_artifact = DebugArtifact { - debug_symbols: vec![program.debug.clone()], - file_map: program.file_map.clone(), - warnings: program.warnings.clone(), - }; - - CompileResult::Program { program: program.into(), debug: debug_artifact } + let warnings = program.warnings.clone(); + CompileResult::Program { program: program.into(), warnings } } pub(crate) fn generate_contract_artifact(contract: CompiledContract) -> CompileResult { - let debug_artifact = DebugArtifact { - debug_symbols: contract.functions.iter().map(|function| function.debug.clone()).collect(), - file_map: contract.file_map, - warnings: contract.warnings, - }; let functions = contract.functions.into_iter().map(ContractFunctionArtifact::from).collect(); - + let contract_artifact = ContractArtifact { noir_version: String::from(NOIR_ARTIFACT_VERSION_STRING), name: contract.name, functions, events: contract.events, + file_map: contract.file_map, }; - CompileResult::Contract { contract: contract_artifact, debug: debug_artifact } + CompileResult::Contract { contract: contract_artifact, warnings: contract.warnings } } #[cfg(test)] diff --git a/noir/compiler/wasm/src/types/noir_artifact.ts b/noir/compiler/wasm/src/types/noir_artifact.ts index f2147cfbeda..4b9e4b1b79c 100644 --- a/noir/compiler/wasm/src/types/noir_artifact.ts +++ b/noir/compiler/wasm/src/types/noir_artifact.ts @@ -49,6 +49,8 @@ export interface NoirFunctionEntry { abi: Abi; /** The bytecode of the function in base64. */ bytecode: string; + /** The debug information, compressed and base64 encoded. */ + debug_symbols: string; } /** @@ -57,12 +59,16 @@ export interface NoirFunctionEntry { export interface CompiledContract { /** The name of the contract. */ name: string; + /** Version of noir used for the build. */ + noir_version: string; /** Compilation backend. */ backend: string; /** The functions of the contract. */ functions: NoirFunctionEntry[]; /** The events of the contract */ events: EventAbi[]; + /** The map of file ID to the source code and path of the file. */ + file_map: DebugFileMap; } /** @@ -73,12 +79,14 @@ export interface CompiledCircuit { hash?: number; /** Compilation backend. */ backend: string; - /** - * The ABI of the function. - */ + /** * The ABI of the function. */ abi: Abi; /** The bytecode of the circuit in base64. */ bytecode: string; + /** The debug information, compressed and base64 encoded. */ + debug_symbols: string; + /** The map of file ID to the source code and path of the file. */ + file_map: DebugFileMap; } /** @@ -142,19 +150,8 @@ export type DebugFileMap = Record< } >; -/** - * The debug metadata of an Noir contract. - */ -export interface DebugMetadata { - /** - * The debug information for each function. - */ - debug_symbols: DebugInfo[]; - /** - * The map of file ID to the source code and path of the file. - */ - file_map: DebugFileMap; -} +/** Compilation warning */ +export type Warning = unknown; /** * The compilation artifacts of a given contract. @@ -165,10 +162,8 @@ export interface ContractCompilationArtifacts { */ contract: CompiledContract; - /** - * The artifact that contains the debug metadata about the contract. - */ - debug?: DebugMetadata; + /** Compilation warnings. */ + warnings: Warning[]; } /** @@ -184,10 +179,8 @@ export interface ProgramCompilationArtifacts { */ program: CompiledCircuit; - /** - * The artifact that contains the debug metadata about the contract. - */ - debug?: DebugMetadata; + /** Compilation warnings. */ + warnings: Warning[]; } /** diff --git a/noir/compiler/wasm/test/compiler/node/compile_with_deps.test.ts b/noir/compiler/wasm/test/compiler/node/compile_with_deps.test.ts index 546ec03c183..4b2a27294b1 100644 --- a/noir/compiler/wasm/test/compiler/node/compile_with_deps.test.ts +++ b/noir/compiler/wasm/test/compiler/node/compile_with_deps.test.ts @@ -1,10 +1,12 @@ import { join, resolve } from 'path'; import { getPaths } from '../../shared'; +import { inflate } from 'pako'; import { expect } from 'chai'; import { readFile } from 'fs/promises'; import { compile, createFileManager } from '@noir-lang/noir_wasm'; -import { CompiledContract } from '../../../src/types/noir_artifact'; +import { CompiledContract, DebugFileMap, DebugInfo } from '../../../src/types/noir_artifact'; +import { ContractCompilationArtifacts, NoirFunctionEntry } from 'dist/types/src/types/noir_artifact'; const basePath = resolve(join(__dirname, '../../')); const { contractProjectPath, contractExpectedArtifact } = getPaths(basePath); @@ -13,14 +15,68 @@ describe('noir-compiler', () => { it('both nargo and noir_wasm should compile identically', async () => { const fm = createFileManager(contractProjectPath); const nargoArtifact = JSON.parse((await readFile(contractExpectedArtifact)).toString()) as CompiledContract; - nargoArtifact.functions.sort((a, b) => a.name.localeCompare(b.name)); + const [nargoDebugInfos, nargoFileMap] = deleteDebugMetadata(nargoArtifact); + normalizeVersion(nargoArtifact); + const noirWasmArtifact = await compile(fm); - if (!('contract' in noirWasmArtifact)) { - throw new Error('Compilation failed'); - } - const noirWasmContract = noirWasmArtifact.contract; + const noirWasmContract = (noirWasmArtifact as ContractCompilationArtifacts).contract; expect(noirWasmContract).not.to.be.undefined; - noirWasmContract.functions.sort((a, b) => a.name.localeCompare(b.name)); + const [noirWasmDebugInfos, norWasmFileMap] = deleteDebugMetadata(noirWasmContract); + normalizeVersion(noirWasmContract); + + // We first compare both contracts without considering debug info expect(nargoArtifact).to.deep.eq(noirWasmContract); - }); + + // Compare the file maps, ignoring keys, since those depend in the order in which files are visited, + // which may change depending on the file manager implementation. Also ignores paths, since the base + // path is reported differently between nargo and noir-wasm. + expect(getSources(nargoFileMap)).to.have.members(getSources(norWasmFileMap)); + + // Compare the debug symbol information, ignoring the actual ids used for file identifiers. + // Debug symbol info looks like the following, what we need is to ignore the 'file' identifiers + // {"locations":{"0":[{"span":{"start":141,"end":156},"file":39},{"span":{"start":38,"end":76},"file":38},{"span":{"start":824,"end":862},"file":23}]}} + expect(nargoDebugInfos).to.deep.eq(noirWasmDebugInfos); + }).timeout(5000); }); + +/** Remove commit identifier from version, which may not match depending on cached nargo and noir-wasm */ +function normalizeVersion(contract: CompiledContract) { + contract.noir_version = contract.noir_version.replace(/\+.+$/, ''); +} + +/** Decompresses and decodes the debug symbols */ +function inflateDebugSymbols(debugSymbols: string) { + return JSON.parse(inflate(Buffer.from(debugSymbols, 'base64'), { to: 'string', raw: true })); +} + +/** Extracts the debug symbols from all functions, decodes them, removes their file identifiers, and deletes them from the artifact. */ +function extractDebugInfos(fns: NoirFunctionEntry[]) { + return fns.map((fn) => { + const debugSymbols = inflateDebugSymbols(fn.debug_symbols); + delete (fn as Partial).debug_symbols; + clearFileIdentifiers(debugSymbols); + return debugSymbols; + }); +} + +/** Deletes all debug info from a contract and returns it. */ +function deleteDebugMetadata(contract: CompiledContract) { + contract.functions.sort((a, b) => a.name.localeCompare(b.name)); + const fileMap = contract.file_map; + delete (contract as Partial).file_map; + return [extractDebugInfos(contract.functions), fileMap]; +} + +/** Clears file identifiers from a set of debug symbols. */ +function clearFileIdentifiers(debugSymbols: DebugInfo) { + for (const loc of Object.values(debugSymbols.locations)) { + for (const span of loc) { + span.file = 0; + } + } +} + +/** Returns list of sources from file map, dropping paths along the way, since they don't match depending on the file manager. */ +function getSources(fileMap: DebugFileMap) { + return Object.values(fileMap).map((file) => file.source); +} diff --git a/noir/tooling/nargo/src/artifacts/contract.rs b/noir/tooling/nargo/src/artifacts/contract.rs index 04699126762..d928b09fcb9 100644 --- a/noir/tooling/nargo/src/artifacts/contract.rs +++ b/noir/tooling/nargo/src/artifacts/contract.rs @@ -1,8 +1,14 @@ use acvm::acir::circuit::Circuit; use noirc_abi::{Abi, ContractEvent}; -use noirc_driver::{ContractFunction, ContractFunctionType}; +use noirc_driver::{CompiledContract, ContractFunction, ContractFunctionType}; use serde::{Deserialize, Serialize}; +use noirc_driver::DebugFile; +use noirc_errors::debug_info::DebugInfo; +use std::collections::BTreeMap; + +use fm::FileId; + #[derive(Serialize, Deserialize)] pub struct ContractArtifact { /// Version of noir used to compile this contract @@ -13,6 +19,20 @@ pub struct ContractArtifact { pub functions: Vec, /// All the events defined inside the contract scope. pub events: Vec, + /// Map of file Id to the source code so locations in debug info can be mapped to source code they point to. + pub file_map: BTreeMap, +} + +impl From for ContractArtifact { + fn from(contract: CompiledContract) -> Self { + ContractArtifact { + noir_version: contract.noir_version, + name: contract.name, + functions: contract.functions.into_iter().map(ContractFunctionArtifact::from).collect(), + events: contract.events, + file_map: contract.file_map, + } + } } /// Each function in the contract will be compiled as a separate noir program. @@ -34,6 +54,12 @@ pub struct ContractFunctionArtifact { deserialize_with = "Circuit::deserialize_circuit_base64" )] pub bytecode: Circuit, + + #[serde( + serialize_with = "DebugInfo::serialize_compressed_base64_json", + deserialize_with = "DebugInfo::deserialize_compressed_base64_json" + )] + pub debug_symbols: DebugInfo, } impl From for ContractFunctionArtifact { @@ -44,6 +70,7 @@ impl From for ContractFunctionArtifact { is_internal: func.is_internal, abi: func.abi, bytecode: func.bytecode, + debug_symbols: func.debug, } } } diff --git a/noir/tooling/nargo/src/artifacts/program.rs b/noir/tooling/nargo/src/artifacts/program.rs index 96e63e6fe50..b1db5f31728 100644 --- a/noir/tooling/nargo/src/artifacts/program.rs +++ b/noir/tooling/nargo/src/artifacts/program.rs @@ -1,6 +1,11 @@ +use std::collections::BTreeMap; + use acvm::acir::circuit::Circuit; +use fm::FileId; use noirc_abi::Abi; use noirc_driver::CompiledProgram; +use noirc_driver::DebugFile; +use noirc_errors::debug_info::DebugInfo; use serde::{Deserialize, Serialize}; #[derive(Serialize, Deserialize, Debug)] @@ -20,6 +25,15 @@ pub struct ProgramArtifact { deserialize_with = "Circuit::deserialize_circuit_base64" )] pub bytecode: Circuit, + + #[serde( + serialize_with = "DebugInfo::serialize_compressed_base64_json", + deserialize_with = "DebugInfo::deserialize_compressed_base64_json" + )] + pub debug_symbols: DebugInfo, + + /// Map of file Id to the source code so locations in debug info can be mapped to source code they point to. + pub file_map: BTreeMap, } impl From for ProgramArtifact { @@ -29,6 +43,22 @@ impl From for ProgramArtifact { abi: program.abi, noir_version: program.noir_version, bytecode: program.circuit, + debug_symbols: program.debug, + file_map: program.file_map, + } + } +} + +impl Into for ProgramArtifact { + fn into(self) -> CompiledProgram { + CompiledProgram { + hash: self.hash, + abi: self.abi, + noir_version: self.noir_version, + circuit: self.bytecode, + debug: self.debug_symbols, + file_map: self.file_map, + warnings: vec![], } } } diff --git a/noir/tooling/nargo_cli/src/cli/compile_cmd.rs b/noir/tooling/nargo_cli/src/cli/compile_cmd.rs index 31105ebe68f..924116861f4 100644 --- a/noir/tooling/nargo_cli/src/cli/compile_cmd.rs +++ b/noir/tooling/nargo_cli/src/cli/compile_cmd.rs @@ -1,10 +1,8 @@ use std::path::Path; use acvm::ExpressionWidth; + use fm::FileManager; -use iter_extended::vecmap; -use nargo::artifacts::contract::{ContractArtifact, ContractFunctionArtifact}; -use nargo::artifacts::debug::DebugArtifact; use nargo::artifacts::program::ProgramArtifact; use nargo::errors::CompileError; use nargo::insert_all_files_for_workspace_into_file_manager; @@ -15,6 +13,7 @@ use nargo_toml::{get_package_manifest, resolve_workspace_from_toml, PackageSelec use noirc_driver::file_manager_with_stdlib; use noirc_driver::NOIR_ARTIFACT_VERSION_STRING; use noirc_driver::{CompilationResult, CompileOptions, CompiledContract, CompiledProgram}; + use noirc_frontend::graph::CrateName; use clap::Args; @@ -23,10 +22,7 @@ use crate::backends::Backend; use crate::errors::CliError; use super::fs::program::only_acir; -use super::fs::program::{ - read_debug_artifact_from_file, read_program_from_file, save_contract_to_file, - save_debug_artifact_to_file, save_program_to_file, -}; +use super::fs::program::{read_program_from_file, save_contract_to_file, save_program_to_file}; use super::NargoConfig; use rayon::prelude::*; @@ -170,24 +166,8 @@ fn compile_program( let (mut context, crate_id) = prepare_package(file_manager, package); let program_artifact_path = workspace.package_build_path(package); - let mut debug_artifact_path = program_artifact_path.clone(); - debug_artifact_path.set_file_name(format!("debug_{}.json", package.name)); - let cached_program = if let (Ok(program_artifact), Ok(mut debug_artifact)) = ( - read_program_from_file(program_artifact_path), - read_debug_artifact_from_file(debug_artifact_path), - ) { - Some(CompiledProgram { - hash: program_artifact.hash, - circuit: program_artifact.bytecode, - abi: program_artifact.abi, - noir_version: program_artifact.noir_version, - debug: debug_artifact.debug_symbols.remove(0), - file_map: debug_artifact.file_map, - warnings: debug_artifact.warnings, - }) - } else { - None - }; + let cached_program: Option = + read_program_from_file(program_artifact_path).map(|p| p.into()).ok(); let force_recompile = cached_program.as_ref().map_or(false, |p| p.noir_version != NOIR_ARTIFACT_VERSION_STRING); @@ -244,51 +224,13 @@ pub(super) fn save_program( } else { save_program_to_file(&program_artifact, &package.name, circuit_dir); } - - let debug_artifact = DebugArtifact { - debug_symbols: vec![program.debug], - file_map: program.file_map, - warnings: program.warnings, - }; - let circuit_name: String = (&package.name).into(); - save_debug_artifact_to_file(&debug_artifact, &circuit_name, circuit_dir); } fn save_contract(contract: CompiledContract, package: &Package, circuit_dir: &Path) { - // TODO(#1389): I wonder if it is incorrect for nargo-core to know anything about contracts. - // As can be seen here, It seems like a leaky abstraction where ContractFunctions (essentially CompiledPrograms) - // are compiled via nargo-core and then the ContractArtifact is constructed here. - // This is due to EACH function needing it's own CRS, PKey, and VKey from the backend. - let debug_artifact = DebugArtifact { - debug_symbols: contract.functions.iter().map(|function| function.debug.clone()).collect(), - file_map: contract.file_map, - warnings: contract.warnings, - }; - - let functions = vecmap(contract.functions, |func| ContractFunctionArtifact { - name: func.name, - function_type: func.function_type, - is_internal: func.is_internal, - abi: func.abi, - bytecode: func.bytecode, - }); - - let contract_artifact = ContractArtifact { - noir_version: contract.noir_version, - name: contract.name, - functions, - events: contract.events, - }; - + let contract_name = contract.name.clone(); save_contract_to_file( - &contract_artifact, - &format!("{}-{}", package.name, contract_artifact.name), - circuit_dir, - ); - - save_debug_artifact_to_file( - &debug_artifact, - &format!("{}-{}", package.name, contract_artifact.name), + &contract.into(), + &format!("{}-{}", package.name, contract_name), circuit_dir, ); } diff --git a/noir/tooling/nargo_cli/src/cli/fs/program.rs b/noir/tooling/nargo_cli/src/cli/fs/program.rs index 1d2f012736e..1fb57ae6685 100644 --- a/noir/tooling/nargo_cli/src/cli/fs/program.rs +++ b/noir/tooling/nargo_cli/src/cli/fs/program.rs @@ -1,9 +1,7 @@ use std::path::{Path, PathBuf}; use acvm::acir::circuit::Circuit; -use nargo::artifacts::{ - contract::ContractArtifact, debug::DebugArtifact, program::ProgramArtifact, -}; +use nargo::artifacts::{contract::ContractArtifact, program::ProgramArtifact}; use noirc_frontend::graph::CrateName; use crate::errors::FilesystemError; @@ -40,15 +38,6 @@ pub(crate) fn save_contract_to_file>( save_build_artifact_to_file(compiled_contract, circuit_name, circuit_dir) } -pub(crate) fn save_debug_artifact_to_file>( - debug_artifact: &DebugArtifact, - circuit_name: &str, - circuit_dir: P, -) -> PathBuf { - let artifact_name = format!("debug_{circuit_name}"); - save_build_artifact_to_file(debug_artifact, &artifact_name, circuit_dir) -} - fn save_build_artifact_to_file, T: ?Sized + serde::Serialize>( build_artifact: &T, artifact_name: &str, @@ -74,14 +63,3 @@ pub(crate) fn read_program_from_file>( Ok(program) } - -pub(crate) fn read_debug_artifact_from_file>( - debug_artifact_path: P, -) -> Result { - let input_string = std::fs::read(&debug_artifact_path) - .map_err(|_| FilesystemError::PathNotValid(debug_artifact_path.as_ref().into()))?; - let program = serde_json::from_slice(&input_string) - .map_err(|err| FilesystemError::ProgramSerializationError(err.to_string()))?; - - Ok(program) -} diff --git a/noir/yarn.lock b/noir/yarn.lock index f4e0ce7df36..7ec790dc23c 100644 --- a/noir/yarn.lock +++ b/noir/yarn.lock @@ -4530,6 +4530,7 @@ __metadata: "@types/mocha": ^10.0.6 "@types/mocha-each": ^2 "@types/node": ^20.10.5 + "@types/pako": ^2 "@types/path-browserify": ^1 "@types/readable-stream": ^4 "@types/sinon": ^17 @@ -4546,6 +4547,7 @@ __metadata: memfs: ^4.6.0 mocha: ^10.2.0 mocha-each: ^2.0.1 + pako: ^2.1.0 path-browserify: ^1.0.1 process: ^0.11.10 readable-stream: ^4.4.2 @@ -6197,6 +6199,13 @@ __metadata: languageName: node linkType: hard +"@types/pako@npm:^2": + version: 2.0.3 + resolution: "@types/pako@npm:2.0.3" + checksum: 0746dd5d29eccf5b2e6cceb3ccb093851219e78bd2e2e20d25757e247987139e061e5d4ba37cb5295493f06e3c683c74f8876011cd8a3f3748a09244fbc841d9 + languageName: node + linkType: hard + "@types/parse-json@npm:^4.0.0": version: 4.0.2 resolution: "@types/parse-json@npm:4.0.2" @@ -17099,6 +17108,13 @@ __metadata: languageName: node linkType: hard +"pako@npm:^2.1.0": + version: 2.1.0 + resolution: "pako@npm:2.1.0" + checksum: 71666548644c9a4d056bcaba849ca6fd7242c6cf1af0646d3346f3079a1c7f4a66ffec6f7369ee0dc88f61926c10d6ab05da3e1fca44b83551839e89edd75a3e + languageName: node + linkType: hard + "param-case@npm:^3.0.4": version: 3.0.4 resolution: "param-case@npm:3.0.4" From 2914c3f20d4f5725e6a7f9bc18712449210d7911 Mon Sep 17 00:00:00 2001 From: Santiago Palladino Date: Mon, 15 Jan 2024 11:28:54 -0300 Subject: [PATCH 02/16] Update yarn-project --- yarn-project/accounts/package.json | 2 +- yarn-project/accounts/package.local.json | 2 +- .../accounts/scripts/copy-contracts.sh | 9 + yarn-project/accounts/src/ecdsa/artifact.ts | 4 +- yarn-project/accounts/src/schnorr/artifact.ts | 4 +- .../accounts/src/single_key/artifact.ts | 6 +- .../acir-simulator/src/client/db_oracle.ts | 12 +- .../src/client/private_execution.test.ts | 10 +- .../src/client/private_execution.ts | 3 +- .../src/client/simulator.test.ts | 5 +- .../acir-simulator/src/client/simulator.ts | 10 +- .../src/client/unconstrained_execution.ts | 3 +- yarn-project/acir-simulator/src/test/utils.ts | 31 --- yarn-project/aztec.js/package.json | 3 +- yarn-project/aztec.js/package.local.json | 2 +- yarn-project/aztec.js/src/api/abi.ts | 2 + .../aztec.js/src/contract/contract.test.ts | 4 + .../contract_deployer.test.ts | 2 + yarn-project/aztec.js/src/index.ts | 4 +- .../circuit-types/src/contract_dao.test.ts | 2 + .../circuit-types/src/contract_dao.ts | 9 +- yarn-project/circuit-types/src/mocks.ts | 1 + yarn-project/cli/src/test/mocks.ts | 3 + yarn-project/end-to-end/tsconfig.web.json | 2 +- yarn-project/foundation/src/abi/abi.ts | 81 +++++--- yarn-project/foundation/src/abi/selector.ts | 15 +- yarn-project/noir-compiler/package.json | 1 + .../add_noir_compiler_commander_actions.ts | 5 +- yarn-project/noir-compiler/src/cli/codegen.ts | 50 ++--- .../src/contract-interface-gen/abi.ts | 120 ----------- .../programTypescript.ts | 189 ------------------ .../{contractTypescript.ts => typescript.ts} | 4 +- yarn-project/noir-compiler/src/index.ts | 6 +- yarn-project/noir-compiler/tsconfig.json | 3 + yarn-project/noir-contracts/bootstrap.sh | 3 - yarn-project/noir-contracts/package.json | 4 +- .../noir-contracts/scripts/compile.sh | 2 +- .../noir-contracts/scripts/generate-types.sh | 7 +- .../scripts/transform_json_abi.sh | 22 -- yarn-project/noir-contracts/tsconfig.json | 8 +- .../noir-protocol-circuits/package.json | 5 +- .../noir-protocol-circuits/src/index.ts | 2 +- .../src/scripts/generate_ts_from_abi.ts | 2 +- .../noir-protocol-circuits/tsconfig.json | 3 + .../pxe/src/simulator_oracle/index.ts | 3 +- yarn-project/types/.eslintrc.cjs | 2 +- yarn-project/types/package.json | 4 +- .../types/src/abi/contract_artifact.ts | 130 ++++++++++++ yarn-project/types/src/abi/index.ts | 1 + yarn-project/types/src/abi/mocked_keys.ts | 2 + .../src/noir/index.ts} | 64 ++---- yarn-project/yarn.lock | 2 + 52 files changed, 339 insertions(+), 536 deletions(-) create mode 100755 yarn-project/accounts/scripts/copy-contracts.sh delete mode 100644 yarn-project/noir-compiler/src/contract-interface-gen/abi.ts delete mode 100644 yarn-project/noir-compiler/src/contract-interface-gen/programTypescript.ts rename yarn-project/noir-compiler/src/contract-interface-gen/{contractTypescript.ts => typescript.ts} (97%) delete mode 100755 yarn-project/noir-contracts/bootstrap.sh delete mode 100755 yarn-project/noir-contracts/scripts/transform_json_abi.sh create mode 100644 yarn-project/types/src/abi/contract_artifact.ts create mode 100644 yarn-project/types/src/abi/index.ts create mode 100644 yarn-project/types/src/abi/mocked_keys.ts rename yarn-project/{noir-compiler/src/noir_artifact.ts => types/src/noir/index.ts} (77%) diff --git a/yarn-project/accounts/package.json b/yarn-project/accounts/package.json index 2a59abcc1b3..e9c63424550 100644 --- a/yarn-project/accounts/package.json +++ b/yarn-project/accounts/package.json @@ -24,7 +24,7 @@ }, "scripts": { "build": "yarn clean && yarn build:copy-contracts && tsc -b", - "build:copy-contracts": "mkdir -p ./src/artifacts && cp ../noir-contracts/src/SchnorrAccount.json ../noir-contracts/src/EcdsaAccount.json ../noir-contracts/src/SchnorrSingleKeyAccount.json ./src/artifacts", + "build:copy-contracts": "./scripts/copy-contracts.sh", "build:dev": "tsc -b --watch", "build:ts": "tsc -b", "clean": "rm -rf ./dest .tsbuildinfo ./src/artifacts", diff --git a/yarn-project/accounts/package.local.json b/yarn-project/accounts/package.local.json index e502a0f74d0..def45a001a2 100644 --- a/yarn-project/accounts/package.local.json +++ b/yarn-project/accounts/package.local.json @@ -1,7 +1,7 @@ { "scripts": { "build": "yarn clean && yarn build:copy-contracts && tsc -b", - "build:copy-contracts": "mkdir -p ./src/artifacts && cp ../noir-contracts/src/SchnorrAccount.json ../noir-contracts/src/EcdsaAccount.json ../noir-contracts/src/SchnorrSingleKeyAccount.json ./src/artifacts", + "build:copy-contracts": "./scripts/copy-contracts.sh", "build:dev": "tsc -b --watch", "build:ts": "tsc -b", "clean": "rm -rf ./dest .tsbuildinfo ./src/artifacts" diff --git a/yarn-project/accounts/scripts/copy-contracts.sh b/yarn-project/accounts/scripts/copy-contracts.sh new file mode 100755 index 00000000000..8c6b0e75332 --- /dev/null +++ b/yarn-project/accounts/scripts/copy-contracts.sh @@ -0,0 +1,9 @@ +#! /bin/bash +set -euo pipefail +mkdir -p ./src/artifacts + +contracts=(schnorr_account_contract-SchnorrAccount ecdsa_account_contract-EcdsaAccount schnorr_single_key_account_contract-SchnorrSingleKeyAccount) + +for contract in "${contracts[@]}"; do + cp "../noir-contracts/target/$contract.json" ./src/artifacts/${contract#*-}.json +done diff --git a/yarn-project/accounts/src/ecdsa/artifact.ts b/yarn-project/accounts/src/ecdsa/artifact.ts index 05c0aae17c9..4dd2fd60dd6 100644 --- a/yarn-project/accounts/src/ecdsa/artifact.ts +++ b/yarn-project/accounts/src/ecdsa/artifact.ts @@ -1,5 +1,5 @@ -import { ContractArtifact } from '@aztec/aztec.js'; +import { NoirCompiledContract, loadContractArtifact } from '@aztec/aztec.js'; import EcdsaAccountContractJson from '../artifacts/EcdsaAccount.json' assert { type: 'json' }; -export const EcdsaAccountContractArtifact = EcdsaAccountContractJson as ContractArtifact; +export const EcdsaAccountContractArtifact = loadContractArtifact(EcdsaAccountContractJson as NoirCompiledContract); diff --git a/yarn-project/accounts/src/schnorr/artifact.ts b/yarn-project/accounts/src/schnorr/artifact.ts index 672b633420e..1d9088bf3ca 100644 --- a/yarn-project/accounts/src/schnorr/artifact.ts +++ b/yarn-project/accounts/src/schnorr/artifact.ts @@ -1,5 +1,5 @@ -import { ContractArtifact } from '@aztec/aztec.js'; +import { NoirCompiledContract, loadContractArtifact } from '@aztec/aztec.js'; import SchnorrAccountContractJson from '../artifacts/SchnorrAccount.json' assert { type: 'json' }; -export const SchnorrAccountContractArtifact = SchnorrAccountContractJson as ContractArtifact; +export const SchnorrAccountContractArtifact = loadContractArtifact(SchnorrAccountContractJson as NoirCompiledContract); diff --git a/yarn-project/accounts/src/single_key/artifact.ts b/yarn-project/accounts/src/single_key/artifact.ts index 4bb139b1252..954c5f199e7 100644 --- a/yarn-project/accounts/src/single_key/artifact.ts +++ b/yarn-project/accounts/src/single_key/artifact.ts @@ -1,5 +1,7 @@ -import { ContractArtifact } from '@aztec/aztec.js'; +import { NoirCompiledContract, loadContractArtifact } from '@aztec/aztec.js'; import SchnorrSingleKeyAccountContractJson from '../artifacts/SchnorrSingleKeyAccount.json' assert { type: 'json' }; -export const SchnorrSingleKeyAccountContractArtifact = SchnorrSingleKeyAccountContractJson as ContractArtifact; +export const SchnorrSingleKeyAccountContractArtifact = loadContractArtifact( + SchnorrSingleKeyAccountContractJson as NoirCompiledContract, +); diff --git a/yarn-project/acir-simulator/src/client/db_oracle.ts b/yarn-project/acir-simulator/src/client/db_oracle.ts index 560c5923ecd..eb4f59fae84 100644 --- a/yarn-project/acir-simulator/src/client/db_oracle.ts +++ b/yarn-project/acir-simulator/src/client/db_oracle.ts @@ -1,6 +1,6 @@ import { L2Block, MerkleTreeId, NullifierMembershipWitness, PublicDataWitness } from '@aztec/circuit-types'; import { BlockHeader, CompleteAddress, GrumpkinPrivateKey, PublicKey } from '@aztec/circuits.js'; -import { FunctionArtifact, FunctionDebugMetadata, FunctionSelector } from '@aztec/foundation/abi'; +import { FunctionArtifactWithDebugMetadata, FunctionSelector } from '@aztec/foundation/abi'; import { AztecAddress } from '@aztec/foundation/aztec-address'; import { EthAddress } from '@aztec/foundation/eth-address'; import { Fr } from '@aztec/foundation/fields'; @@ -17,16 +17,6 @@ export class ContractNotFoundError extends Error { } } -/** - * A function artifact with optional debug metadata - */ -export interface FunctionArtifactWithDebugMetadata extends FunctionArtifact { - /** - * Debug metadata for the function. - */ - debug?: FunctionDebugMetadata; -} - /** * The database oracle interface. */ diff --git a/yarn-project/acir-simulator/src/client/private_execution.test.ts b/yarn-project/acir-simulator/src/client/private_execution.test.ts index cadb2afec9f..574e4b7b521 100644 --- a/yarn-project/acir-simulator/src/client/private_execution.test.ts +++ b/yarn-project/acir-simulator/src/client/private_execution.test.ts @@ -21,7 +21,13 @@ import { siloCommitment, } from '@aztec/circuits.js/abis'; import { makeContractDeploymentData } from '@aztec/circuits.js/factories'; -import { FunctionArtifact, FunctionSelector, encodeArguments } from '@aztec/foundation/abi'; +import { + FunctionArtifact, + FunctionSelector, + encodeArguments, + getFunctionArtifact, + getFunctionArtifactWithSelector, +} from '@aztec/foundation/abi'; import { asyncMap } from '@aztec/foundation/async-map'; import { AztecAddress } from '@aztec/foundation/aztec-address'; import { pedersenHash } from '@aztec/foundation/crypto'; @@ -46,7 +52,7 @@ import { default as levelup } from 'levelup'; import { type MemDown, default as memdown } from 'memdown'; import { getFunctionSelector } from 'viem'; -import { buildL1ToL2Message, getFunctionArtifact, getFunctionArtifactWithSelector } from '../test/utils.js'; +import { buildL1ToL2Message } from '../test/utils.js'; import { computeSlotForMapping } from '../utils.js'; import { DBOracle } from './db_oracle.js'; import { AcirSimulator } from './simulator.js'; diff --git a/yarn-project/acir-simulator/src/client/private_execution.ts b/yarn-project/acir-simulator/src/client/private_execution.ts index d2d43ca534d..c16fcd83b34 100644 --- a/yarn-project/acir-simulator/src/client/private_execution.ts +++ b/yarn-project/acir-simulator/src/client/private_execution.ts @@ -1,5 +1,5 @@ import { FunctionData, PrivateCallStackItem } from '@aztec/circuits.js'; -import { decodeReturnValues } from '@aztec/foundation/abi'; +import { FunctionArtifactWithDebugMetadata, decodeReturnValues } from '@aztec/foundation/abi'; import { AztecAddress } from '@aztec/foundation/aztec-address'; import { Fr } from '@aztec/foundation/fields'; import { createDebugLogger } from '@aztec/foundation/log'; @@ -9,7 +9,6 @@ import { extractPrivateCircuitPublicInputs } from '../acvm/deserialize.js'; import { Oracle, acvm, extractCallStack } from '../acvm/index.js'; import { ExecutionError } from '../common/errors.js'; import { ClientExecutionContext } from './client_execution_context.js'; -import { FunctionArtifactWithDebugMetadata } from './db_oracle.js'; import { ExecutionResult } from './execution_result.js'; import { AcirSimulator } from './simulator.js'; diff --git a/yarn-project/acir-simulator/src/client/simulator.test.ts b/yarn-project/acir-simulator/src/client/simulator.test.ts index 406a1292461..b1e0d95a4bc 100644 --- a/yarn-project/acir-simulator/src/client/simulator.test.ts +++ b/yarn-project/acir-simulator/src/client/simulator.test.ts @@ -1,7 +1,7 @@ import { Note } from '@aztec/circuit-types'; import { CompleteAddress } from '@aztec/circuits.js'; import { computeUniqueCommitment, siloCommitment } from '@aztec/circuits.js/abis'; -import { ABIParameterVisibility } from '@aztec/foundation/abi'; +import { ABIParameterVisibility, FunctionArtifactWithDebugMetadata, getFunctionArtifact } from '@aztec/foundation/abi'; import { AztecAddress } from '@aztec/foundation/aztec-address'; import { pedersenHash } from '@aztec/foundation/crypto'; import { Fr, GrumpkinScalar } from '@aztec/foundation/fields'; @@ -9,8 +9,7 @@ import { TokenContractArtifact } from '@aztec/noir-contracts/Token'; import { MockProxy, mock } from 'jest-mock-extended'; -import { getFunctionArtifact } from '../test/utils.js'; -import { DBOracle, FunctionArtifactWithDebugMetadata } from './db_oracle.js'; +import { DBOracle } from './db_oracle.js'; import { AcirSimulator } from './simulator.js'; describe('Simulator', () => { diff --git a/yarn-project/acir-simulator/src/client/simulator.ts b/yarn-project/acir-simulator/src/client/simulator.ts index 0e11e43509d..92430a19969 100644 --- a/yarn-project/acir-simulator/src/client/simulator.ts +++ b/yarn-project/acir-simulator/src/client/simulator.ts @@ -1,7 +1,13 @@ import { AztecNode, FunctionCall, Note, TxExecutionRequest } from '@aztec/circuit-types'; import { CallContext, FunctionData } from '@aztec/circuits.js'; import { Grumpkin } from '@aztec/circuits.js/barretenberg'; -import { ArrayType, FunctionSelector, FunctionType, encodeArguments } from '@aztec/foundation/abi'; +import { + ArrayType, + FunctionArtifactWithDebugMetadata, + FunctionSelector, + FunctionType, + encodeArguments, +} from '@aztec/foundation/abi'; import { AztecAddress } from '@aztec/foundation/aztec-address'; import { EthAddress } from '@aztec/foundation/eth-address'; import { Fr } from '@aztec/foundation/fields'; @@ -12,7 +18,7 @@ import { WasmBlackBoxFunctionSolver, createBlackBoxSolver } from '@noir-lang/acv import { createSimulationError } from '../common/errors.js'; import { PackedArgsCache } from '../common/packed_args_cache.js'; import { ClientExecutionContext } from './client_execution_context.js'; -import { DBOracle, FunctionArtifactWithDebugMetadata } from './db_oracle.js'; +import { DBOracle } from './db_oracle.js'; import { ExecutionNoteCache } from './execution_note_cache.js'; import { ExecutionResult } from './execution_result.js'; import { executePrivateFunction } from './private_execution.js'; diff --git a/yarn-project/acir-simulator/src/client/unconstrained_execution.ts b/yarn-project/acir-simulator/src/client/unconstrained_execution.ts index d197ec386fb..71730b411fa 100644 --- a/yarn-project/acir-simulator/src/client/unconstrained_execution.ts +++ b/yarn-project/acir-simulator/src/client/unconstrained_execution.ts @@ -1,5 +1,5 @@ import { FunctionData } from '@aztec/circuits.js'; -import { DecodedReturn, decodeReturnValues } from '@aztec/foundation/abi'; +import { DecodedReturn, FunctionArtifactWithDebugMetadata, decodeReturnValues } from '@aztec/foundation/abi'; import { AztecAddress } from '@aztec/foundation/aztec-address'; import { Fr } from '@aztec/foundation/fields'; import { createDebugLogger } from '@aztec/foundation/log'; @@ -8,7 +8,6 @@ import { extractReturnWitness } from '../acvm/deserialize.js'; import { ACVMField, Oracle, acvm, extractCallStack, fromACVMField, toACVMWitness } from '../acvm/index.js'; import { ExecutionError } from '../common/errors.js'; import { AcirSimulator } from '../index.js'; -import { FunctionArtifactWithDebugMetadata } from './db_oracle.js'; import { ViewDataOracle } from './view_data_oracle.js'; /** diff --git a/yarn-project/acir-simulator/src/test/utils.ts b/yarn-project/acir-simulator/src/test/utils.ts index e2e0310d458..916243400e4 100644 --- a/yarn-project/acir-simulator/src/test/utils.ts +++ b/yarn-project/acir-simulator/src/test/utils.ts @@ -1,11 +1,8 @@ import { L1Actor, L1ToL2Message, L2Actor } from '@aztec/circuit-types'; import { AztecAddress, EthAddress, Fr } from '@aztec/circuits.js'; import { computeSecretMessageHash } from '@aztec/circuits.js/abis'; -import { ContractArtifact, FunctionSelector, getFunctionDebugMetadata } from '@aztec/foundation/abi'; import { sha256 } from '@aztec/foundation/crypto'; -import { FunctionArtifactWithDebugMetadata } from '../index.js'; - /** * Test utility function to craft an L1 to L2 message. * @param selector - The cross chain message selector. @@ -39,31 +36,3 @@ export const buildL1ToL2Message = ( 0, ); }; - -export const getFunctionArtifact = ( - artifact: ContractArtifact, - functionName: string, -): FunctionArtifactWithDebugMetadata => { - const functionArtifact = artifact.functions.find(f => f.name === functionName); - if (!functionArtifact) { - throw new Error(`Unknown function ${functionName}`); - } - - const debug = getFunctionDebugMetadata(artifact, functionName); - return { ...functionArtifact, debug }; -}; - -export const getFunctionArtifactWithSelector = ( - artifact: ContractArtifact, - functionSelector: FunctionSelector, -): FunctionArtifactWithDebugMetadata => { - const functionArtifact = artifact.functions.find(f => - functionSelector.equals(FunctionSelector.fromNameAndParameters(f.name, f.parameters)), - ); - if (!functionArtifact) { - throw new Error(`Unknown function ${functionSelector}`); - } - - const debug = getFunctionDebugMetadata(artifact, functionArtifact.name); - return { ...functionArtifact, debug }; -}; diff --git a/yarn-project/aztec.js/package.json b/yarn-project/aztec.js/package.json index 7b6d167eef2..c3e3c461005 100644 --- a/yarn-project/aztec.js/package.json +++ b/yarn-project/aztec.js/package.json @@ -25,8 +25,7 @@ "tsconfig": "./tsconfig.json" }, "scripts": { - "build": "yarn clean && yarn build:copy-contracts && tsc -b && webpack", - "build:copy-contracts": "mkdir -p ./src/account_contract/artifacts && cp ../noir-contracts/src/SchnorrAccount.json ../noir-contracts/src/EcdsaAccount.json ../noir-contracts/src/SchnorrSingleKeyAccount.json ./src/account_contract/artifacts", + "build": "yarn clean && tsc -b && webpack", "build:web": "webpack", "build:dev": "tsc -b --watch", "build:ts": "tsc -b", diff --git a/yarn-project/aztec.js/package.local.json b/yarn-project/aztec.js/package.local.json index db6bd6204c7..e070cdff602 100644 --- a/yarn-project/aztec.js/package.local.json +++ b/yarn-project/aztec.js/package.local.json @@ -1,6 +1,6 @@ { "scripts": { - "build": "yarn clean && yarn build:copy-contracts && tsc -b && webpack", + "build": "yarn clean && tsc -b && webpack", "build:web": "webpack", "build:dev": "tsc -b --watch", "build:ts": "tsc -b", diff --git a/yarn-project/aztec.js/src/api/abi.ts b/yarn-project/aztec.js/src/api/abi.ts index d76502b881d..7e94b7eb30f 100644 --- a/yarn-project/aztec.js/src/api/abi.ts +++ b/yarn-project/aztec.js/src/api/abi.ts @@ -1 +1,3 @@ export { ContractArtifact, FunctionArtifact, FunctionSelector } from '@aztec/foundation/abi'; +export { loadContractArtifact } from '@aztec/types/abi'; +export { NoirCompiledContract } from '@aztec/types/noir'; diff --git a/yarn-project/aztec.js/src/contract/contract.test.ts b/yarn-project/aztec.js/src/contract/contract.test.ts index 524eb778393..14bdbe71f29 100644 --- a/yarn-project/aztec.js/src/contract/contract.test.ts +++ b/yarn-project/aztec.js/src/contract/contract.test.ts @@ -43,6 +43,7 @@ describe('Contract Class', () => { name: 'bar', functionType: FunctionType.SECRET, isInternal: false, + debugSymbols: '', parameters: [ { name: 'value', @@ -69,6 +70,7 @@ describe('Contract Class', () => { parameters: [], returnTypes: [], bytecode: '0be', + debugSymbols: '', }, { name: 'qux', @@ -91,9 +93,11 @@ describe('Contract Class', () => { }, ], bytecode: '0cd', + debugSymbols: '', }, ], events: [], + fileMap: {}, }; beforeEach(() => { diff --git a/yarn-project/aztec.js/src/contract_deployer/contract_deployer.test.ts b/yarn-project/aztec.js/src/contract_deployer/contract_deployer.test.ts index 8316f8f0a71..6fabd46e2ac 100644 --- a/yarn-project/aztec.js/src/contract_deployer/contract_deployer.test.ts +++ b/yarn-project/aztec.js/src/contract_deployer/contract_deployer.test.ts @@ -19,9 +19,11 @@ describe.skip('Contract Deployer', () => { parameters: [], returnTypes: [], bytecode: '0af', + debugSymbols: '', }, ], events: [], + fileMap: {}, }; const publicKey: PublicKey = Point.random(); diff --git a/yarn-project/aztec.js/src/index.ts b/yarn-project/aztec.js/src/index.ts index d0f2ba7a8a2..ff2378a23bf 100644 --- a/yarn-project/aztec.js/src/index.ts +++ b/yarn-project/aztec.js/src/index.ts @@ -64,7 +64,6 @@ export { EthAddress, Fr, Fq, - FunctionSelector, GlobalVariables, GrumpkinScalar, Point, @@ -114,7 +113,7 @@ export { NodeInfo } from '@aztec/types/interfaces'; // TODO: These kinds of things have no place on our public api. // External devs will almost certainly have their own methods of doing these things. // If we want to use them in our own "aztec.js consuming code", import them from foundation as needed. -export { ContractArtifact, FunctionArtifact, encodeArguments } from '@aztec/foundation/abi'; +export { encodeArguments } from '@aztec/foundation/abi'; export { sha256 } from '@aztec/foundation/crypto'; export { DebugLogger, createDebugLogger, onLog } from '@aztec/foundation/log'; export { retry, retryUntil } from '@aztec/foundation/retry'; @@ -137,3 +136,4 @@ export { // Here you *can* do `export *` as the granular api defacto exports things explicitly. // This entire index file will be deprecated at some point after we're satisfied. export * from './api/init.js'; +export * from './api/abi.js'; diff --git a/yarn-project/circuit-types/src/contract_dao.test.ts b/yarn-project/circuit-types/src/contract_dao.test.ts index 5cfa8ea7e92..5e8faa4650a 100644 --- a/yarn-project/circuit-types/src/contract_dao.test.ts +++ b/yarn-project/circuit-types/src/contract_dao.test.ts @@ -38,9 +38,11 @@ describe('ContractDao', () => { ], returnTypes: [], bytecode: '0af', + debugSymbols: '', }, ], events: [], + fileMap: {}, }; const dao = new ContractDao(artifact, CompleteAddress.random(), EthAddress.random()); diff --git a/yarn-project/circuit-types/src/contract_dao.ts b/yarn-project/circuit-types/src/contract_dao.ts index 2817c1f2551..79e07af969f 100644 --- a/yarn-project/circuit-types/src/contract_dao.ts +++ b/yarn-project/circuit-types/src/contract_dao.ts @@ -1,7 +1,7 @@ import { CompleteAddress, ContractFunctionDao } from '@aztec/circuits.js'; import { ContractArtifact, - DebugMetadata, + DebugFileMap, EventAbi, FunctionDebugMetadata, FunctionSelector, @@ -46,8 +46,8 @@ export class ContractDao implements ContractArtifact { return this.contractArtifact.events; } - get debug(): DebugMetadata | undefined { - return this.contractArtifact.debug; + get fileMap(): DebugFileMap { + return this.contractArtifact.fileMap; } getFunctionArtifact(selector: FunctionSelector): ContractFunctionDao | undefined { @@ -59,7 +59,8 @@ export class ContractDao implements ContractArtifact { } getFunctionDebugMetadataByName(functionName: string): FunctionDebugMetadata | undefined { - return getFunctionDebugMetadata(this, functionName); + const fn = this.getFunctionArtifactByName(functionName); + return fn && getFunctionDebugMetadata(this, fn); } toBuffer(): Buffer { diff --git a/yarn-project/circuit-types/src/mocks.ts b/yarn-project/circuit-types/src/mocks.ts index 44336d6caa3..c4d9827e852 100644 --- a/yarn-project/circuit-types/src/mocks.ts +++ b/yarn-project/circuit-types/src/mocks.ts @@ -48,6 +48,7 @@ export const randomContractArtifact = (): ContractArtifact => ({ name: randomBytes(4).toString('hex'), functions: [], events: [], + fileMap: {}, }); export const randomDeployedContract = (): DeployedContract => ({ diff --git a/yarn-project/cli/src/test/mocks.ts b/yarn-project/cli/src/test/mocks.ts index f02cbdb8f75..7a9e662eda6 100644 --- a/yarn-project/cli/src/test/mocks.ts +++ b/yarn-project/cli/src/test/mocks.ts @@ -18,6 +18,7 @@ export const mockContractArtifact: ContractArtifact = { ], returnTypes: [], bytecode: 'constructorBytecode', + debugSymbols: '', }, { name: 'mockFunction', @@ -59,7 +60,9 @@ export const mockContractArtifact: ContractArtifact = { ], returnTypes: [{ kind: 'boolean' }], bytecode: 'mockBytecode', + debugSymbols: '', }, ], events: [], + fileMap: {}, }; diff --git a/yarn-project/end-to-end/tsconfig.web.json b/yarn-project/end-to-end/tsconfig.web.json index 94b4537fe51..890902dced6 100644 --- a/yarn-project/end-to-end/tsconfig.web.json +++ b/yarn-project/end-to-end/tsconfig.web.json @@ -8,5 +8,5 @@ { "path": "../aztec.js" } - ], + ] } diff --git a/yarn-project/foundation/src/abi/abi.ts b/yarn-project/foundation/src/abi/abi.ts index 9216c9805e9..406ff37aa99 100644 --- a/yarn-project/foundation/src/abi/abi.ts +++ b/yarn-project/foundation/src/abi/abi.ts @@ -1,5 +1,7 @@ import { inflate } from 'pako'; +import { type FunctionSelector } from './selector.js'; + /** * A named type. */ @@ -164,6 +166,10 @@ export interface FunctionArtifact extends FunctionAbi { * The verification key of the function. */ verificationKey?: string; + /** + * Maps opcodes to source code pointers + */ + debugSymbols: string; } /** @@ -227,20 +233,6 @@ export type DebugFileMap = Record< } >; -/** - * The debug metadata of an ABI. - */ -export interface DebugMetadata { - /** - * The DebugInfo object, deflated as JSON, compressed using gzip and serialized with base64. - */ - debugSymbols: string[]; - /** - * The map of file ID to the source code and path of the file. - */ - fileMap: DebugFileMap; -} - /** * Defines artifact of a contract. */ @@ -265,10 +257,9 @@ export interface ContractArtifact { events: EventAbi[]; /** - * The debug metadata of the contract. - * It's used to include the relevant source code section when a constraint is not met during simulation. + * The map of file ID to the source code and path of the file. */ - debug?: DebugMetadata; + fileMap: DebugFileMap; } /** @@ -285,6 +276,47 @@ export interface FunctionDebugMetadata { files: DebugFileMap; } +/** A function artifact with optional debug metadata */ +export interface FunctionArtifactWithDebugMetadata extends FunctionArtifact { + /** Debug metadata for the function. */ + debug?: FunctionDebugMetadata; +} + +/** + * Gets a function artifact given its name or selector. + */ +export function getFunctionArtifact( + artifact: ContractArtifact, + functionNameOrSelector: string | FunctionSelector, +): FunctionArtifact { + const functionArtifact = artifact.functions.find(f => + typeof functionNameOrSelector === 'string' + ? f.name === functionNameOrSelector + : functionNameOrSelector.equals(f.name, f.parameters), + ); + if (!functionArtifact) { + throw new Error(`Unknown function ${functionNameOrSelector}`); + } + return functionArtifact; +} + +/** @deprecated Use getFunctionArtifact instead */ +export function getFunctionArtifactWithSelector(artifact: ContractArtifact, selector: FunctionSelector) { + return getFunctionArtifact(artifact, selector); +} + +/** + * Gets a function artifact including debug metadata given its name or selector. + */ +export function getFunctionArtifactWithDebugMetadata( + artifact: ContractArtifact, + functionNameOrSelector: string | FunctionSelector, +): FunctionArtifactWithDebugMetadata { + const functionArtifact = getFunctionArtifact(artifact, functionNameOrSelector); + const debugMetadata = getFunctionDebugMetadata(artifact, functionArtifact); + return { ...functionArtifact, debug: debugMetadata }; +} + /** * Gets the debug metadata of a given function from the contract artifact * @param artifact - The contract build artifact @@ -292,19 +324,14 @@ export interface FunctionDebugMetadata { * @returns The debug metadata of the function */ export function getFunctionDebugMetadata( - artifact: ContractArtifact, - functionName: string, + contractArtifact: ContractArtifact, + functionArtifact: FunctionArtifact, ): FunctionDebugMetadata | undefined { - const functionIndex = artifact.functions.findIndex(f => f.name === functionName); - if (artifact.debug && functionIndex !== -1) { + if (functionArtifact.debugSymbols && contractArtifact.fileMap) { const debugSymbols = JSON.parse( - inflate(Buffer.from(artifact.debug.debugSymbols[functionIndex], 'base64'), { to: 'string' }), + inflate(Buffer.from(functionArtifact.debugSymbols, 'base64'), { to: 'string', raw: true }), ); - const files = artifact.debug.fileMap; - return { - debugSymbols, - files, - }; + return { debugSymbols, files: contractArtifact.fileMap }; } return undefined; } diff --git a/yarn-project/foundation/src/abi/selector.ts b/yarn-project/foundation/src/abi/selector.ts index 0c631418b29..ff70d868f03 100644 --- a/yarn-project/foundation/src/abi/selector.ts +++ b/yarn-project/foundation/src/abi/selector.ts @@ -3,7 +3,7 @@ import { BufferReader } from '@aztec/foundation/serialize'; import { keccak } from '../crypto/keccak/index.js'; import { Fr } from '../fields/index.js'; -import { ABIParameter } from './abi.js'; +import { type ABIParameter } from './abi.js'; import { decodeFunctionSignature } from './decoder.js'; /* eslint-disable @typescript-eslint/no-unsafe-declaration-merging */ @@ -71,6 +71,19 @@ export interface FunctionSelector { /** A function selector is the first 4 bytes of the hash of a function signature. */ export class FunctionSelector extends Selector { + /** + * Checks if this function selector is equal to another. + * @returns True if the function selectors are equal. + */ + equals(otherName: string, otherParams: ABIParameter[]): boolean; + equals(other: FunctionSelector): boolean; + equals(other: FunctionSelector | string, otherParams?: ABIParameter[]): boolean { + if (typeof other === 'string') { + return this.equals(FunctionSelector.fromNameAndParameters(other, otherParams!)); + } + return this.value === other.value; + } + /** * Deserializes from a buffer or reader, corresponding to a write in cpp. * @param buffer - Buffer or BufferReader to read from. diff --git a/yarn-project/noir-compiler/package.json b/yarn-project/noir-compiler/package.json index af5b492ecfe..71c96a4db41 100644 --- a/yarn-project/noir-compiler/package.json +++ b/yarn-project/noir-compiler/package.json @@ -47,6 +47,7 @@ "dependencies": { "@aztec/circuits.js": "workspace:^", "@aztec/foundation": "workspace:^", + "@aztec/types": "workspace:^", "@iarna/toml": "^2.2.5", "@noir-lang/noir_wasm": "portal:../../noir/packages/noir_wasm", "base64-js": "^1.5.1", diff --git a/yarn-project/noir-compiler/src/cli/add_noir_compiler_commander_actions.ts b/yarn-project/noir-compiler/src/cli/add_noir_compiler_commander_actions.ts index 4c1dd616c20..ab40a9b78e8 100644 --- a/yarn-project/noir-compiler/src/cli/add_noir_compiler_commander_actions.ts +++ b/yarn-project/noir-compiler/src/cli/add_noir_compiler_commander_actions.ts @@ -18,15 +18,14 @@ export function addCodegenCommanderAction(program: Command, _: LogFn = () => {}) .command('codegen') .argument('', 'Path to the Noir ABI or project dir.') .option('-o, --outdir ', 'Output folder for the generated code.') - .option('-d, --debug', 'Include debug info.') .option('--ts', 'Generate TypeScript wrapper.') .option('--nr', 'Generate Noir interface.') .description('Validates and generates an Aztec Contract ABI from Noir ABI.') - .action(async (noirAbiPath: string, { debug, outdir, ts, nr }) => { + .action(async (noirAbiPath: string, { outdir, ts, nr }) => { if (ts && nr) { throw new Error('--ts and --nr are mutually exclusive.'); } const { generateCode } = await import('./codegen.js'); - generateCode(outdir || dirname(noirAbiPath), noirAbiPath, debug, ts, nr); + generateCode(outdir || dirname(noirAbiPath), noirAbiPath, { ts, nr }); }); } diff --git a/yarn-project/noir-compiler/src/cli/codegen.ts b/yarn-project/noir-compiler/src/cli/codegen.ts index 98eb5670d42..5d0234a7f84 100644 --- a/yarn-project/noir-compiler/src/cli/codegen.ts +++ b/yarn-project/noir-compiler/src/cli/codegen.ts @@ -1,35 +1,38 @@ -import { existsSync, mkdirSync, readFileSync, readdirSync, statSync, writeFileSync } from 'fs'; +import { loadContractArtifact } from '@aztec/types/abi'; + +import { mkdirSync, readFileSync, readdirSync, statSync, writeFileSync } from 'fs'; import path from 'path'; -import { generateContractArtifact } from '../contract-interface-gen/abi.js'; -import { generateTypescriptContractInterface } from '../contract-interface-gen/contractTypescript.js'; import { generateNoirContractInterface } from '../contract-interface-gen/noir.js'; +import { generateTypescriptContractInterface } from '../contract-interface-gen/typescript.js'; + +/** Generate code options */ +type GenerateCodeOptions = { /** Typescript */ ts?: boolean; /** Noir */ nr?: boolean }; /** - * + * Generates Noir interface or Typescript interface for a folder or single file from a Noir compilation artifact. */ -export function generateCode(outputPath: string, fileOrDirPath: string, includeDebug = false, ts = false, nr = false) { +export function generateCode(outputPath: string, fileOrDirPath: string, opts: GenerateCodeOptions = {}) { const stats = statSync(fileOrDirPath); if (stats.isDirectory()) { const files = readdirSync(fileOrDirPath).filter(file => file.endsWith('.json') && !file.startsWith('debug_')); for (const file of files) { const fullPath = path.join(fileOrDirPath, file); - generateFromNoirAbi(outputPath, fullPath, includeDebug, ts, nr); + generateFromNoirAbi(outputPath, fullPath, opts); } } else if (stats.isFile()) { - generateFromNoirAbi(outputPath, fileOrDirPath, includeDebug, ts, nr); + generateFromNoirAbi(outputPath, fileOrDirPath, opts); } } /** - * + * Generates Noir interface or Typescript interface for a single file Noir compilation artifact. */ -function generateFromNoirAbi(outputPath: string, noirAbiPath: string, includeDebug: boolean, ts: boolean, nr: boolean) { +function generateFromNoirAbi(outputPath: string, noirAbiPath: string, opts: GenerateCodeOptions = {}) { const contract = JSON.parse(readFileSync(noirAbiPath, 'utf8')); - const noirDebugPath = includeDebug ? getDebugFilePath(noirAbiPath) : undefined; - const debug = noirDebugPath ? JSON.parse(readFileSync(noirDebugPath, 'utf8')) : undefined; - const aztecAbi = generateContractArtifact({ contract, debug }); + const aztecAbi = loadContractArtifact(contract); + const { nr, ts } = opts; mkdirSync(outputPath, { recursive: true }); @@ -39,20 +42,17 @@ function generateFromNoirAbi(outputPath: string, noirAbiPath: string, includeDeb return; } - writeFileSync(`${outputPath}/${aztecAbi.name}.json`, JSON.stringify(aztecAbi, undefined, 2)); - if (ts) { - const tsWrapper = generateTypescriptContractInterface(aztecAbi, `./${aztecAbi.name}.json`); + console.log('OUT', outputPath); + let relativeArtifactPath = path.relative(outputPath, noirAbiPath); + if (relativeArtifactPath === path.basename(noirAbiPath)) { + // Prepend ./ for local import if the folder is the same + relativeArtifactPath = `./${relativeArtifactPath}`; + } + + console.log(`PATHS`, path.dirname(outputPath), noirAbiPath, relativeArtifactPath); + + const tsWrapper = generateTypescriptContractInterface(aztecAbi, relativeArtifactPath); writeFileSync(`${outputPath}/${aztecAbi.name}.ts`, tsWrapper); } } - -/** - * - */ -function getDebugFilePath(filePath: string) { - const dirname = path.dirname(filePath); - const basename = path.basename(filePath); - const result = path.join(dirname, 'debug_' + basename); - return existsSync(result) ? result : undefined; -} diff --git a/yarn-project/noir-compiler/src/contract-interface-gen/abi.ts b/yarn-project/noir-compiler/src/contract-interface-gen/abi.ts deleted file mode 100644 index 47473cdefa8..00000000000 --- a/yarn-project/noir-compiler/src/contract-interface-gen/abi.ts +++ /dev/null @@ -1,120 +0,0 @@ -import { FUNCTION_TREE_HEIGHT } from '@aztec/circuits.js/constants'; -import { ContractArtifact, DebugMetadata, FunctionArtifact, FunctionType } from '@aztec/foundation/abi'; - -import { deflate } from 'pako'; - -import { mockVerificationKey } from '../mocked_keys.js'; -import { - NoirCompilationResult, - NoirContractCompilationArtifacts, - NoirFunctionEntry, - NoirProgramCompilationArtifacts, - ProgramArtifact, - isNoirContractCompilationArtifacts, - isNoirProgramCompilationArtifacts, -} from '../noir_artifact.js'; - -/** - * Generates a function build artifact. Replaces verification key with a mock value. - * @param fn - Noir function entry. - * @returns Function artifact. - */ -function generateFunctionArtifact(fn: NoirFunctionEntry): FunctionArtifact { - const functionType = fn.function_type.toLowerCase() as FunctionType; - const isInternal = fn.is_internal; - - // If the function is not unconstrained, the first item is inputs or CallContext which we should omit - let parameters = fn.abi.parameters; - if (functionType !== FunctionType.UNCONSTRAINED) { - parameters = parameters.slice(1); - } - - // If the function is secret, the return is the public inputs, which should be omitted - const returnTypes = functionType === FunctionType.SECRET ? [] : [fn.abi.return_type.abi_type]; - - return { - name: fn.name, - functionType, - isInternal, - parameters, - returnTypes, - bytecode: fn.bytecode, - verificationKey: mockVerificationKey, - }; -} - -/** - * Entrypoint for generating the .json artifact for compiled contract or program - * @param compileResult - Noir build output. - * @returns Aztec contract build artifact. - */ -export function generateArtifact(compileResult: NoirCompilationResult) { - if (isNoirContractCompilationArtifacts(compileResult)) { - return generateContractArtifact(compileResult); - } else if (isNoirProgramCompilationArtifacts(compileResult)) { - return generateProgramArtifact(compileResult); - } else { - throw Error('Unsupported artifact type'); - } -} - -/** - * Given a Nargo output generates an Aztec-compatible contract artifact. - * @param compiled - Noir build output. - * @returns Aztec contract build artifact. - */ -export function generateProgramArtifact( - { program }: NoirProgramCompilationArtifacts, - // eslint-disable-next-line camelcase - noir_version?: string, -): ProgramArtifact { - return { - // eslint-disable-next-line camelcase - noir_version, - hash: program.hash, - abi: program.abi, - - // TODO: should we parse and write the debug? it doesn't seem to be in the nargo output - // debug: someParsedDebug, - }; -} - -/** - * Given a Nargo output generates an Aztec-compatible contract artifact. - * @param compiled - Noir build output. - * @returns Aztec contract build artifact. - */ -export function generateContractArtifact( - { contract, debug }: NoirContractCompilationArtifacts, - aztecNrVersion?: string, -): ContractArtifact { - const constructorArtifact = contract.functions.find(({ name }) => name === 'constructor'); - if (constructorArtifact === undefined) { - throw new Error('Contract must have a constructor function'); - } - if (contract.functions.length > 2 ** FUNCTION_TREE_HEIGHT) { - throw new Error(`Contract can only have a maximum of ${2 ** FUNCTION_TREE_HEIGHT} functions`); - } - const originalFunctions = contract.functions; - // TODO why sort? we should have idempotent compilation so this should not be needed. - const sortedFunctions = [...contract.functions].sort((fnA, fnB) => fnA.name.localeCompare(fnB.name)); - let parsedDebug: DebugMetadata | undefined = undefined; - - if (debug) { - parsedDebug = { - debugSymbols: sortedFunctions.map(fn => { - const originalIndex = originalFunctions.indexOf(fn); - return Buffer.from(deflate(JSON.stringify(debug.debug_symbols[originalIndex]))).toString('base64'); - }), - fileMap: debug.file_map, - }; - } - - return { - name: contract.name, - functions: sortedFunctions.map(generateFunctionArtifact), - events: contract.events, - debug: parsedDebug, - aztecNrVersion, - }; -} diff --git a/yarn-project/noir-compiler/src/contract-interface-gen/programTypescript.ts b/yarn-project/noir-compiler/src/contract-interface-gen/programTypescript.ts deleted file mode 100644 index 7961344b522..00000000000 --- a/yarn-project/noir-compiler/src/contract-interface-gen/programTypescript.ts +++ /dev/null @@ -1,189 +0,0 @@ -import { ABIType } from '@aztec/foundation/abi'; -import { NoirFunctionAbi } from '@aztec/noir-compiler'; - -/** - * Keep track off all of the Noir primitive types that were used. - * Most of these will not have a 1-1 definition in TypeScript, - * so we will need to generate type aliases for them. - * - * We want to generate type aliases - * for specific types that are used in the ABI. - * - * For example: - * - If `Field` is used we want to alias that - * with `number`. - * - If `u32` is used we want to alias that with `number` too. - */ -type PrimitiveTypesUsed = { - /** - * The name of the type alias that we will generate. - */ - aliasName: string; - /** - * The TypeScript type that we will alias to. - */ - tsType: string; -}; - -const noirPrimitiveTypesToTsTypes = new Map(); - -/** - * Typescript does not allow us to check for equality of non-primitive types - * easily, so we create a addIfUnique function that will only add an item - * to the map if it is not already there by using JSON.stringify. - * @param item - The item to add to the map. - */ -function addIfUnique(item: PrimitiveTypesUsed) { - const key = JSON.stringify(item); - if (!noirPrimitiveTypesToTsTypes.has(key)) { - noirPrimitiveTypesToTsTypes.set(key, item); - } -} - -/** - * Converts an ABI type to a TypeScript type. - * @param type - The ABI type to convert. - * @returns The typescript code to define the type. - */ -function abiTypeToTs(type: ABIType): string { - switch (type.kind) { - case 'integer': { - let tsIntType = ''; - if (type.sign === 'signed') { - tsIntType = `i${type.width}`; - } else { - tsIntType = `u${type.width}`; - } - addIfUnique({ aliasName: tsIntType, tsType: 'string' }); - return tsIntType; - } - case 'boolean': - return `boolean`; - case 'array': - return `FixedLengthArray<${abiTypeToTs(type.type)}, ${type.length}>`; - case 'struct': - return getLastComponentOfPath(type.path); - case 'field': - addIfUnique({ aliasName: 'Field', tsType: 'string' }); - return 'Field'; - default: - throw new Error(`Unknown ABI type ${type}`); - } -} - -/** - * Returns the last component of a path, e.g. "foo::bar::baz" -\> "baz" - * Note: that if we have a path such as "Baz", we will return "Baz". - * - * Since these paths corresponds to structs, we can assume that we - * cannot have "foo::bar::". - * - * We also make the assumption that since these paths are coming from - * Noir, then we will not have two paths that look like this: - * - foo::bar::Baz - * - cat::dog::Baz - * ie the last component of the path (struct name) is enough to uniquely identify - * the whole path. - * - * TODO: We should double check this assumption when we use type aliases, - * I expect that `foo::bar::Baz as Dog` would effectively give `foo::bar::Dog` - * @param str - The path to get the last component of. - * @returns The last component of the path. - */ -function getLastComponentOfPath(str: string): string { - const parts = str.split('::'); - const lastPart = parts[parts.length - 1]; - return lastPart; -} - -/** - * Generates TypeScript interfaces for the structs used in the ABI. - * @param type - The ABI type to generate the interface for. - * @param output - The set of structs that we have already generated bindings for. - * @returns The TypeScript code to define the struct. - */ -function generateStructInterfaces(type: ABIType, output: Set): string { - let result = ''; - - // Edge case to handle the array of structs case. - if (type.kind === 'array' && type.type.kind === 'struct' && !output.has(getLastComponentOfPath(type.type.path))) { - result += generateStructInterfaces(type.type, output); - } - if (type.kind !== 'struct') { - return result; - } - - // List of structs encountered while viewing this type that we need to generate - // bindings for. - const typesEncountered = new Set(); - - // Codegen the struct and then its fields, so that the structs fields - // are defined before the struct itself. - let codeGeneratedStruct = ''; - let codeGeneratedStructFields = ''; - - const structName = getLastComponentOfPath(type.path); - if (!output.has(structName)) { - codeGeneratedStruct += `export interface ${structName} {\n`; - for (const field of type.fields) { - codeGeneratedStruct += ` ${field.name}: ${abiTypeToTs(field.type)};\n`; - typesEncountered.add(field.type); - } - codeGeneratedStruct += `}\n\n`; - output.add(structName); - - // Generate code for the encountered structs in the field above - for (const type of typesEncountered) { - codeGeneratedStructFields += generateStructInterfaces(type, output); - } - } - - return codeGeneratedStructFields + '\n' + codeGeneratedStruct; -} - -/** - * Generates a TypeScript interface for the ABI. - * @param abiObj - The ABI to generate the interface for. - * @returns The TypeScript code to define the interface. - */ -export function generateTypescriptProgramInterface(abiObj: NoirFunctionAbi): string { - let result = ``; - const outputStructs = new Set(); - - // Define structs for composite types - for (const param of abiObj.parameters) { - result += generateStructInterfaces(param.type, outputStructs); - } - - // Generating Return type, if it exists - // - if (abiObj.return_type != null) { - result += generateStructInterfaces(abiObj.return_type.abi_type, outputStructs); - result += `export type ReturnType = ${abiTypeToTs(abiObj.return_type.abi_type)};\n`; - } - - // Generating Input type - result += '\nexport interface InputType {\n'; - for (const param of abiObj.parameters) { - result += ` ${param.name}: ${abiTypeToTs(param.type)};\n`; - } - result += '}'; - - // Add the primitive Noir types that do not have a 1-1 mapping to TypeScript. - let primitiveTypeAliases = ''; - for (const [, value] of noirPrimitiveTypesToTsTypes) { - primitiveTypeAliases += `\nexport type ${value.aliasName} = ${value.tsType};`; - } - - const fixedLengthArray = - '\nexport type FixedLengthArray = L extends 0 ? never[]: T[] & { length: L }'; - - return ( - `/* Autogenerated file, do not edit! */\n\n/* eslint-disable */\n` + - fixedLengthArray + - '\n' + - primitiveTypeAliases + - '\n' + - result - ); -} diff --git a/yarn-project/noir-compiler/src/contract-interface-gen/contractTypescript.ts b/yarn-project/noir-compiler/src/contract-interface-gen/typescript.ts similarity index 97% rename from yarn-project/noir-compiler/src/contract-interface-gen/contractTypescript.ts rename to yarn-project/noir-compiler/src/contract-interface-gen/typescript.ts index 7f37f9e4923..c17d0d7abb4 100644 --- a/yarn-project/noir-compiler/src/contract-interface-gen/contractTypescript.ts +++ b/yarn-project/noir-compiler/src/contract-interface-gen/typescript.ts @@ -154,7 +154,7 @@ function generateArtifactGetter(name: string) { function generateAbiStatement(name: string, artifactImportPath: string) { const stmts = [ `import ${name}ContractArtifactJson from '${artifactImportPath}' assert { type: 'json' };`, - `export const ${name}ContractArtifact = ${name}ContractArtifactJson as ContractArtifact;`, + `export const ${name}ContractArtifact = loadContractArtifact(${name}ContractArtifactJson as NoirCompiledContract);`, ]; return stmts.join('\n'); } @@ -192,6 +192,8 @@ import { FieldLike, Fr, FunctionSelectorLike, + loadContractArtifact, + NoirCompiledContract, Point, PublicKey, Wallet, diff --git a/yarn-project/noir-compiler/src/index.ts b/yarn-project/noir-compiler/src/index.ts index 836c2e8b2c9..88416ef4282 100644 --- a/yarn-project/noir-compiler/src/index.ts +++ b/yarn-project/noir-compiler/src/index.ts @@ -1,8 +1,4 @@ export * from './versions.js'; -export { generateTypescriptContractInterface } from './contract-interface-gen/contractTypescript.js'; +export { generateTypescriptContractInterface } from './contract-interface-gen/typescript.js'; export { generateNoirContractInterface } from './contract-interface-gen/noir.js'; -export { generateTypescriptProgramInterface } from './contract-interface-gen/programTypescript.js'; -export { generateContractArtifact } from './contract-interface-gen/abi.js'; - -export * from './noir_artifact.js'; diff --git a/yarn-project/noir-compiler/tsconfig.json b/yarn-project/noir-compiler/tsconfig.json index a6b3ad94790..00bc12a18a0 100644 --- a/yarn-project/noir-compiler/tsconfig.json +++ b/yarn-project/noir-compiler/tsconfig.json @@ -11,6 +11,9 @@ }, { "path": "../foundation" + }, + { + "path": "../types" } ], "include": ["src", "src/*.json"] diff --git a/yarn-project/noir-contracts/bootstrap.sh b/yarn-project/noir-contracts/bootstrap.sh deleted file mode 100755 index 43284ba2a79..00000000000 --- a/yarn-project/noir-contracts/bootstrap.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/usr/bin/env bash - -yarn noir:build:all diff --git a/yarn-project/noir-contracts/package.json b/yarn-project/noir-contracts/package.json index cd81311cf34..da109ff5b09 100644 --- a/yarn-project/noir-contracts/package.json +++ b/yarn-project/noir-contracts/package.json @@ -3,8 +3,8 @@ "version": "0.1.0", "type": "module", "exports": { - ".": "./dest/index.js", - "./*": "./dest/*.js" + ".": "./dest/src/index.js", + "./*": "./dest/src/*.js" }, "scripts": { "build": "yarn clean && yarn build:contracts && tsc -b", diff --git a/yarn-project/noir-contracts/scripts/compile.sh b/yarn-project/noir-contracts/scripts/compile.sh index 214e441409b..671599aa874 100755 --- a/yarn-project/noir-contracts/scripts/compile.sh +++ b/yarn-project/noir-contracts/scripts/compile.sh @@ -3,4 +3,4 @@ set -euo pipefail echo "Compiling contracts..." -../../noir/target/release/nargo compile --silence-warnings +nargo compile --silence-warnings diff --git a/yarn-project/noir-contracts/scripts/generate-types.sh b/yarn-project/noir-contracts/scripts/generate-types.sh index 6901ab97f40..8d11bb1943d 100755 --- a/yarn-project/noir-contracts/scripts/generate-types.sh +++ b/yarn-project/noir-contracts/scripts/generate-types.sh @@ -7,18 +7,17 @@ INDEX="$OUT_DIR/index.ts" rm -rf $OUT_DIR && mkdir -p $OUT_DIR # Generate index.ts header. -echo "// Auto generated module - do not edit!\n" > $INDEX +echo "// Auto generated module - do not edit!" > $INDEX for ABI in $(find target -maxdepth 1 -type f ! -name 'debug_*' -name '*.json'); do CONTRACT=$(jq -r .name $ABI) - DEBUG_INFO="$(dirname $ABI)/debug_$(basename $ABI)" echo "Creating types for $CONTRACT in $ABI..." - node --no-warnings ../noir-compiler/dest/cli.js codegen -o $OUT_DIR -d --ts $ABI + node --no-warnings ../noir-compiler/dest/cli.js codegen -o $OUT_DIR --ts $ABI # Add contract import/export to index.ts. echo "export * from './${CONTRACT}.js';" >> $INDEX done echo "Formatting..." -yarn formatting:fix + diff --git a/yarn-project/noir-contracts/scripts/transform_json_abi.sh b/yarn-project/noir-contracts/scripts/transform_json_abi.sh deleted file mode 100755 index bc27163ee6f..00000000000 --- a/yarn-project/noir-contracts/scripts/transform_json_abi.sh +++ /dev/null @@ -1,22 +0,0 @@ -#!/bin/bash -# Sadly, yarn-project expects ABI files in a format different to what is output from nargo. -# This provides a tool to quickly do the transform with jq. -# It's not currently used as the transform is done in TypeScript when we generate the contract wrapper. -# TODO: Why don't our contract classes just work with noir abis? -# -# Lowercase function_type value. -# Camel case function_type and is_internal. -# Discard first parameter (input) if function is not unconstrained. -# Hoist parameters out of abi. -# Hoist return_type out of abi, make an array of 1 element, or empty array if function is secret. -# -jq ' - .functions |= map( - (.functionType = (.function_type | ascii_downcase)) | - (.isInternal = .is_internal) | - del(.function_type, .is_internal) | - (.parameters = if .functionType == "unconstrained" then .abi.parameters else .abi.parameters[1:] end) | - (.returnTypes = if .functionType == "secret" then [] else [ .abi.return_type.abi_type ] end) | - del(.abi) - ) -' $1 diff --git a/yarn-project/noir-contracts/tsconfig.json b/yarn-project/noir-contracts/tsconfig.json index a82cec59baa..bf3da7b0006 100644 --- a/yarn-project/noir-contracts/tsconfig.json +++ b/yarn-project/noir-contracts/tsconfig.json @@ -2,7 +2,7 @@ "extends": "..", "compilerOptions": { "outDir": "dest", - "rootDir": "src", + "rootDir": ".", "tsBuildInfoFile": ".tsbuildinfo" }, "references": [ @@ -12,9 +12,7 @@ ], "include": [ "src", - "src/**/*.json" + "target", + "target/*.json", ], - "exclude": [ - "src/contracts" - ] } diff --git a/yarn-project/noir-protocol-circuits/package.json b/yarn-project/noir-protocol-circuits/package.json index 1a1bd96cb30..358e89ccc14 100644 --- a/yarn-project/noir-protocol-circuits/package.json +++ b/yarn-project/noir-protocol-circuits/package.json @@ -7,12 +7,12 @@ "./types": "./dest/types/index.js" }, "scripts": { - "build": "yarn clean && yarn noir:build && yarn noir:types", + "build": "yarn clean && yarn noir:build && yarn noir:types && tsc -b", "clean": "rm -rf ./dest .tsbuildinfo src/types src/target", "formatting": "run -T prettier --check ./src && run -T eslint ./src", "formatting:fix": "NODE_OPTIONS='--max-old-space-size=8096' run -T eslint --fix ./src && run -T prettier -w ./src", "formatting:fix:types": "NODE_OPTIONS='--max-old-space-size=8096' run -T eslint --fix ./src/types && run -T prettier -w ./src/types", - "noir:build": "cd src && ../../../noir/target/release/nargo compile --silence-warnings && rm -rf ./target/debug_*", + "noir:build": "cd src && ../../../noir/target/release/nargo compile --silence-warnings", "noir:types": "node --loader ts-node/esm src/scripts/generate_ts_from_abi.ts && yarn formatting:fix:types", "noir:test": "cd src && ../../../noir/target/release/nargo test", "test": "yarn test:js && yarn noir:test", @@ -30,6 +30,7 @@ "@aztec/circuits.js": "workspace:^", "@aztec/foundation": "workspace:^", "@aztec/noir-compiler": "workspace:^", + "@aztec/types": "workspace:^", "@noir-lang/acvm_js": "portal:../../noir/packages/acvm_js", "@noir-lang/backend_barretenberg": "portal:../../noir/packages/backend_barretenberg", "@noir-lang/noir_js": "portal:../../noir/packages/noir_js", diff --git a/yarn-project/noir-protocol-circuits/src/index.ts b/yarn-project/noir-protocol-circuits/src/index.ts index 89954211e99..05b346011be 100644 --- a/yarn-project/noir-protocol-circuits/src/index.ts +++ b/yarn-project/noir-protocol-circuits/src/index.ts @@ -11,7 +11,7 @@ import { RootRollupInputs, RootRollupPublicInputs, } from '@aztec/circuits.js'; -import { NoirCompiledCircuit } from '@aztec/noir-compiler'; +import { NoirCompiledCircuit } from '@aztec/types/noir'; import { WasmBlackBoxFunctionSolver, createBlackBoxSolver, executeCircuitWithBlackBoxSolver } from '@noir-lang/acvm_js'; import { Abi, abiDecode, abiEncode } from '@noir-lang/noirc_abi'; diff --git a/yarn-project/noir-protocol-circuits/src/scripts/generate_ts_from_abi.ts b/yarn-project/noir-protocol-circuits/src/scripts/generate_ts_from_abi.ts index b3c5d16482a..6fc683cc162 100644 --- a/yarn-project/noir-protocol-circuits/src/scripts/generate_ts_from_abi.ts +++ b/yarn-project/noir-protocol-circuits/src/scripts/generate_ts_from_abi.ts @@ -1,6 +1,6 @@ import { ABIType } from '@aztec/foundation/abi'; import { createConsoleLogger } from '@aztec/foundation/log'; -import { NoirCompiledCircuit, NoirFunctionAbi } from '@aztec/noir-compiler'; +import { NoirCompiledCircuit, NoirFunctionAbi } from '@aztec/types/noir'; import fs from 'fs/promises'; diff --git a/yarn-project/noir-protocol-circuits/tsconfig.json b/yarn-project/noir-protocol-circuits/tsconfig.json index 4c2a3c5e245..917d509e475 100644 --- a/yarn-project/noir-protocol-circuits/tsconfig.json +++ b/yarn-project/noir-protocol-circuits/tsconfig.json @@ -15,6 +15,9 @@ { "path": "../noir-compiler" }, + { + "path": "../types" + }, { "path": "../circuit-types" }, diff --git a/yarn-project/pxe/src/simulator_oracle/index.ts b/yarn-project/pxe/src/simulator_oracle/index.ts index 7af6ca539d7..d33010931b1 100644 --- a/yarn-project/pxe/src/simulator_oracle/index.ts +++ b/yarn-project/pxe/src/simulator_oracle/index.ts @@ -1,4 +1,4 @@ -import { DBOracle, FunctionArtifactWithDebugMetadata, MessageLoadOracleInputs } from '@aztec/acir-simulator'; +import { DBOracle, MessageLoadOracleInputs } from '@aztec/acir-simulator'; import { KeyStore, L2Block, @@ -17,6 +17,7 @@ import { GrumpkinPrivateKey, PublicKey, } from '@aztec/circuits.js'; +import { FunctionArtifactWithDebugMetadata } from '@aztec/foundation/abi'; import { createDebugLogger } from '@aztec/foundation/log'; import { ContractDataOracle } from '../contract_data_oracle/index.js'; diff --git a/yarn-project/types/.eslintrc.cjs b/yarn-project/types/.eslintrc.cjs index 30064fcb134..e659927475c 100644 --- a/yarn-project/types/.eslintrc.cjs +++ b/yarn-project/types/.eslintrc.cjs @@ -1 +1 @@ -module.exports = require('@aztec/foundation/eslint'); \ No newline at end of file +module.exports = require('@aztec/foundation/eslint'); diff --git a/yarn-project/types/package.json b/yarn-project/types/package.json index 2ebd3ab048d..f8e42023289 100644 --- a/yarn-project/types/package.json +++ b/yarn-project/types/package.json @@ -6,8 +6,10 @@ "main": "./dest/index.js", "types": "./dest/index.d.ts", "exports": { + "./abi": "./dest/abi/index.js", "./interfaces": "./dest/interfaces/index.js", - "./membership": "./dest/sibling-path/index.js" + "./membership": "./dest/sibling-path/index.js", + "./noir": "./dest/noir/index.js" }, "scripts": { "build": "yarn clean && tsc -b", diff --git a/yarn-project/types/src/abi/contract_artifact.ts b/yarn-project/types/src/abi/contract_artifact.ts new file mode 100644 index 00000000000..1df2e3dbac1 --- /dev/null +++ b/yarn-project/types/src/abi/contract_artifact.ts @@ -0,0 +1,130 @@ +import { + ABIParameter, + ABIParameterVisibility, + ABIType, + ContractArtifact, + FunctionArtifact, + FunctionType, +} from '@aztec/foundation/abi'; + +import { NoirCompiledContract } from '../noir/index.js'; +import { mockVerificationKey } from './mocked_keys.js'; + +/** + * Gets nargo build output and returns a valid contract artifact instance. + * @param input - Input object as generated by nargo compile. + * @returns A valid contract artifact instance. + */ +export function loadContractArtifact(input: NoirCompiledContract): ContractArtifact { + if (isContractArtifact(input)) { + return input; + } + const contractArtifact = generateContractArtifact(input); + validateContractArtifact(contractArtifact); + return contractArtifact; +} + +/** + * Checks if the given input looks like a valid ContractArtifact. The check is not exhaustive, + * and it's just meant to differentiate between nargo raw build artifacts and the ones + * produced by this compiler. + * @param input - Input object. + * @returns True if it looks like a ContractArtifact. + */ +function isContractArtifact(input: any): input is ContractArtifact { + if (typeof input !== 'object') { + return false; + } + const maybeContractArtifact = input as ContractArtifact; + if (typeof maybeContractArtifact.name !== 'string') { + return false; + } + if (!Array.isArray(maybeContractArtifact.functions)) { + return false; + } + for (const fn of maybeContractArtifact.functions) { + if (typeof fn.name !== 'string') { + return false; + } + if (typeof fn.functionType !== 'string') { + return false; + } + } + return true; +} + +/** Parameter in a function from a noir contract compilation artifact */ +type NoirCompiledContractFunctionParameter = NoirCompiledContractFunction['abi']['parameters'][number]; + +/** + * Generates a function parameter out of one generated by a nargo build. + * @param param - Noir parameter. + * @returns A function parameter. + */ +function generateFunctionParameter(param: NoirCompiledContractFunctionParameter): ABIParameter { + const { visibility } = param; + if ((visibility as string) === 'databus') { + throw new Error(`Unsupported visibility ${param.visibility} for noir contract function parameter ${param.name}.`); + } + return { ...param, visibility: visibility as ABIParameterVisibility }; +} + +/** Function from a noir contract compilation artifact */ +type NoirCompiledContractFunction = NoirCompiledContract['functions'][number]; + +/** + * Generates a function build artifact. Replaces verification key with a mock value. + * @param fn - Noir function entry. + * @returns Function artifact. + */ +function generateFunctionArtifact(fn: NoirCompiledContractFunction): FunctionArtifact { + const functionType = fn.function_type.toLowerCase() as FunctionType; + const isInternal = fn.is_internal; + + // If the function is not unconstrained, the first item is inputs or CallContext which we should omit + let parameters = fn.abi.parameters.map(generateFunctionParameter); + if (functionType !== 'unconstrained') { + parameters = parameters.slice(1); + } + + // If the function is secret, the return is the public inputs, which should be omitted + let returnTypes: ABIType[] = []; + if (functionType !== 'secret' && fn.abi.return_type) { + returnTypes = [fn.abi.return_type.abi_type]; + } + + return { + name: fn.name, + functionType, + isInternal, + parameters, + returnTypes, + bytecode: fn.bytecode, + verificationKey: mockVerificationKey, + debugSymbols: fn.debug_symbols, + }; +} + +/** Validates contract artifact instance, throwing on error. */ +function validateContractArtifact(contract: ContractArtifact) { + const constructorArtifact = contract.functions.find(({ name }) => name === 'constructor'); + if (constructorArtifact === undefined) { + throw new Error('Contract must have a constructor function'); + } + return contract; +} + +/** + * Given a Nargo output generates an Aztec-compatible contract artifact. + * @param compiled - Noir build output. + * @returns Aztec contract build artifact. + */ +function generateContractArtifact(contract: NoirCompiledContract, aztecNrVersion?: string): ContractArtifact { + return { + name: contract.name, + functions: contract.functions.map(generateFunctionArtifact), + events: contract.events, + fileMap: contract.file_map, + aztecNrVersion, + }; +} diff --git a/yarn-project/types/src/abi/index.ts b/yarn-project/types/src/abi/index.ts new file mode 100644 index 00000000000..27174adec05 --- /dev/null +++ b/yarn-project/types/src/abi/index.ts @@ -0,0 +1 @@ +export * from './contract_artifact.js'; diff --git a/yarn-project/types/src/abi/mocked_keys.ts b/yarn-project/types/src/abi/mocked_keys.ts new file mode 100644 index 00000000000..b8f5c677ead --- /dev/null +++ b/yarn-project/types/src/abi/mocked_keys.ts @@ -0,0 +1,2 @@ +export const mockVerificationKey = + '0000000200000800000000740000000f00000003515f3109623eb3c25aa5b16a1a79fd558bac7a7ce62c4560a8c537c77ce80dd339128d1d37b6582ee9e6df9567efb64313471dfa18f520f9ce53161b50dbf7731bc5f900000003515f322bc4cce83a486a92c92fd59bd84e0f92595baa639fc2ed86b00ffa0dfded2a092a669a3bdb7a273a015eda494457cc7ed5236f26cee330c290d45a33b9daa94800000003515f332729426c008c085a81bd34d8ef12dd31e80130339ef99d50013a89e4558eee6d0fa4ffe2ee7b7b62eb92608b2251ac31396a718f9b34978888789042b790a30100000003515f342be6b6824a913eb7a57b03cb1ee7bfb4de02f2f65fe8a4e97baa7766ddb353a82a8a25c49dc63778cd9fe96173f12a2bc77f3682f4c4448f98f1df82c75234a100000003515f351f85760d6ab567465aadc2f180af9eae3800e6958fec96aef53fd8a7b195d7c000c6267a0dd5cfc22b3fe804f53e266069c0e36f51885baec1e7e67650c62e170000000c515f41524954484d455449430d9d0f8ece2aa12012fa21e6e5c859e97bd5704e5c122064a66051294bc5e04213f61f54a0ebdf6fee4d4a6ecf693478191de0c2899bcd8e86a636c8d3eff43400000003515f43224a99d02c86336737c8dd5b746c40d2be6aead8393889a76a18d664029096e90f7fe81adcc92a74350eada9622ac453f49ebac24a066a1f83b394df54dfa0130000000c515f46495845445f42415345060e8a013ed289c2f9fd7473b04f6594b138ddb4b4cf6b901622a14088f04b8d2c83ff74fce56e3d5573b99c7b26d85d5046ce0c6559506acb7a675e7713eb3a00000007515f4c4f4749430721a91cb8da4b917e054f72147e1760cfe0ef3d45090ac0f4961d84ec1996961a25e787b26bd8b50b1a99450f77a424a83513c2b33af268cd253b0587ff50c700000003515f4d05dbd8623b8652511e1eb38d38887a69eceb082f807514f09e127237c5213b401b9325b48c6c225968002318095f89d0ef9cf629b2b7f0172e03bc39aacf6ed800000007515f52414e474504b57a3805e41df328f5ca9aefa40fad5917391543b7b65c6476e60b8f72e9ad07c92f3b3e11c8feae96dedc4b14a6226ef3201244f37cfc1ee5b96781f48d2b000000075349474d415f3125001d1954a18571eaa007144c5a567bb0d2be4def08a8be918b8c05e3b27d312c59ed41e09e144eab5de77ca89a2fd783be702a47c951d3112e3de02ce6e47c000000075349474d415f3223994e6a23618e60fa01c449a7ab88378709197e186d48d604bfb6931ffb15ad11c5ec7a0700570f80088fd5198ab5d5c227f2ad2a455a6edeec024156bb7beb000000075349474d415f3300cda5845f23468a13275d18bddae27c6bb189cf9aa95b6a03a0cb6688c7e8d829639b45cf8607c525cc400b55ebf90205f2f378626dc3406cc59b2d1b474fba000000075349474d415f342d299e7928496ea2d37f10b43afd6a80c90a33b483090d18069ffa275eedb2fc2f82121e8de43dc036d99b478b6227ceef34248939987a19011f065d8b5cef5c0000000010000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f'; diff --git a/yarn-project/noir-compiler/src/noir_artifact.ts b/yarn-project/types/src/noir/index.ts similarity index 77% rename from yarn-project/noir-compiler/src/noir_artifact.ts rename to yarn-project/types/src/noir/index.ts index f8702b3ca0f..65d7c88cb29 100644 --- a/yarn-project/noir-compiler/src/noir_artifact.ts +++ b/yarn-project/types/src/noir/index.ts @@ -10,20 +10,15 @@ import { /** The Aztec.nr function types. */ type NoirFunctionType = 'Open' | 'Secret' | 'Unconstrained'; +/** The witness indices of the parameters. */ +type ParamWitnessIndices = { /** Start */ start: number; /** End */ end: number }; + /** The ABI of an Aztec.nr function. */ export interface NoirFunctionAbi { /** The parameters of the function. */ parameters: ABIParameter[]; /** The witness indices of the parameters. Indexed by parameter name. */ - param_witnesses: { - /** input */ - input: { - /** start */ - start: number; - /** end */ - end: number; - }[]; - }; + param_witnesses: { [key: string]: undefined | ParamWitnessIndices[] }; /** The return type of the function. */ return_type: { /** @@ -54,9 +49,11 @@ export interface NoirFunctionEntry { /** The bytecode of the function in base64. */ bytecode: string; /** The proving key. */ - proving_key: string; + proving_key?: string; /** The verification key. */ - verification_key: string; + verification_key?: string; + /** The debug information, compressed and base64 encoded. */ + debug_symbols: string; } /** @@ -69,6 +66,8 @@ export interface NoirCompiledContract { functions: NoirFunctionEntry[]; /** The events of the contract */ events: EventAbi[]; + /** The map of file ID to the source code and path of the file. */ + file_map: DebugFileMap; } /** @@ -83,35 +82,10 @@ export interface NoirCompiledCircuit { abi: NoirFunctionAbi; /** The bytecode of the circuit in base64. */ bytecode: string; -} - -/** - * Defines artifact of a contract. - */ -export interface ProgramArtifact { - /** - * version of noir used to compile - */ - noir_version?: string; - /** - * the name of the project, read from Nargo.toml - */ - name?: string; - /** - * The hash of the contract. - */ - hash?: number; - - /** - * The abi of the program. - */ - abi: any; // TODO: type - - /** - * The debug metadata of the contract. - * It's used to include the relevant source code section when a constraint is not met during simulation. - */ - debug?: NoirDebugMetadata; + /** The debug information, compressed and base64 encoded. */ + debug_symbols: string; + /** The map of file ID to the source code and path of the file. */ + file_map: DebugFileMap; } /** @@ -136,11 +110,6 @@ export interface NoirContractCompilationArtifacts { * The compiled contract. */ contract: NoirCompiledContract; - - /** - * The artifact that contains the debug metadata about the contract. - */ - debug?: NoirDebugMetadata; } /** @@ -155,11 +124,6 @@ export interface NoirProgramCompilationArtifacts { * The compiled contract. */ program: NoirCompiledCircuit; - - /** - * The artifact that contains the debug metadata about the contract. - */ - debug?: NoirDebugMetadata; } /** diff --git a/yarn-project/yarn.lock b/yarn-project/yarn.lock index c5e752f4d2f..ccd7eed53ed 100644 --- a/yarn-project/yarn.lock +++ b/yarn-project/yarn.lock @@ -608,6 +608,7 @@ __metadata: dependencies: "@aztec/circuits.js": "workspace:^" "@aztec/foundation": "workspace:^" + "@aztec/types": "workspace:^" "@iarna/toml": ^2.2.5 "@jest/globals": ^29.5.0 "@noir-lang/noir_wasm": "portal:../../noir/packages/noir_wasm" @@ -663,6 +664,7 @@ __metadata: "@aztec/foundation": "workspace:^" "@aztec/merkle-tree": "workspace:^" "@aztec/noir-compiler": "workspace:^" + "@aztec/types": "workspace:^" "@jest/globals": ^29.5.0 "@noir-lang/acvm_js": "portal:../../noir/packages/acvm_js" "@noir-lang/backend_barretenberg": "portal:../../noir/packages/backend_barretenberg" From 1028f3917fe6e6ed44de1e3f722834375b5c6c4f Mon Sep 17 00:00:00 2001 From: Santiago Palladino Date: Mon, 15 Jan 2024 11:44:48 -0300 Subject: [PATCH 03/16] Make cargo clippy happy --- noir/compiler/noirc_errors/src/debug_info.rs | 4 ++-- noir/compiler/wasm/src/compile.rs | 2 +- noir/tooling/nargo/src/artifacts/program.rs | 16 ++++++++-------- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/noir/compiler/noirc_errors/src/debug_info.rs b/noir/compiler/noirc_errors/src/debug_info.rs index a15119943c1..ffca8fbf2e1 100644 --- a/noir/compiler/noirc_errors/src/debug_info.rs +++ b/noir/compiler/noirc_errors/src/debug_info.rs @@ -110,7 +110,7 @@ impl DebugInfo { encoder.write_all(json_str.as_bytes()).map_err(S::Error::custom)?; let compressed_data = encoder.finish().map_err(S::Error::custom)?; - let encoded_b64 = base64::prelude::BASE64_STANDARD.encode(&compressed_data); + let encoded_b64 = base64::prelude::BASE64_STANDARD.encode(compressed_data); s.serialize_str(&encoded_b64) } @@ -123,7 +123,7 @@ impl DebugInfo { let encoded_b64: String = Deserialize::deserialize(deserializer)?; let compressed_data = - base64::prelude::BASE64_STANDARD.decode(&encoded_b64).map_err(D::Error::custom)?; + base64::prelude::BASE64_STANDARD.decode(encoded_b64).map_err(D::Error::custom)?; let mut decoder = DeflateDecoder::new(&compressed_data[..]); let mut decompressed_data = Vec::new(); diff --git a/noir/compiler/wasm/src/compile.rs b/noir/compiler/wasm/src/compile.rs index c94392adf83..83ea2d5512a 100644 --- a/noir/compiler/wasm/src/compile.rs +++ b/noir/compiler/wasm/src/compile.rs @@ -272,7 +272,7 @@ pub(crate) fn generate_program_artifact(program: CompiledProgram) -> CompileResu pub(crate) fn generate_contract_artifact(contract: CompiledContract) -> CompileResult { let functions = contract.functions.into_iter().map(ContractFunctionArtifact::from).collect(); - + let contract_artifact = ContractArtifact { noir_version: String::from(NOIR_ARTIFACT_VERSION_STRING), name: contract.name, diff --git a/noir/tooling/nargo/src/artifacts/program.rs b/noir/tooling/nargo/src/artifacts/program.rs index b1db5f31728..d8dc42ec214 100644 --- a/noir/tooling/nargo/src/artifacts/program.rs +++ b/noir/tooling/nargo/src/artifacts/program.rs @@ -49,15 +49,15 @@ impl From for ProgramArtifact { } } -impl Into for ProgramArtifact { - fn into(self) -> CompiledProgram { +impl From for CompiledProgram { + fn from(program: ProgramArtifact) -> Self { CompiledProgram { - hash: self.hash, - abi: self.abi, - noir_version: self.noir_version, - circuit: self.bytecode, - debug: self.debug_symbols, - file_map: self.file_map, + hash: program.hash, + abi: program.abi, + noir_version: program.noir_version, + circuit: program.bytecode, + debug: program.debug_symbols, + file_map: program.file_map, warnings: vec![], } } From 2ab5667109d193678f59b0091daf0947ff15f359 Mon Sep 17 00:00:00 2001 From: Santiago Palladino Date: Mon, 15 Jan 2024 13:52:09 -0300 Subject: [PATCH 04/16] Inflate as helper in noir wasm and fix browser test --- noir/compiler/wasm/package.json | 1 + noir/compiler/wasm/src/index.cts | 3 +- noir/compiler/wasm/src/index.mts | 3 +- noir/compiler/wasm/src/noir/debug.ts | 6 ++ .../browser/compile_with_deps.test.ts | 39 +++++---- .../compiler/node/compile_with_deps.test.ts | 76 ++---------------- .../compiler/shared/compile_with_deps.test.ts | 80 +++++++++++++++++++ .../src/client/private_execution.test.ts | 1 + 8 files changed, 118 insertions(+), 91 deletions(-) create mode 100644 noir/compiler/wasm/src/noir/debug.ts create mode 100644 noir/compiler/wasm/test/compiler/shared/compile_with_deps.test.ts diff --git a/noir/compiler/wasm/package.json b/noir/compiler/wasm/package.json index 7cdf78b0ffd..8b35e6ea7ac 100644 --- a/noir/compiler/wasm/package.json +++ b/noir/compiler/wasm/package.json @@ -33,6 +33,7 @@ "test": "yarn test:build_fixtures && yarn test:node && yarn test:browser", "test:build_fixtures": "./build-fixtures.sh", "test:browser": "web-test-runner", + "test:browser:docker": "docker run --rm -v $(cd ../.. && pwd):/usr/src/noir -w /usr/src/noir/compiler/wasm mcr.microsoft.com/playwright:v1.40.0-jammy yarn test:browser", "test:node": "NODE_NO_WARNINGS=1 mocha --config ./.mocharc.json", "clean": "rm -rf ./build ./target ./dist public/fixtures/simple/target public/fixtures/with-deps/target", "nightly:version": "jq --arg new_version \"-$(git rev-parse --short HEAD)$1\" '.version = .version + $new_version' package.json > package-tmp.json && mv package-tmp.json package.json", diff --git a/noir/compiler/wasm/src/index.cts b/noir/compiler/wasm/src/index.cts index 31d169e8268..14687e615df 100644 --- a/noir/compiler/wasm/src/index.cts +++ b/noir/compiler/wasm/src/index.cts @@ -3,6 +3,7 @@ import { createNodejsFileManager } from './noir/file-manager/nodejs-file-manager import { NoirWasmCompiler } from './noir/noir-wasm-compiler'; import { LogData, LogFn } from './utils'; import { CompilationResult } from './types/noir_artifact'; +import { inflateDebugSymbols } from './noir/debug'; async function compile( fileManager: FileManager, @@ -46,4 +47,4 @@ async function compile( const createFileManager = createNodejsFileManager; -export { compile, createFileManager, CompilationResult }; +export { compile, createFileManager, inflateDebugSymbols, CompilationResult }; diff --git a/noir/compiler/wasm/src/index.mts b/noir/compiler/wasm/src/index.mts index 6340e2dc37a..8774a7857ef 100644 --- a/noir/compiler/wasm/src/index.mts +++ b/noir/compiler/wasm/src/index.mts @@ -3,6 +3,7 @@ import { createNodejsFileManager } from './noir/file-manager/nodejs-file-manager import { NoirWasmCompiler } from './noir/noir-wasm-compiler'; import { LogData, LogFn } from './utils'; import { CompilationResult } from './types/noir_artifact'; +import { inflateDebugSymbols } from './noir/debug'; async function compile( fileManager: FileManager, @@ -48,4 +49,4 @@ async function compile( const createFileManager = createNodejsFileManager; -export { compile, createFileManager, CompilationResult }; +export { compile, createFileManager, inflateDebugSymbols, CompilationResult }; diff --git a/noir/compiler/wasm/src/noir/debug.ts b/noir/compiler/wasm/src/noir/debug.ts new file mode 100644 index 00000000000..7a65f4b68c2 --- /dev/null +++ b/noir/compiler/wasm/src/noir/debug.ts @@ -0,0 +1,6 @@ +import { inflate } from 'pako'; + +/** Decompresses and decodes the debug symbols */ +export function inflateDebugSymbols(debugSymbols: string) { + return JSON.parse(inflate(Buffer.from(debugSymbols, 'base64'), { to: 'string', raw: true })); +} diff --git a/noir/compiler/wasm/test/compiler/browser/compile_with_deps.test.ts b/noir/compiler/wasm/test/compiler/browser/compile_with_deps.test.ts index 3580779ff1d..9b922643e1a 100644 --- a/noir/compiler/wasm/test/compiler/browser/compile_with_deps.test.ts +++ b/noir/compiler/wasm/test/compiler/browser/compile_with_deps.test.ts @@ -3,6 +3,7 @@ import { getPaths } from '../../shared'; import { expect } from '@esm-bundle/chai'; import { compile, createFileManager } from '@noir-lang/noir_wasm'; import { CompiledContract } from '../../../src/types/noir_artifact'; +import { shouldCompileIdentically } from '../shared/compile_with_deps.test'; const paths = getPaths('.'); @@ -21,24 +22,22 @@ async function getPrecompiledSource(path: string): Promise { return JSON.parse(compiledData); } -describe('noir-compiler', () => { - it('both nargo and noir_wasm should compile identically', async () => { - const { contractExpectedArtifact } = paths; - const fm = createFileManager('/'); - const files = Object.values(paths).filter((fileOrDir) => /^\.?\/.*\..*$/.test(fileOrDir)); - for (const path of files) { - console.log(path); - await fm.writeFile(path, (await getFile(path)).body as ReadableStream); - } - const nargoArtifact = (await getPrecompiledSource(contractExpectedArtifact)) as CompiledContract; - nargoArtifact.functions.sort((a, b) => a.name.localeCompare(b.name)); - const noirWasmArtifact = await compile(fm, '/fixtures/noir-contract'); - if (!('contract' in noirWasmArtifact)) { - throw new Error('Compilation failed'); - } - const noirWasmContract = noirWasmArtifact.contract; - expect(noirWasmContract).not.to.be.undefined; - noirWasmContract.functions.sort((a, b) => a.name.localeCompare(b.name)); - expect(nargoArtifact).to.deep.eq(noirWasmContract); - }).timeout(60 * 20e3); +describe('noir-compiler/browser', () => { + shouldCompileIdentically( + async () => { + const { contractExpectedArtifact } = paths; + const fm = createFileManager('/'); + const files = Object.values(paths).filter((fileOrDir) => /^\.?\/.*\..*$/.test(fileOrDir)); + for (const path of files) { + console.log(path); + await fm.writeFile(path, (await getFile(path)).body as ReadableStream); + } + const nargoArtifact = (await getPrecompiledSource(contractExpectedArtifact)) as CompiledContract; + const noirWasmArtifact = await compile(fm, '/fixtures/noir-contract'); + + return { nargoArtifact, noirWasmArtifact }; + }, + expect, + 60 * 20e3, + ); }); diff --git a/noir/compiler/wasm/test/compiler/node/compile_with_deps.test.ts b/noir/compiler/wasm/test/compiler/node/compile_with_deps.test.ts index 4b2a27294b1..eef9c7e4635 100644 --- a/noir/compiler/wasm/test/compiler/node/compile_with_deps.test.ts +++ b/noir/compiler/wasm/test/compiler/node/compile_with_deps.test.ts @@ -1,82 +1,20 @@ import { join, resolve } from 'path'; import { getPaths } from '../../shared'; -import { inflate } from 'pako'; import { expect } from 'chai'; -import { readFile } from 'fs/promises'; import { compile, createFileManager } from '@noir-lang/noir_wasm'; -import { CompiledContract, DebugFileMap, DebugInfo } from '../../../src/types/noir_artifact'; -import { ContractCompilationArtifacts, NoirFunctionEntry } from 'dist/types/src/types/noir_artifact'; +import { readFile } from 'fs/promises'; +import { CompiledContract } from '../../../src/types/noir_artifact'; +import { shouldCompileIdentically } from '../shared/compile_with_deps.test'; const basePath = resolve(join(__dirname, '../../')); const { contractProjectPath, contractExpectedArtifact } = getPaths(basePath); -describe('noir-compiler', () => { - it('both nargo and noir_wasm should compile identically', async () => { +describe('noir-compiler/node', () => { + shouldCompileIdentically(async () => { const fm = createFileManager(contractProjectPath); const nargoArtifact = JSON.parse((await readFile(contractExpectedArtifact)).toString()) as CompiledContract; - const [nargoDebugInfos, nargoFileMap] = deleteDebugMetadata(nargoArtifact); - normalizeVersion(nargoArtifact); - const noirWasmArtifact = await compile(fm); - const noirWasmContract = (noirWasmArtifact as ContractCompilationArtifacts).contract; - expect(noirWasmContract).not.to.be.undefined; - const [noirWasmDebugInfos, norWasmFileMap] = deleteDebugMetadata(noirWasmContract); - normalizeVersion(noirWasmContract); - - // We first compare both contracts without considering debug info - expect(nargoArtifact).to.deep.eq(noirWasmContract); - - // Compare the file maps, ignoring keys, since those depend in the order in which files are visited, - // which may change depending on the file manager implementation. Also ignores paths, since the base - // path is reported differently between nargo and noir-wasm. - expect(getSources(nargoFileMap)).to.have.members(getSources(norWasmFileMap)); - - // Compare the debug symbol information, ignoring the actual ids used for file identifiers. - // Debug symbol info looks like the following, what we need is to ignore the 'file' identifiers - // {"locations":{"0":[{"span":{"start":141,"end":156},"file":39},{"span":{"start":38,"end":76},"file":38},{"span":{"start":824,"end":862},"file":23}]}} - expect(nargoDebugInfos).to.deep.eq(noirWasmDebugInfos); - }).timeout(5000); + return { nargoArtifact, noirWasmArtifact }; + }, expect); }); - -/** Remove commit identifier from version, which may not match depending on cached nargo and noir-wasm */ -function normalizeVersion(contract: CompiledContract) { - contract.noir_version = contract.noir_version.replace(/\+.+$/, ''); -} - -/** Decompresses and decodes the debug symbols */ -function inflateDebugSymbols(debugSymbols: string) { - return JSON.parse(inflate(Buffer.from(debugSymbols, 'base64'), { to: 'string', raw: true })); -} - -/** Extracts the debug symbols from all functions, decodes them, removes their file identifiers, and deletes them from the artifact. */ -function extractDebugInfos(fns: NoirFunctionEntry[]) { - return fns.map((fn) => { - const debugSymbols = inflateDebugSymbols(fn.debug_symbols); - delete (fn as Partial).debug_symbols; - clearFileIdentifiers(debugSymbols); - return debugSymbols; - }); -} - -/** Deletes all debug info from a contract and returns it. */ -function deleteDebugMetadata(contract: CompiledContract) { - contract.functions.sort((a, b) => a.name.localeCompare(b.name)); - const fileMap = contract.file_map; - delete (contract as Partial).file_map; - return [extractDebugInfos(contract.functions), fileMap]; -} - -/** Clears file identifiers from a set of debug symbols. */ -function clearFileIdentifiers(debugSymbols: DebugInfo) { - for (const loc of Object.values(debugSymbols.locations)) { - for (const span of loc) { - span.file = 0; - } - } -} - -/** Returns list of sources from file map, dropping paths along the way, since they don't match depending on the file manager. */ -function getSources(fileMap: DebugFileMap) { - return Object.values(fileMap).map((file) => file.source); -} diff --git a/noir/compiler/wasm/test/compiler/shared/compile_with_deps.test.ts b/noir/compiler/wasm/test/compiler/shared/compile_with_deps.test.ts new file mode 100644 index 00000000000..1840912ebe7 --- /dev/null +++ b/noir/compiler/wasm/test/compiler/shared/compile_with_deps.test.ts @@ -0,0 +1,80 @@ +import { CompilationResult, inflateDebugSymbols } from '@noir-lang/noir_wasm'; +import { type expect as Expect } from 'chai'; +import { + CompiledContract, + ContractCompilationArtifacts, + DebugFileMap, + DebugInfo, + NoirFunctionEntry, +} from '../../../src/types/noir_artifact'; + +export function shouldCompileIdentically( + compileFn: () => Promise<{ nargoArtifact: CompiledContract; noirWasmArtifact: CompilationResult }>, + expect: typeof Expect, + timeout = 5000, +) { + it('both nargo and noir_wasm should compile identically', async () => { + // Compile! + const { nargoArtifact, noirWasmArtifact } = await compileFn(); + + // Prepare nargo artifact + const [nargoDebugInfos, nargoFileMap] = deleteDebugMetadata(nargoArtifact); + normalizeVersion(nargoArtifact); + + // Prepare noir-wasm artifact + const noirWasmContract = (noirWasmArtifact as ContractCompilationArtifacts).contract; + expect(noirWasmContract).not.to.be.undefined; + const [noirWasmDebugInfos, norWasmFileMap] = deleteDebugMetadata(noirWasmContract); + normalizeVersion(noirWasmContract); + + // We first compare both contracts without considering debug info + expect(nargoArtifact).to.deep.eq(noirWasmContract); + + // Compare the file maps, ignoring keys, since those depend in the order in which files are visited, + // which may change depending on the file manager implementation. Also ignores paths, since the base + // path is reported differently between nargo and noir-wasm. + expect(getSources(nargoFileMap)).to.have.members(getSources(norWasmFileMap)); + + // Compare the debug symbol information, ignoring the actual ids used for file identifiers. + // Debug symbol info looks like the following, what we need is to ignore the 'file' identifiers + // {"locations":{"0":[{"span":{"start":141,"end":156},"file":39},{"span":{"start":38,"end":76},"file":38},{"span":{"start":824,"end":862},"file":23}]}} + expect(nargoDebugInfos).to.deep.eq(noirWasmDebugInfos); + }).timeout(timeout); +} + +/** Remove commit identifier from version, which may not match depending on cached nargo and noir-wasm */ +function normalizeVersion(contract: CompiledContract) { + contract.noir_version = contract.noir_version.replace(/\+.+$/, ''); +} + +/** Extracts the debug symbols from all functions, decodes them, removes their file identifiers, and deletes them from the artifact. */ +function extractDebugInfos(fns: NoirFunctionEntry[]) { + return fns.map((fn) => { + const debugSymbols = inflateDebugSymbols(fn.debug_symbols); + delete (fn as Partial).debug_symbols; + clearFileIdentifiers(debugSymbols); + return debugSymbols; + }); +} + +/** Deletes all debug info from a contract and returns it. */ +function deleteDebugMetadata(contract: CompiledContract) { + contract.functions.sort((a, b) => a.name.localeCompare(b.name)); + const fileMap = contract.file_map; + delete (contract as Partial).file_map; + return [extractDebugInfos(contract.functions), fileMap]; +} + +/** Clears file identifiers from a set of debug symbols. */ +function clearFileIdentifiers(debugSymbols: DebugInfo) { + for (const loc of Object.values(debugSymbols.locations)) { + for (const span of loc) { + span.file = 0; + } + } +} + +/** Returns list of sources from file map, dropping paths along the way, since they don't match depending on the file manager. */ +function getSources(fileMap: DebugFileMap) { + return Object.values(fileMap).map((file) => file.source); +} diff --git a/yarn-project/acir-simulator/src/client/private_execution.test.ts b/yarn-project/acir-simulator/src/client/private_execution.test.ts index 574e4b7b521..bf1c8b21c6b 100644 --- a/yarn-project/acir-simulator/src/client/private_execution.test.ts +++ b/yarn-project/acir-simulator/src/client/private_execution.test.ts @@ -235,6 +235,7 @@ describe('Private Execution test suite', () => { it('should have a constructor with arguments that inserts notes', async () => { const artifact = getFunctionArtifact(StatefulTestContractArtifact, 'constructor'); + console.log('ARTIFACT BYTECODE', artifact.bytecode); const result = await runSimulator({ args: [owner, 140], artifact }); From b89f99a8e6353f919139b15312d033a5c08f0745 Mon Sep 17 00:00:00 2001 From: Santiago Palladino Date: Mon, 15 Jan 2024 14:00:39 -0300 Subject: [PATCH 05/16] Fix yarn lockfile --- yarn-project/yarn.lock | 2 ++ 1 file changed, 2 insertions(+) diff --git a/yarn-project/yarn.lock b/yarn-project/yarn.lock index ccd7eed53ed..54e7444f69f 100644 --- a/yarn-project/yarn.lock +++ b/yarn-project/yarn.lock @@ -2817,6 +2817,8 @@ __metadata: "@noir-lang/noir_wasm@portal:../noir/packages/noir_wasm::locator=%40aztec%2Faztec3-packages%40workspace%3A.": version: 0.0.0-use.local resolution: "@noir-lang/noir_wasm@portal:../noir/packages/noir_wasm::locator=%40aztec%2Faztec3-packages%40workspace%3A." + dependencies: + pako: ^2.1.0 languageName: node linkType: soft From a45baa1278f77cdf3350fb2faa3bd3978211fa99 Mon Sep 17 00:00:00 2001 From: Santiago Palladino Date: Mon, 15 Jan 2024 14:27:21 -0300 Subject: [PATCH 06/16] Revert change in compile script --- yarn-project/noir-contracts/scripts/compile.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yarn-project/noir-contracts/scripts/compile.sh b/yarn-project/noir-contracts/scripts/compile.sh index 671599aa874..214e441409b 100755 --- a/yarn-project/noir-contracts/scripts/compile.sh +++ b/yarn-project/noir-contracts/scripts/compile.sh @@ -3,4 +3,4 @@ set -euo pipefail echo "Compiling contracts..." -nargo compile --silence-warnings +../../noir/target/release/nargo compile --silence-warnings From d0c68e6480c5300cce8eb28e7994206afe9134f2 Mon Sep 17 00:00:00 2001 From: Santiago Palladino Date: Mon, 15 Jan 2024 14:29:07 -0300 Subject: [PATCH 07/16] Revert change in types script --- yarn-project/noir-contracts/scripts/generate-types.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/yarn-project/noir-contracts/scripts/generate-types.sh b/yarn-project/noir-contracts/scripts/generate-types.sh index 8d11bb1943d..8ec4b7ebc4c 100755 --- a/yarn-project/noir-contracts/scripts/generate-types.sh +++ b/yarn-project/noir-contracts/scripts/generate-types.sh @@ -20,4 +20,5 @@ for ABI in $(find target -maxdepth 1 -type f ! -name 'debug_*' -name '*.json'); done echo "Formatting..." +yarn formatting:fix From c7f03749e06f8412075a516051b441b64697e482 Mon Sep 17 00:00:00 2001 From: Santiago Palladino Date: Mon, 15 Jan 2024 14:57:25 -0300 Subject: [PATCH 08/16] Formatting fixes --- yarn-project/accounts/scripts/copy-contracts.sh | 2 ++ .../acir-simulator/src/client/private_execution.test.ts | 2 -- yarn-project/noir-compiler/src/cli/codegen.ts | 3 --- 3 files changed, 2 insertions(+), 5 deletions(-) diff --git a/yarn-project/accounts/scripts/copy-contracts.sh b/yarn-project/accounts/scripts/copy-contracts.sh index 8c6b0e75332..6c7559dd49d 100755 --- a/yarn-project/accounts/scripts/copy-contracts.sh +++ b/yarn-project/accounts/scripts/copy-contracts.sh @@ -7,3 +7,5 @@ contracts=(schnorr_account_contract-SchnorrAccount ecdsa_account_contract-EcdsaA for contract in "${contracts[@]}"; do cp "../noir-contracts/target/$contract.json" ./src/artifacts/${contract#*-}.json done + +yarn formatting:fix \ No newline at end of file diff --git a/yarn-project/acir-simulator/src/client/private_execution.test.ts b/yarn-project/acir-simulator/src/client/private_execution.test.ts index bf1c8b21c6b..becd6a0f73c 100644 --- a/yarn-project/acir-simulator/src/client/private_execution.test.ts +++ b/yarn-project/acir-simulator/src/client/private_execution.test.ts @@ -235,8 +235,6 @@ describe('Private Execution test suite', () => { it('should have a constructor with arguments that inserts notes', async () => { const artifact = getFunctionArtifact(StatefulTestContractArtifact, 'constructor'); - console.log('ARTIFACT BYTECODE', artifact.bytecode); - const result = await runSimulator({ args: [owner, 140], artifact }); expect(result.newNotes).toHaveLength(1); diff --git a/yarn-project/noir-compiler/src/cli/codegen.ts b/yarn-project/noir-compiler/src/cli/codegen.ts index 5d0234a7f84..19c90f0a551 100644 --- a/yarn-project/noir-compiler/src/cli/codegen.ts +++ b/yarn-project/noir-compiler/src/cli/codegen.ts @@ -43,15 +43,12 @@ function generateFromNoirAbi(outputPath: string, noirAbiPath: string, opts: Gene } if (ts) { - console.log('OUT', outputPath); let relativeArtifactPath = path.relative(outputPath, noirAbiPath); if (relativeArtifactPath === path.basename(noirAbiPath)) { // Prepend ./ for local import if the folder is the same relativeArtifactPath = `./${relativeArtifactPath}`; } - console.log(`PATHS`, path.dirname(outputPath), noirAbiPath, relativeArtifactPath); - const tsWrapper = generateTypescriptContractInterface(aztecAbi, relativeArtifactPath); writeFileSync(`${outputPath}/${aztecAbi.name}.ts`, tsWrapper); } From 0864f801187855b9bd3d766aca282131a5126f99 Mon Sep 17 00:00:00 2001 From: Santiago Palladino Date: Mon, 15 Jan 2024 15:09:02 -0300 Subject: [PATCH 09/16] Import json artifact directly in js tests --- yarn-project/end-to-end/src/sample-dapp/ci/index.test.mjs | 2 +- yarn-project/end-to-end/src/sample-dapp/contracts.mjs | 6 +++--- yarn-project/end-to-end/src/sample-dapp/deploy.mjs | 5 +++-- .../foundation/src/json-rpc/client/json_rpc_client.ts | 2 +- yarn-project/noir-contracts/package.json | 1 + 5 files changed, 9 insertions(+), 7 deletions(-) diff --git a/yarn-project/end-to-end/src/sample-dapp/ci/index.test.mjs b/yarn-project/end-to-end/src/sample-dapp/ci/index.test.mjs index 5544f249352..ae799a12aab 100644 --- a/yarn-project/end-to-end/src/sample-dapp/ci/index.test.mjs +++ b/yarn-project/end-to-end/src/sample-dapp/ci/index.test.mjs @@ -10,6 +10,6 @@ describe('sample-dapp', () => { it('deploys and runs without errors', async () => { await waitForPXE(createPXEClient(PXE_URL)); await deploy(); - await main(); + // await main(); }, 90_000); }); diff --git a/yarn-project/end-to-end/src/sample-dapp/contracts.mjs b/yarn-project/end-to-end/src/sample-dapp/contracts.mjs index bb02c811fb0..83dfc7d054f 100644 --- a/yarn-project/end-to-end/src/sample-dapp/contracts.mjs +++ b/yarn-project/end-to-end/src/sample-dapp/contracts.mjs @@ -1,11 +1,11 @@ -import { AztecAddress, Contract } from '@aztec/aztec.js'; -import { TokenContractArtifact } from '@aztec/noir-contracts/Token'; +import { AztecAddress, Contract, loadContractArtifact } from '@aztec/aztec.js'; +import TokenContractJson from '@aztec/noir-contracts/target/token_contract-Token' assert { type: 'json' }; import { readFileSync } from 'fs'; // docs:start:get-tokens export async function getToken(client) { const addresses = JSON.parse(readFileSync('addresses.json')); - return Contract.at(AztecAddress.fromString(addresses.token), TokenContractArtifact, client); + return Contract.at(AztecAddress.fromString(addresses.token), loadContractArtifact(TokenContractJson), client); } // docs:end:get-tokens diff --git a/yarn-project/end-to-end/src/sample-dapp/deploy.mjs b/yarn-project/end-to-end/src/sample-dapp/deploy.mjs index 35654abcac2..33e739c3166 100644 --- a/yarn-project/end-to-end/src/sample-dapp/deploy.mjs +++ b/yarn-project/end-to-end/src/sample-dapp/deploy.mjs @@ -1,6 +1,6 @@ import { getInitialTestAccountsWallets } from '@aztec/accounts/testing'; -import { Contract, createPXEClient } from '@aztec/aztec.js'; -import { TokenContractArtifact } from '@aztec/noir-contracts/Token'; +import { Contract, createPXEClient, loadContractArtifact } from '@aztec/aztec.js'; +import TokenContractJson from '@aztec/noir-contracts/target/token_contract-Token' assert { type: 'json' }; import { writeFileSync } from 'fs'; import { fileURLToPath } from 'url'; @@ -13,6 +13,7 @@ async function main() { const [ownerWallet] = await getInitialTestAccountsWallets(pxe); const ownerAddress = ownerWallet.getCompleteAddress(); + const TokenContractArtifact = loadContractArtifact(TokenContractJson); const token = await Contract.deploy(ownerWallet, TokenContractArtifact, [ownerAddress, 'TokenName', 'TKN', 18]) .send() .deployed(); diff --git a/yarn-project/foundation/src/json-rpc/client/json_rpc_client.ts b/yarn-project/foundation/src/json-rpc/client/json_rpc_client.ts index a7cb59263ee..37713f3da94 100644 --- a/yarn-project/foundation/src/json-rpc/client/json_rpc_client.ts +++ b/yarn-project/foundation/src/json-rpc/client/json_rpc_client.ts @@ -77,7 +77,7 @@ export function makeFetch(retries: number[], noRetry: boolean, log?: DebugLogger return async (host: string, rpcMethod: string, body: any, useApiEndpoints: boolean) => { return await retry( () => defaultFetch(host, rpcMethod, body, useApiEndpoints, noRetry), - 'JsonRpcClient request', + `JsonRpcClient request to ${host}`, makeBackoff(retries), log, true, diff --git a/yarn-project/noir-contracts/package.json b/yarn-project/noir-contracts/package.json index da109ff5b09..6845b1f90ff 100644 --- a/yarn-project/noir-contracts/package.json +++ b/yarn-project/noir-contracts/package.json @@ -4,6 +4,7 @@ "type": "module", "exports": { ".": "./dest/src/index.js", + "./target/*": "./dest/target/*.json", "./*": "./dest/src/*.js" }, "scripts": { From fb9b690fb2138fb7febea3e9e30734c6d1192fd0 Mon Sep 17 00:00:00 2001 From: Santiago Palladino Date: Mon, 15 Jan 2024 15:18:06 -0300 Subject: [PATCH 10/16] Update docs --- docs/docs/dev_docs/contracts/compiling.md | 16 ++-------------- docs/docs/dev_docs/contracts/deploying.md | 2 +- .../getting_started/aztecnr-getting-started.md | 2 +- .../tutorials/uniswap/typescript_glue_code.md | 2 +- .../writing_dapp/contract_deployment.md | 11 ++--------- .../writing_dapp/contract_interaction.md | 2 +- .../tutorials/writing_private_voting_contract.md | 10 ++++------ .../dev_docs/tutorials/writing_token_contract.md | 2 +- 8 files changed, 13 insertions(+), 34 deletions(-) diff --git a/docs/docs/dev_docs/contracts/compiling.md b/docs/docs/dev_docs/contracts/compiling.md index a44bd6e32cd..8d19f7811a8 100644 --- a/docs/docs/dev_docs/contracts/compiling.md +++ b/docs/docs/dev_docs/contracts/compiling.md @@ -18,23 +18,11 @@ aztec-nargo compile This will output a JSON [artifact](./artifacts.md) for each contract in the project to a `target` folder containing the Noir ABI artifacts. -Before you can use the ABI it currently needs to be validated as being Aztec compatible, and transformed to an Aztec compatible ABI using `aztec-cli codegen`, passing a Noir ABI file or folder, and output location, e.g: - -```bash -aztec-cli codegen ./aztec-nargo/output/target/path -o src/artifacts -``` - -It can be useful to perform this compilation, validation and transformation in one go, so you may wish to chain the commands and perhaps add them to a package.json script. The below assumes your contract is in a folder called `contract` at your project root: - -```bash -(cd contract && aztec-nargo compile && aztec-cli codegen target -o ../src/artifacts) -``` - ### Typescript Interfaces -You can use the codegenerator to autogenerate type-safe typescript classes for each of your contracts. These classes define type-safe methods for deploying and interacting with your contract based on their artifact. +You can use the code generator to autogenerate type-safe typescript classes for each of your contracts. These classes define type-safe methods for deploying and interacting with your contract based on their artifact. -To generate them, include a `--ts` option in the codegen command with a path to the target folder for the typescript files: +To generate them, include a `--ts` option in the `codegen` command with a path to the target folder for the typescript files: ```bash aztec-cli codegen ./aztec-nargo/output/target/path -o src/artifacts --ts diff --git a/docs/docs/dev_docs/contracts/deploying.md b/docs/docs/dev_docs/contracts/deploying.md index 7e1f9a6d012..c2db9fc764a 100644 --- a/docs/docs/dev_docs/contracts/deploying.md +++ b/docs/docs/dev_docs/contracts/deploying.md @@ -33,7 +33,7 @@ Compile the contract: aztec-nargo compile ``` -Generate the ABI and typescript class: +Generate the typescript class: ```bash aztec-cli codegen ./aztec-nargo/output/target/path -o src/artifacts --ts diff --git a/docs/docs/dev_docs/getting_started/aztecnr-getting-started.md b/docs/docs/dev_docs/getting_started/aztecnr-getting-started.md index fe1b59cd6c8..954d60ff2b1 100644 --- a/docs/docs/dev_docs/getting_started/aztecnr-getting-started.md +++ b/docs/docs/dev_docs/getting_started/aztecnr-getting-started.md @@ -156,7 +156,7 @@ aztec-nargo compile This will compile the smart contract and create a `target` folder with a `.json` artifact inside. -After compiling, you need to generate the ABI and typescript class. In the same directory, run this: +After compiling, you can generate a typescript class. In the same directory, run this: ```bash aztec-cli codegen target -o src/artifacts --ts diff --git a/docs/docs/dev_docs/tutorials/uniswap/typescript_glue_code.md b/docs/docs/dev_docs/tutorials/uniswap/typescript_glue_code.md index e4004c9b02d..3bc026658e5 100644 --- a/docs/docs/dev_docs/tutorials/uniswap/typescript_glue_code.md +++ b/docs/docs/dev_docs/tutorials/uniswap/typescript_glue_code.md @@ -33,7 +33,7 @@ and the each of the Aztec.nr contracts by going into each folder and running: aztec-nargo compile ``` -And then generate the ABIs and typescript interface: +And then generate the typescript interface: ```bash aztec-cli codegen ./target/ -o ../../../src/test/fixtures uniswap --ts diff --git a/docs/docs/dev_docs/tutorials/writing_dapp/contract_deployment.md b/docs/docs/dev_docs/tutorials/writing_dapp/contract_deployment.md index d15d12279be..7459287af51 100644 --- a/docs/docs/dev_docs/tutorials/writing_dapp/contract_deployment.md +++ b/docs/docs/dev_docs/tutorials/writing_dapp/contract_deployment.md @@ -42,14 +42,6 @@ Now run the following from your contract folder (containing Nargo.toml): aztec-nargo compile ``` -Once you have compiled your contracts, you need to generate the ABIs: - -```sh -aztec-cli codegen ./target/path -o src/artifacts --ts -``` - -This should have created an artifact `contracts/token/src/artifacts/Token.json` with the interface and bytecode for your contract. - ## Deploy your contracts Let's now write a script for deploying your contracts to the Sandbox. We'll create a Private eXecution Environment (PXE) client, and then use the `ContractDeployer` class to deploy our contracts, and store the deployment address to a local JSON file. @@ -61,7 +53,8 @@ Create a new file `src/deploy.mjs`: import { writeFileSync } from 'fs'; import { Contract, ContractDeployer, createPXEClient } from '@aztec/aztec.js'; import { getInitialTestAccountsWallets } from '@aztec/accounts/testing'; -import TokenContractArtifact from "../contracts/token/target/Token.json" assert { type: "json" }; +import TokenContractJson from "../contracts/token/target/token_contract-Token.json" assert { type: "json" }; + #include_code dapp-deploy yarn-project/end-to-end/src/sample-dapp/deploy.mjs raw diff --git a/docs/docs/dev_docs/tutorials/writing_dapp/contract_interaction.md b/docs/docs/dev_docs/tutorials/writing_dapp/contract_interaction.md index 0e520cbf687..73c0eef546c 100644 --- a/docs/docs/dev_docs/tutorials/writing_dapp/contract_interaction.md +++ b/docs/docs/dev_docs/tutorials/writing_dapp/contract_interaction.md @@ -18,7 +18,7 @@ To do this, let's first initialize a new `Contract` instance using `aztec.js` th // src/contracts.mjs import { Contract } from "@aztec/aztec.js"; import { readFileSync } from "fs"; -import TokenContractArtifact from "../contracts/token/src/artifacts/Token.json" assert { type: "json" }; +import TokenContractJson from "../contracts/token/target/token_contract-Token.json" assert { type: "json" }; ``` And then add the following code for initializing the `Contract` instances: diff --git a/docs/docs/dev_docs/tutorials/writing_private_voting_contract.md b/docs/docs/dev_docs/tutorials/writing_private_voting_contract.md index 4683798346e..b5e6f084721 100644 --- a/docs/docs/dev_docs/tutorials/writing_private_voting_contract.md +++ b/docs/docs/dev_docs/tutorials/writing_private_voting_contract.md @@ -193,18 +193,16 @@ The easiest way to compile the contract is with `aztec-nargo`. Run the following aztec-nargo compile ``` -This will create a new directory called `target` and a JSON artifact inside it. To create the Aztec contract ABI and typescript interface, run: +This will create a new directory called `target` and a JSON artifact inside it. To optionally create a typescript interface, run: ```bash aztec-cli codegen target -o src/artifacts --ts ``` -This will create the ABI called `Voting.json` in `src/artifacts`. If you are getting some errors here you might want to check out the [debugging page](../debugging/main.md). - Once it is compiled you can [deploy](../contracts/deploying.md) it to the sandbox. Ensure your [sandbox is running](../cli/sandbox-reference.md) and run this in the same dir as before: ```bash -aztec-cli deploy ./src/artifacts/Voting.json --args $ADMIN_ADDRESS +aztec-cli deploy ./target/Voting.json --args $ADMIN_ADDRESS ``` The constructor takes an address as an argument to set the admin, so you can use an address that is deployed with the sandbox - check the sandbox terminal or run `aztec-cli get-accounts`. @@ -214,7 +212,7 @@ You should see a success message with the contract address. Now we can start cal Cast a vote like this: ```bash -aztec-cli send cast_vote --contract-artifact ./src/artifacts/Voting.json --contract-address $CONTRACT_ADDRESS --args 1 --private-key $PRIVATE_KEY +aztec-cli send cast_vote --contract-artifact ./target/Voting.json --contract-address $CONTRACT_ADDRESS --args 1 --private-key $PRIVATE_KEY ``` You can get the contract address from the sandbox terminal or the message printed when you deployed the contract. You can also get a private key from the sandbox terminal, or generate one with `aztec-cli generate-private-key`. @@ -226,7 +224,7 @@ You can now try running this command again to ensure our nullifier works. Get the number of votes like this: ```bash -aztec-cli call get_vote --contract-artifact ./src/artifacts/Voting.json --contract-address $CONTRACT_ADDRESS --args 1 +aztec-cli call get_vote --contract-artifact ./target/Voting.json --contract-address $CONTRACT_ADDRESS --args 1 ``` This should return `1n`. diff --git a/docs/docs/dev_docs/tutorials/writing_token_contract.md b/docs/docs/dev_docs/tutorials/writing_token_contract.md index e3380713e8e..f4fda400456 100644 --- a/docs/docs/dev_docs/tutorials/writing_token_contract.md +++ b/docs/docs/dev_docs/tutorials/writing_token_contract.md @@ -467,7 +467,7 @@ Run the following command in the directory where your `Nargo.toml` file is locat aztec-nargo compile ``` -Once your contract is compiled, generate the Aztec contract ABI with typescript interface with the following command: +Once your contract is compiled, optionally generate a typescript interface with the following command: ```bash aztec-cli codegen target -o src/artifacts --ts From fe0b9975a28970af915b39f5f338e880577b60f8 Mon Sep 17 00:00:00 2001 From: Santiago Palladino Date: Mon, 15 Jan 2024 15:20:26 -0300 Subject: [PATCH 11/16] Fix formatting in copy contracts --- yarn-project/accounts/scripts/copy-contracts.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yarn-project/accounts/scripts/copy-contracts.sh b/yarn-project/accounts/scripts/copy-contracts.sh index 6c7559dd49d..1fb52a3f282 100755 --- a/yarn-project/accounts/scripts/copy-contracts.sh +++ b/yarn-project/accounts/scripts/copy-contracts.sh @@ -8,4 +8,4 @@ for contract in "${contracts[@]}"; do cp "../noir-contracts/target/$contract.json" ./src/artifacts/${contract#*-}.json done -yarn formatting:fix \ No newline at end of file +yarn run -T prettier -w ./src/artifacts \ No newline at end of file From 7108b3c2a134e9169961f8e6d0d70aa48d4ead33 Mon Sep 17 00:00:00 2001 From: Santiago Palladino Date: Mon, 15 Jan 2024 16:15:54 -0300 Subject: [PATCH 12/16] Fix boxes tsconfig --- boxes/blank-react/tsconfig.json | 2 +- boxes/blank/tsconfig.json | 2 +- boxes/token/tsconfig.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/boxes/blank-react/tsconfig.json b/boxes/blank-react/tsconfig.json index 25932cb04b5..acc585a3b0e 100644 --- a/boxes/blank-react/tsconfig.json +++ b/boxes/blank-react/tsconfig.json @@ -21,5 +21,5 @@ "skipLibCheck": true, "jsx": "react-jsx" }, - "include": ["src", "src/artifacts/Blank.json"] + "include": ["src", "src/contracts/target/*.json"] } diff --git a/boxes/blank/tsconfig.json b/boxes/blank/tsconfig.json index 25932cb04b5..acc585a3b0e 100644 --- a/boxes/blank/tsconfig.json +++ b/boxes/blank/tsconfig.json @@ -21,5 +21,5 @@ "skipLibCheck": true, "jsx": "react-jsx" }, - "include": ["src", "src/artifacts/Blank.json"] + "include": ["src", "src/contracts/target/*.json"] } diff --git a/boxes/token/tsconfig.json b/boxes/token/tsconfig.json index 0c77d2196f9..acc585a3b0e 100644 --- a/boxes/token/tsconfig.json +++ b/boxes/token/tsconfig.json @@ -21,5 +21,5 @@ "skipLibCheck": true, "jsx": "react-jsx" }, - "include": ["src", "src/artifacts/Token.json"] + "include": ["src", "src/contracts/target/*.json"] } From a11a1c65b12bf5b3680d72cea69155cf857f518c Mon Sep 17 00:00:00 2001 From: Santiago Palladino Date: Mon, 15 Jan 2024 17:19:32 -0300 Subject: [PATCH 13/16] Fix addresses in e2e test --- yarn-project/end-to-end/src/guides/up_quick_start.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/yarn-project/end-to-end/src/guides/up_quick_start.sh b/yarn-project/end-to-end/src/guides/up_quick_start.sh index badbad7a9e8..194ca903bc9 100755 --- a/yarn-project/end-to-end/src/guides/up_quick_start.sh +++ b/yarn-project/end-to-end/src/guides/up_quick_start.sh @@ -6,8 +6,8 @@ set -eux # The following accounts and pks must match the ones exposed by the sandbox. # docs:start:declare-accounts -ALICE="0x26fc40ccf8622e4ac4bb1132762cb3917933b1b556155b1964bbbfdd3071ff5c" -BOB="0x2a0f32c34c5b948a7f9766f0c1aad70a86c0ee649f56208e936be4324d49b0b9" +ALICE="0x04dbef85279f36ac8b9627a3ff4f03fbaa2697a2855d6337d6ab2213d0781c41" +BOB="0x0ef67d2de19479fa81380723850b347e46b790d5528ee387fecdc312ce691dc4" ALICE_PRIVATE_KEY="0x2153536ff6628eee01cf4024889ff977a18d9fa61d0e414422f7681cf085c281" # docs:end:declare-accounts From d65828b62de47eb6537c3533552ceb72ad75b2e9 Mon Sep 17 00:00:00 2001 From: Santiago Palladino Date: Mon, 15 Jan 2024 17:33:00 -0300 Subject: [PATCH 14/16] Load accounts from CLI in e2e quick start guide --- yarn-project/cli/src/cmds/get_accounts.ts | 24 +++++++++++++++++-- yarn-project/cli/src/index.ts | 3 ++- .../end-to-end/src/guides/up_quick_start.sh | 7 +++--- 3 files changed, 27 insertions(+), 7 deletions(-) diff --git a/yarn-project/cli/src/cmds/get_accounts.ts b/yarn-project/cli/src/cmds/get_accounts.ts index 155e92d5a4e..79f9dbee325 100644 --- a/yarn-project/cli/src/cmds/get_accounts.ts +++ b/yarn-project/cli/src/cmds/get_accounts.ts @@ -5,11 +5,31 @@ import { createCompatibleClient } from '../client.js'; /** * */ -export async function getAccounts(rpcUrl: string, debugLogger: DebugLogger, log: LogFn) { +export async function getAccounts( + rpcUrl: string, + json: boolean, + debugLogger: DebugLogger, + log: LogFn, + logJson: (output: any) => void, +) { const client = await createCompatibleClient(rpcUrl, debugLogger); const accounts = await client.getRegisteredAccounts(); if (!accounts.length) { - log('No accounts found.'); + if (json) { + logJson([]); + } else { + log('No accounts found.'); + } + return; + } + if (json) { + logJson( + accounts.map(a => ({ + address: a.address.toString(), + publicKey: a.publicKey.toString(), + partialAddress: a.partialAddress.toString(), + })), + ); } else { log(`Accounts found: \n`); for (const account of accounts) { diff --git a/yarn-project/cli/src/index.ts b/yarn-project/cli/src/index.ts index 7b108c9f724..074745d6647 100644 --- a/yarn-project/cli/src/index.ts +++ b/yarn-project/cli/src/index.ts @@ -296,9 +296,10 @@ export function getProgram(log: LogFn, debugLogger: DebugLogger): Command { .command('get-accounts') .description('Gets all the Aztec accounts stored in the PXE.') .addOption(pxeOption) + .option('--json', 'Emit output as json') .action(async (options: any) => { const { getAccounts } = await import('./cmds/get_accounts.js'); - await getAccounts(options.rpcUrl, debugLogger, log); + await getAccounts(options.rpcUrl, options.json, debugLogger, log, logJson); }); program diff --git a/yarn-project/end-to-end/src/guides/up_quick_start.sh b/yarn-project/end-to-end/src/guides/up_quick_start.sh index 194ca903bc9..cd6de58da45 100755 --- a/yarn-project/end-to-end/src/guides/up_quick_start.sh +++ b/yarn-project/end-to-end/src/guides/up_quick_start.sh @@ -3,11 +3,10 @@ set -eux -# The following accounts and pks must match the ones exposed by the sandbox. - # docs:start:declare-accounts -ALICE="0x04dbef85279f36ac8b9627a3ff4f03fbaa2697a2855d6337d6ab2213d0781c41" -BOB="0x0ef67d2de19479fa81380723850b347e46b790d5528ee387fecdc312ce691dc4" +ACCOUNTS=$(aztec-cli get-accounts --json | jq -r '.[].address') +ALICE=$(echo "$ACCOUNTS" | sed -n 1p) +BOB=$(echo "$ACCOUNTS" | sed -n 2p) ALICE_PRIVATE_KEY="0x2153536ff6628eee01cf4024889ff977a18d9fa61d0e414422f7681cf085c281" # docs:end:declare-accounts From 4cd833af860814dcc5fe93f871797c1289209030 Mon Sep 17 00:00:00 2001 From: Santiago Palladino Date: Tue, 16 Jan 2024 11:44:50 -0300 Subject: [PATCH 15/16] Oops --- yarn-project/end-to-end/src/sample-dapp/ci/index.test.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yarn-project/end-to-end/src/sample-dapp/ci/index.test.mjs b/yarn-project/end-to-end/src/sample-dapp/ci/index.test.mjs index ae799a12aab..5544f249352 100644 --- a/yarn-project/end-to-end/src/sample-dapp/ci/index.test.mjs +++ b/yarn-project/end-to-end/src/sample-dapp/ci/index.test.mjs @@ -10,6 +10,6 @@ describe('sample-dapp', () => { it('deploys and runs without errors', async () => { await waitForPXE(createPXEClient(PXE_URL)); await deploy(); - // await main(); + await main(); }, 90_000); }); From 2d8868aa1ab6b28a8573ba7416293c949e009d20 Mon Sep 17 00:00:00 2001 From: Santiago Palladino Date: Wed, 17 Jan 2024 10:38:08 -0300 Subject: [PATCH 16/16] Apply suggestions from @TomAFrench --- noir/compiler/wasm/src/types/noir_artifact.ts | 12 ++++-------- .../test/compiler/browser/compile_with_deps.test.ts | 4 ++-- .../test/compiler/node/compile_with_deps.test.ts | 4 ++-- .../test/compiler/shared/compile_with_deps.test.ts | 10 +++++----- 4 files changed, 13 insertions(+), 17 deletions(-) diff --git a/noir/compiler/wasm/src/types/noir_artifact.ts b/noir/compiler/wasm/src/types/noir_artifact.ts index 4b9e4b1b79c..715877e335f 100644 --- a/noir/compiler/wasm/src/types/noir_artifact.ts +++ b/noir/compiler/wasm/src/types/noir_artifact.ts @@ -56,13 +56,11 @@ export interface NoirFunctionEntry { /** * The compilation result of an Noir contract. */ -export interface CompiledContract { +export interface ContractArtifact { /** The name of the contract. */ name: string; /** Version of noir used for the build. */ noir_version: string; - /** Compilation backend. */ - backend: string; /** The functions of the contract. */ functions: NoirFunctionEntry[]; /** The events of the contract */ @@ -74,11 +72,9 @@ export interface CompiledContract { /** * The compilation result of an Noir contract. */ -export interface CompiledCircuit { +export interface ProgramArtifact { /** The hash of the circuit. */ hash?: number; - /** Compilation backend. */ - backend: string; /** * The ABI of the function. */ abi: Abi; /** The bytecode of the circuit in base64. */ @@ -160,7 +156,7 @@ export interface ContractCompilationArtifacts { /** * The compiled contract. */ - contract: CompiledContract; + contract: ContractArtifact; /** Compilation warnings. */ warnings: Warning[]; @@ -177,7 +173,7 @@ export interface ProgramCompilationArtifacts { /** * The compiled contract. */ - program: CompiledCircuit; + program: ProgramArtifact; /** Compilation warnings. */ warnings: Warning[]; diff --git a/noir/compiler/wasm/test/compiler/browser/compile_with_deps.test.ts b/noir/compiler/wasm/test/compiler/browser/compile_with_deps.test.ts index 9b922643e1a..0d1e22e288f 100644 --- a/noir/compiler/wasm/test/compiler/browser/compile_with_deps.test.ts +++ b/noir/compiler/wasm/test/compiler/browser/compile_with_deps.test.ts @@ -2,7 +2,7 @@ import { getPaths } from '../../shared'; import { expect } from '@esm-bundle/chai'; import { compile, createFileManager } from '@noir-lang/noir_wasm'; -import { CompiledContract } from '../../../src/types/noir_artifact'; +import { ContractArtifact } from '../../../src/types/noir_artifact'; import { shouldCompileIdentically } from '../shared/compile_with_deps.test'; const paths = getPaths('.'); @@ -32,7 +32,7 @@ describe('noir-compiler/browser', () => { console.log(path); await fm.writeFile(path, (await getFile(path)).body as ReadableStream); } - const nargoArtifact = (await getPrecompiledSource(contractExpectedArtifact)) as CompiledContract; + const nargoArtifact = (await getPrecompiledSource(contractExpectedArtifact)) as ContractArtifact; const noirWasmArtifact = await compile(fm, '/fixtures/noir-contract'); return { nargoArtifact, noirWasmArtifact }; diff --git a/noir/compiler/wasm/test/compiler/node/compile_with_deps.test.ts b/noir/compiler/wasm/test/compiler/node/compile_with_deps.test.ts index eef9c7e4635..2a402dc9d02 100644 --- a/noir/compiler/wasm/test/compiler/node/compile_with_deps.test.ts +++ b/noir/compiler/wasm/test/compiler/node/compile_with_deps.test.ts @@ -4,7 +4,7 @@ import { getPaths } from '../../shared'; import { expect } from 'chai'; import { compile, createFileManager } from '@noir-lang/noir_wasm'; import { readFile } from 'fs/promises'; -import { CompiledContract } from '../../../src/types/noir_artifact'; +import { ContractArtifact } from '../../../src/types/noir_artifact'; import { shouldCompileIdentically } from '../shared/compile_with_deps.test'; const basePath = resolve(join(__dirname, '../../')); @@ -13,7 +13,7 @@ const { contractProjectPath, contractExpectedArtifact } = getPaths(basePath); describe('noir-compiler/node', () => { shouldCompileIdentically(async () => { const fm = createFileManager(contractProjectPath); - const nargoArtifact = JSON.parse((await readFile(contractExpectedArtifact)).toString()) as CompiledContract; + const nargoArtifact = JSON.parse((await readFile(contractExpectedArtifact)).toString()) as ContractArtifact; const noirWasmArtifact = await compile(fm); return { nargoArtifact, noirWasmArtifact }; }, expect); diff --git a/noir/compiler/wasm/test/compiler/shared/compile_with_deps.test.ts b/noir/compiler/wasm/test/compiler/shared/compile_with_deps.test.ts index 1840912ebe7..0960cba0665 100644 --- a/noir/compiler/wasm/test/compiler/shared/compile_with_deps.test.ts +++ b/noir/compiler/wasm/test/compiler/shared/compile_with_deps.test.ts @@ -1,7 +1,7 @@ import { CompilationResult, inflateDebugSymbols } from '@noir-lang/noir_wasm'; import { type expect as Expect } from 'chai'; import { - CompiledContract, + ContractArtifact, ContractCompilationArtifacts, DebugFileMap, DebugInfo, @@ -9,7 +9,7 @@ import { } from '../../../src/types/noir_artifact'; export function shouldCompileIdentically( - compileFn: () => Promise<{ nargoArtifact: CompiledContract; noirWasmArtifact: CompilationResult }>, + compileFn: () => Promise<{ nargoArtifact: ContractArtifact; noirWasmArtifact: CompilationResult }>, expect: typeof Expect, timeout = 5000, ) { @@ -43,7 +43,7 @@ export function shouldCompileIdentically( } /** Remove commit identifier from version, which may not match depending on cached nargo and noir-wasm */ -function normalizeVersion(contract: CompiledContract) { +function normalizeVersion(contract: ContractArtifact) { contract.noir_version = contract.noir_version.replace(/\+.+$/, ''); } @@ -58,10 +58,10 @@ function extractDebugInfos(fns: NoirFunctionEntry[]) { } /** Deletes all debug info from a contract and returns it. */ -function deleteDebugMetadata(contract: CompiledContract) { +function deleteDebugMetadata(contract: ContractArtifact) { contract.functions.sort((a, b) => a.name.localeCompare(b.name)); const fileMap = contract.file_map; - delete (contract as Partial).file_map; + delete (contract as Partial).file_map; return [extractDebugInfos(contract.functions), fileMap]; }