From 1b1fda19590aef8064691c2a9829b814a466a9ee Mon Sep 17 00:00:00 2001 From: sirasistant Date: Thu, 20 Mar 2025 14:00:35 +0000 Subject: [PATCH 1/3] fix: Disallow registration of contract classes with no bytecode --- avm-transpiler/Cargo.lock | 70 ++++++++++++++++++- avm-transpiler/Cargo.toml | 1 + avm-transpiler/src/transpile_contract.rs | 51 ++++++++++++-- .../src/main.nr | 3 + 4 files changed, 120 insertions(+), 5 deletions(-) diff --git a/avm-transpiler/Cargo.lock b/avm-transpiler/Cargo.lock index 61ebfba95473..6f99cf38d5c0 100644 --- a/avm-transpiler/Cargo.lock +++ b/avm-transpiler/Cargo.lock @@ -329,6 +329,7 @@ dependencies = [ "env_logger", "fxhash", "log", + "noirc_abi", "noirc_errors", "once_cell", "regex", @@ -787,7 +788,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" dependencies = [ "libc", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -1261,6 +1262,21 @@ dependencies = [ "prost", ] +[[package]] +name = "noirc_abi" +version = "1.0.0-beta.3" +dependencies = [ + "acvm", + "iter-extended", + "noirc_printable_type", + "num-bigint", + "num-traits", + "serde", + "serde_json", + "thiserror", + "toml", +] + [[package]] name = "noirc_errors" version = "1.0.0-beta.3" @@ -1692,6 +1708,15 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_spanned" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" +dependencies = [ + "serde", +] + [[package]] name = "serde_with" version = "3.9.0" @@ -1937,6 +1962,40 @@ dependencies = [ "zerovec", ] +[[package]] +name = "toml" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd79e69d3b627db300ff956027cc6c3798cef26d22526befdfcd12feeb6d2257" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", +] + +[[package]] +name = "toml_datetime" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.19.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" +dependencies = [ + "indexmap 2.8.0", + "serde", + "serde_spanned", + "toml_datetime", + "winnow", +] + [[package]] name = "tracing" version = "0.1.40" @@ -2239,6 +2298,15 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" +[[package]] +name = "winnow" +version = "0.5.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" +dependencies = [ + "memchr", +] + [[package]] name = "write16" version = "1.0.0" diff --git a/avm-transpiler/Cargo.toml b/avm-transpiler/Cargo.toml index 63c160ed1118..02bb5aba1100 100644 --- a/avm-transpiler/Cargo.toml +++ b/avm-transpiler/Cargo.toml @@ -11,6 +11,7 @@ license = "MIT OR Apache-2.0" # local acvm = { path = "../noir/noir-repo/acvm-repo/acvm", features = ["bn254"] } noirc_errors = { path = "../noir/noir-repo/compiler/noirc_errors" } +noirc_abi = { path = "../noir/noir-repo/tooling/noirc_abi" } # external base64 = "0.21" diff --git a/avm-transpiler/src/transpile_contract.rs b/avm-transpiler/src/transpile_contract.rs index 6bb30a3adc2e..dbe4c9c1a4bc 100644 --- a/avm-transpiler/src/transpile_contract.rs +++ b/avm-transpiler/src/transpile_contract.rs @@ -4,8 +4,11 @@ use log::info; use serde::{Deserialize, Serialize}; use acvm::acir::circuit::Program; -use noirc_errors::debug_info::ProgramDebugInfo; +use noirc_abi::{Abi, AbiParameter, AbiType}; +use noirc_errors::debug_info::{DebugInfo, ProgramDebugInfo}; +use crate::instructions::{AvmInstruction, AvmOperand}; +use crate::opcodes::AvmOpcode; use crate::transpile::{brillig_to_avm, patch_debug_info_pcs}; use crate::utils::extract_brillig_from_acir_program; @@ -40,7 +43,7 @@ pub struct AvmContractFunctionArtifact { pub name: String, pub is_unconstrained: bool, pub custom_attributes: Vec, - pub abi: serde_json::Value, + pub abi: Abi, pub bytecode: String, // base64 #[serde( serialize_with = "ProgramDebugInfo::serialize_compressed_base64_json", @@ -57,7 +60,7 @@ pub struct AcirContractFunctionArtifact { pub name: String, pub is_unconstrained: bool, pub custom_attributes: Vec, - pub abi: serde_json::Value, + pub abi: Abi, #[serde( serialize_with = "Program::serialize_program_base64", deserialize_with = "Program::deserialize_program_base64" @@ -85,10 +88,13 @@ pub enum AvmOrAcirContractFunctionArtifact { impl From for TranspiledContractArtifact { fn from(contract: CompiledAcirContractArtifact) -> Self { let mut functions: Vec = Vec::new(); + let mut has_public_dispatch = false; for function in contract.functions { if function.custom_attributes.contains(&"public".to_string()) { - // if function.name == "public_dispatch" { + if function.name == "public_dispatch" { + has_public_dispatch = true; + } info!("Transpiling AVM function {} on contract {}", function.name, contract.name); // Extract Brillig Opcodes from acir let acir_program = function.bytecode; @@ -128,6 +134,14 @@ impl From for TranspiledContractArtifact { functions.push(AvmOrAcirContractFunctionArtifact::Acir(function)); } } + + // The AVM currently does not allow executing empty bytecode. In order to avoid this, + // we have disabled registering classes with empty bytecode. This makes it so private only + // contracts need to have public bytecode to be registrable. We inject revert() in those. + if !has_public_dispatch { + functions.push(create_revert_dispatch_fn()); + } + TranspiledContractArtifact { transpiled: true, noir_version: contract.noir_version, @@ -138,3 +152,32 @@ impl From for TranspiledContractArtifact { } } } + +fn create_revert_dispatch_fn() -> AvmOrAcirContractFunctionArtifact { + let revert_bytecode = AvmInstruction { + opcode: AvmOpcode::REVERT_8, + indirect: Some(AvmOperand::U8 { value: 0 }), + operands: vec![AvmOperand::U8 { value: 0 }, AvmOperand::U8 { value: 0 }], + ..Default::default() + } + .to_bytes(); + + let empty_dispatch_fn = AvmContractFunctionArtifact { + name: "public_dispatch".to_string(), + is_unconstrained: true, + custom_attributes: vec!["public".to_string()], + abi: Abi { + parameters: vec![AbiParameter { + name: "selector".to_string(), + typ: AbiType::Field, + visibility: noirc_abi::AbiVisibility::Private, + }], + ..Default::default() + }, + bytecode: base64::prelude::BASE64_STANDARD.encode(revert_bytecode), + debug_symbols: ProgramDebugInfo { debug_infos: vec![DebugInfo::default()] }, + brillig_names: vec!["public_dispatch".to_string()], + }; + + AvmOrAcirContractFunctionArtifact::Avm(empty_dispatch_fn) +} diff --git a/noir-projects/noir-contracts/contracts/contract_class_registerer_contract/src/main.nr b/noir-projects/noir-contracts/contracts/contract_class_registerer_contract/src/main.nr index 1b5ac82bf091..7a182b58cd36 100644 --- a/noir-projects/noir-contracts/contracts/contract_class_registerer_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/contract_class_registerer_contract/src/main.nr @@ -60,6 +60,9 @@ pub contract ContractClassRegisterer { let bytecode_length_in_bytes: u32 = packed_public_bytecode[0] as u32; let bytecode_length_in_fields: u32 = (bytecode_length_in_bytes / 31) + (bytecode_length_in_bytes % 31 != 0) as u32; + // We don't allow registering classes with empty public bytecode. + // Since the AVM doesn't handle execution of empty bytecode at the moment. + assert(bytecode_length_in_fields > 0); assert(bytecode_length_in_fields < MAX_PACKED_PUBLIC_BYTECODE_SIZE_IN_FIELDS); // The first value in the running hash is the bytecode length in bytes From 0e0ea897439fe813f66053e22c13049e8e218520 Mon Sep 17 00:00:00 2001 From: sirasistant Date: Thu, 20 Mar 2025 15:39:53 +0000 Subject: [PATCH 2/3] revert with message --- avm-transpiler/Cargo.lock | 260 +++++++++++++++++- avm-transpiler/Cargo.toml | 1 + avm-transpiler/src/transpile_contract.rs | 54 +++- .../src/public/avm/avm_simulator.test.ts | 29 +- 4 files changed, 331 insertions(+), 13 deletions(-) diff --git a/avm-transpiler/Cargo.lock b/avm-transpiler/Cargo.lock index 6f99cf38d5c0..f5d473b4a95d 100644 --- a/avm-transpiler/Cargo.lock +++ b/avm-transpiler/Cargo.lock @@ -253,6 +253,18 @@ dependencies = [ "syn 2.0.87", ] +[[package]] +name = "ark-grumpkin" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef677b59f5aff4123207c4dceb1c0ec8fdde2d4af7886f48be42ad864bfa0352" +dependencies = [ + "ark-bn254", + "ark-ec", + "ark-ff", + "ark-std", +] + [[package]] name = "ark-poly" version = "0.5.0" @@ -331,6 +343,7 @@ dependencies = [ "log", "noirc_abi", "noirc_errors", + "noirc_evaluator", "once_cell", "regex", "serde", @@ -376,6 +389,12 @@ version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" +[[package]] +name = "binary-merge" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "597bb81c80a54b6a4381b23faba8d7774b144c94cbd1d6fe3f1329bd776554ab" + [[package]] name = "bincode" version = "1.3.3" @@ -391,6 +410,15 @@ version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" +[[package]] +name = "bitmaps" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "031043d04099746d8db04daf1fa424b2bc8bd69d92b25962dcde24da39ab64a2" +dependencies = [ + "typenum", +] + [[package]] name = "blake2" version = "0.10.6" @@ -422,6 +450,21 @@ dependencies = [ "generic-array", ] +[[package]] +name = "bn254_blackbox_solver" +version = "1.0.0-beta.3" +dependencies = [ + "acir", + "acvm_blackbox_solver", + "ark-bn254", + "ark-ec", + "ark-ff", + "ark-grumpkin", + "hex", + "lazy_static", + "num-bigint", +] + [[package]] name = "brillig" version = "1.0.0-beta.3" @@ -482,8 +525,10 @@ checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" dependencies = [ "android-tzdata", "iana-time-zone", + "js-sys", "num-traits", "serde", + "wasm-bindgen", "windows-targets", ] @@ -577,6 +622,25 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "crossbeam-deque" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + [[package]] name = "crossbeam-utils" version = "0.8.21" @@ -817,6 +881,12 @@ dependencies = [ "subtle", ] +[[package]] +name = "fixedbitset" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" + [[package]] name = "fixedbitset" version = "0.5.7" @@ -1114,6 +1184,21 @@ dependencies = [ "icu_properties", ] +[[package]] +name = "im" +version = "15.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0acd33ff0285af998aaf9b57342af478078f53492322fafc47450e09397e0e9" +dependencies = [ + "bitmaps", + "rand_core", + "rand_xoshiro", + "serde", + "sized-chunks", + "typenum", + "version_check", +] + [[package]] name = "indenter" version = "0.3.3" @@ -1142,6 +1227,15 @@ dependencies = [ "serde", ] +[[package]] +name = "inplace-vec-builder" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf64c2edc8226891a71f127587a2861b132d2b942310843814d5001d99a1d307" +dependencies = [ + "smallvec", +] + [[package]] name = "is_terminal_polyfill" version = "1.70.0" @@ -1277,6 +1371,10 @@ dependencies = [ "toml", ] +[[package]] +name = "noirc_arena" +version = "1.0.0-beta.3" + [[package]] name = "noirc_errors" version = "1.0.0-beta.3" @@ -1294,6 +1392,61 @@ dependencies = [ "tracing", ] +[[package]] +name = "noirc_evaluator" +version = "1.0.0-beta.3" +dependencies = [ + "acvm", + "bn254_blackbox_solver", + "cfg-if", + "chrono", + "fxhash", + "im", + "iter-extended", + "noirc_errors", + "noirc_frontend", + "num-bigint", + "num-traits", + "petgraph 0.6.5", + "rayon", + "serde", + "serde_json", + "serde_with", + "smallvec", + "thiserror", + "tracing", + "vec-collections", +] + +[[package]] +name = "noirc_frontend" +version = "1.0.0-beta.3" +dependencies = [ + "acvm", + "bn254_blackbox_solver", + "cfg-if", + "fm", + "fxhash", + "im", + "iter-extended", + "noirc_arena", + "noirc_errors", + "noirc_printable_type", + "num-bigint", + "num-traits", + "petgraph 0.6.5", + "rangemap", + "rustc-hash", + "serde", + "serde_json", + "small-ord-set", + "smol_str", + "strum", + "strum_macros", + "thiserror", + "tracing", +] + [[package]] name = "noirc_printable_type" version = "1.0.0-beta.3" @@ -1380,13 +1533,23 @@ version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" +[[package]] +name = "petgraph" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" +dependencies = [ + "fixedbitset 0.4.2", + "indexmap 2.8.0", +] + [[package]] name = "petgraph" version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3672b37090dbd86368a4145bc067582552b29c27377cad4e0a306c97f9bd7772" dependencies = [ - "fixedbitset", + "fixedbitset 0.5.7", "indexmap 2.8.0", ] @@ -1458,7 +1621,7 @@ dependencies = [ "log", "multimap", "once_cell", - "petgraph", + "petgraph 0.7.1", "prettyplease", "prost", "prost-types", @@ -1537,6 +1700,41 @@ dependencies = [ "getrandom", ] +[[package]] +name = "rand_xoshiro" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f97cdb2a36ed4183de61b2f824cc45c9f1037f28afe0a322e9fff4c108b5aaa" +dependencies = [ + "rand_core", +] + +[[package]] +name = "rangemap" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f60fcc7d6849342eff22c4350c8b9a989ee8ceabc4b481253e8946b9fe83d684" + +[[package]] +name = "rayon" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + [[package]] name = "regex" version = "1.11.1" @@ -1597,6 +1795,12 @@ version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + [[package]] name = "rustix" version = "0.38.34" @@ -1783,11 +1987,48 @@ dependencies = [ "rand_core", ] +[[package]] +name = "sized-chunks" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16d69225bde7a69b235da73377861095455d298f2b970996eec25ddbb42b3d1e" +dependencies = [ + "bitmaps", + "typenum", +] + +[[package]] +name = "small-ord-set" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf7035a2b2268a5be8c1395738565b06beda836097e12021cdefc06b127a0e7e" +dependencies = [ + "smallvec", +] + [[package]] name = "smallvec" version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7fcf8323ef1faaee30a44a340193b1ac6814fd9b7b4e88e9d4519a3e4abe1cfd" +dependencies = [ + "serde", +] + +[[package]] +name = "smol_str" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fad6c857cbab2627dcf01ec85a623ca4e7dcb5691cbaa3d7fb7653671f0d09c9" +dependencies = [ + "serde", +] + +[[package]] +name = "sorted-iter" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bceb57dc07c92cdae60f5b27b3fa92ecaaa42fe36c55e22dbfb0b44893e0b1f7" [[package]] name = "spki" @@ -2123,6 +2364,21 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" +[[package]] +name = "vec-collections" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c9965c8f2ffed1dbcd16cafe18a009642f540fa22661c6cfd6309ddb02e4982" +dependencies = [ + "binary-merge", + "inplace-vec-builder", + "lazy_static", + "num-traits", + "serde", + "smallvec", + "sorted-iter", +] + [[package]] name = "version_check" version = "0.9.4" diff --git a/avm-transpiler/Cargo.toml b/avm-transpiler/Cargo.toml index 02bb5aba1100..574779924c43 100644 --- a/avm-transpiler/Cargo.toml +++ b/avm-transpiler/Cargo.toml @@ -12,6 +12,7 @@ license = "MIT OR Apache-2.0" acvm = { path = "../noir/noir-repo/acvm-repo/acvm", features = ["bn254"] } noirc_errors = { path = "../noir/noir-repo/compiler/noirc_errors" } noirc_abi = { path = "../noir/noir-repo/tooling/noirc_abi" } +noirc_evaluator = { path = "../noir/noir-repo/compiler/noirc_evaluator" } # external base64 = "0.21" diff --git a/avm-transpiler/src/transpile_contract.rs b/avm-transpiler/src/transpile_contract.rs index dbe4c9c1a4bc..006ac7b92dd4 100644 --- a/avm-transpiler/src/transpile_contract.rs +++ b/avm-transpiler/src/transpile_contract.rs @@ -1,13 +1,16 @@ +use std::collections::BTreeMap; + use acvm::FieldElement; use base64::Engine; use log::info; use serde::{Deserialize, Serialize}; use acvm::acir::circuit::Program; -use noirc_abi::{Abi, AbiParameter, AbiType}; +use noirc_abi::{Abi, AbiErrorType, AbiParameter, AbiType}; use noirc_errors::debug_info::{DebugInfo, ProgramDebugInfo}; +use noirc_evaluator::ErrorType; -use crate::instructions::{AvmInstruction, AvmOperand}; +use crate::instructions::{AvmInstruction, AvmOperand, AvmTypeTag}; use crate::opcodes::AvmOpcode; use crate::transpile::{brillig_to_avm, patch_debug_info_pcs}; use crate::utils::extract_brillig_from_acir_program; @@ -154,13 +157,40 @@ impl From for TranspiledContractArtifact { } fn create_revert_dispatch_fn() -> AvmOrAcirContractFunctionArtifact { - let revert_bytecode = AvmInstruction { - opcode: AvmOpcode::REVERT_8, - indirect: Some(AvmOperand::U8 { value: 0 }), - operands: vec![AvmOperand::U8 { value: 0 }, AvmOperand::U8 { value: 0 }], - ..Default::default() - } - .to_bytes(); + let error_string = "No public functions".to_string(); + let error_selector = ErrorType::String(error_string.clone()).selector(); + + let revert_bytecode: Vec = vec![ + // Set revert data len + AvmInstruction { + opcode: AvmOpcode::SET_8, + indirect: Some(AvmOperand::U8 { value: 0 }), // All direct + tag: Some(AvmTypeTag::UINT32), + operands: vec![AvmOperand::U8 { value: 0 }], // Address 0 + immediates: vec![AvmOperand::U8 { value: 1 }], // Value 1 + }, + // Set error selector + AvmInstruction { + opcode: AvmOpcode::SET_64, + indirect: Some(AvmOperand::U8 { value: 0 }), // All direct + tag: Some(AvmTypeTag::UINT64), + operands: vec![AvmOperand::U16 { value: 1 }], // Address 1 + immediates: vec![AvmOperand::U64 { value: error_selector.as_u64() }], // Value selector + }, + // Revert + AvmInstruction { + opcode: AvmOpcode::REVERT_8, + indirect: Some(AvmOperand::U8 { value: 0 }), // All direct + operands: vec![ + AvmOperand::U8 { value: 1 }, // Revert data start address + AvmOperand::U8 { value: 0 }, // Revert data size address + ], + ..Default::default() + }, + ] + .into_iter() + .flat_map(|instruction| instruction.to_bytes()) + .collect(); let empty_dispatch_fn = AvmContractFunctionArtifact { name: "public_dispatch".to_string(), @@ -172,7 +202,11 @@ fn create_revert_dispatch_fn() -> AvmOrAcirContractFunctionArtifact { typ: AbiType::Field, visibility: noirc_abi::AbiVisibility::Private, }], - ..Default::default() + return_type: None, + error_types: BTreeMap::from([( + error_selector, + AbiErrorType::String { string: error_string }, + )]), }, bytecode: base64::prelude::BASE64_STANDARD.encode(revert_bytecode), debug_symbols: ProgramDebugInfo { debug_infos: vec![DebugInfo::default()] }, diff --git a/yarn-project/simulator/src/public/avm/avm_simulator.test.ts b/yarn-project/simulator/src/public/avm/avm_simulator.test.ts index dbbbffdff5cc..320017406781 100644 --- a/yarn-project/simulator/src/public/avm/avm_simulator.test.ts +++ b/yarn-project/simulator/src/public/avm/avm_simulator.test.ts @@ -10,7 +10,8 @@ import { } from '@aztec/foundation/crypto'; import { Fq, Fr, Point } from '@aztec/foundation/fields'; import type { Fieldable } from '@aztec/foundation/serialize'; -import { FunctionSelector } from '@aztec/stdlib/abi'; +import { CounterContract } from '@aztec/noir-contracts.js/Counter'; +import { type FunctionArtifact, FunctionSelector } from '@aztec/stdlib/abi'; import { PublicDataWrite } from '@aztec/stdlib/avm'; import { AztecAddress } from '@aztec/stdlib/aztec-address'; import { SerializableContractInstance, computePublicBytecodeCommitment } from '@aztec/stdlib/contract'; @@ -28,6 +29,7 @@ import { makeContractClassPublic, makeContractInstanceFromClassId } from '@aztec import { MerkleTreeId } from '@aztec/stdlib/trees'; import { NativeWorldStateService } from '@aztec/world-state'; +import { strict as assert } from 'assert'; import { randomInt } from 'crypto'; import { mock } from 'jest-mock-extended'; @@ -43,6 +45,7 @@ import { getAvmGadgetsTestContractBytecode, getAvmTestContractArtifact, getAvmTestContractBytecode, + getContractFunctionArtifact, initContext, initExecutionEnvironment, initGlobalVariables, @@ -52,6 +55,7 @@ import { randomMemoryFields, randomMemoryUint64s, resolveAvmTestContractAssertionMessage, + resolveContractAssertionMessage, } from './fixtures/index.js'; import { SimpleContractDataSource } from './fixtures/simple_contract_data_source.js'; import type { AvmPersistableStateManager } from './journal/journal.js'; @@ -1278,6 +1282,29 @@ describe('AVM simulator: transpiled Noir contracts', () => { }); }); }); + + it('should be able to execute contracts that only have private functions', async () => { + const context = initContext({ env: initExecutionEnvironment({ calldata: [] }) }); + + // Counter contract is a private only contract (no public functions) + const counterDispatch = getContractFunctionArtifact( + 'public_dispatch', + CounterContract.artifact, + ) as FunctionArtifact; + assert(!!counterDispatch?.bytecode); + const results = await new AvmSimulator(context).executeBytecode(counterDispatch.bytecode); + + expect(results.reverted).toBe(true); + expect(results.revertReason).toBeDefined(); + expect( + resolveContractAssertionMessage( + 'public_dispatch', + results.revertReason!, + results.output, + CounterContract.artifact, + ), + ).toMatch('No public functions'); + }); }); function sha256FromMemoryBytes(bytes: Uint8[]): Promise { From 756a7b700c34e0a9f9bdc14090585e8d482375ac Mon Sep 17 00:00:00 2001 From: sirasistant Date: Thu, 20 Mar 2025 16:14:10 +0000 Subject: [PATCH 3/3] use neq instead of gt --- .../contracts/contract_class_registerer_contract/src/main.nr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/noir-projects/noir-contracts/contracts/contract_class_registerer_contract/src/main.nr b/noir-projects/noir-contracts/contracts/contract_class_registerer_contract/src/main.nr index 7a182b58cd36..4e93ec5a3b2b 100644 --- a/noir-projects/noir-contracts/contracts/contract_class_registerer_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/contract_class_registerer_contract/src/main.nr @@ -62,7 +62,7 @@ pub contract ContractClassRegisterer { (bytecode_length_in_bytes / 31) + (bytecode_length_in_bytes % 31 != 0) as u32; // We don't allow registering classes with empty public bytecode. // Since the AVM doesn't handle execution of empty bytecode at the moment. - assert(bytecode_length_in_fields > 0); + assert(bytecode_length_in_fields != 0); assert(bytecode_length_in_fields < MAX_PACKED_PUBLIC_BYTECODE_SIZE_IN_FIELDS); // The first value in the running hash is the bytecode length in bytes