From 3b5f7e02597035314fd2e49e240319b07ce61151 Mon Sep 17 00:00:00 2001 From: Akosh Farkash Date: Tue, 17 Dec 2024 17:44:30 +0000 Subject: [PATCH 01/21] Use jsonrpsee on the client side --- Cargo.lock | 443 ++++++++++++++++++++++- Cargo.toml | 3 +- compiler/noirc_printable_type/Cargo.toml | 2 +- compiler/noirc_printable_type/src/lib.rs | 4 +- cspell.json | 1 + tooling/nargo/Cargo.toml | 6 +- tooling/nargo/src/foreign_calls/rpc.rs | 55 ++- 7 files changed, 483 insertions(+), 31 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4907de7ae62..22cd2f58a14 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -436,6 +436,23 @@ dependencies = [ "waitpid-any", ] +[[package]] +name = "async-trait" +version = "0.1.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", +] + +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + [[package]] name = "autocfg" version = "1.4.0" @@ -729,6 +746,12 @@ dependencies = [ "shlex", ] +[[package]] +name = "cesu8" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" + [[package]] name = "cfg-if" version = "0.1.10" @@ -916,6 +939,16 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" +[[package]] +name = "combine" +version = "4.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" +dependencies = [ + "bytes", + "memchr", +] + [[package]] name = "comma" version = "1.0.0" @@ -997,6 +1030,16 @@ dependencies = [ "unicode-segmentation", ] +[[package]] +name = "core-foundation" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "core-foundation-sys" version = "0.8.7" @@ -1850,6 +1893,25 @@ dependencies = [ "subtle", ] +[[package]] +name = "h2" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccae279728d634d083c00f6099cb58f01cc99c145b84b8be2f6c74618d79922e" +dependencies = [ + "atomic-waker", + "bytes", + "fnv", + "futures-core", + "futures-sink", + "http 1.2.0", + "indexmap 2.6.0", + "slab", + "tokio", + "tokio-util 0.7.12", + "tracing", +] + [[package]] name = "half" version = "2.4.1" @@ -1969,6 +2031,17 @@ dependencies = [ "itoa", ] +[[package]] +name = "http" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f16ca2af56261c99fba8bac40a10251ce8188205a4c448fbb745a2e4daa76fea" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + [[package]] name = "http-body" version = "0.4.6" @@ -1976,7 +2049,30 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" dependencies = [ "bytes", - "http", + "http 0.2.12", + "pin-project-lite", +] + +[[package]] +name = "http-body" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" +dependencies = [ + "bytes", + "http 1.2.0", +] + +[[package]] +name = "http-body-util" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" +dependencies = [ + "bytes", + "futures-util", + "http 1.2.0", + "http-body 1.0.1", "pin-project-lite", ] @@ -2002,8 +2098,8 @@ dependencies = [ "futures-channel", "futures-core", "futures-util", - "http", - "http-body", + "http 0.2.12", + "http-body 0.4.6", "httparse", "httpdate", "itoa", @@ -2015,6 +2111,63 @@ dependencies = [ "want", ] +[[package]] +name = "hyper" +version = "1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "256fb8d4bd6413123cc9d91832d78325c48ff41677595be797d90f42969beae0" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "h2", + "http 1.2.0", + "http-body 1.0.1", + "httparse", + "itoa", + "pin-project-lite", + "smallvec", + "tokio", + "want", +] + +[[package]] +name = "hyper-rustls" +version = "0.27.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08afdbb5c31130e3034af566421053ab03787c640246a446327f550d11bcb333" +dependencies = [ + "futures-util", + "http 1.2.0", + "hyper 1.5.2", + "hyper-util", + "log", + "rustls", + "rustls-pki-types", + "tokio", + "tokio-rustls", + "tower-service", +] + +[[package]] +name = "hyper-util" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df2dcfbe0677734ab2f3ffa7fa7bfd4706bfdc1ef393f2ee30184aed67e631b4" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "http 1.2.0", + "http-body 1.0.1", + "hyper 1.5.2", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", +] + [[package]] name = "iai" version = "0.1.1" @@ -2371,6 +2524,26 @@ version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" +[[package]] +name = "jni" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6df18c2e3db7e453d3c6ac5b3e9d5182664d28788126d39b91f2d1e22b017ec" +dependencies = [ + "cesu8", + "combine", + "jni-sys", + "log", + "thiserror", + "walkdir", +] + +[[package]] +name = "jni-sys" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" + [[package]] name = "js-sys" version = "0.3.63" @@ -2452,7 +2625,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e1dea6e07251d9ce6a552abfb5d7ad6bc290a4596c8dcc3d795fae2bbdc1f3ff" dependencies = [ "futures 0.3.31", - "hyper", + "hyper 0.14.31", "jsonrpc-core", "jsonrpc-server-utils", "log", @@ -2494,6 +2667,74 @@ dependencies = [ "unicase", ] +[[package]] +name = "jsonrpsee" +version = "0.24.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5c71d8c1a731cc4227c2f698d377e7848ca12c8a48866fc5e6951c43a4db843" +dependencies = [ + "jsonrpsee-core", + "jsonrpsee-http-client", + "jsonrpsee-types", +] + +[[package]] +name = "jsonrpsee-core" +version = "0.24.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2882f6f8acb9fdaec7cefc4fd607119a9bd709831df7d7672a1d3b644628280" +dependencies = [ + "async-trait", + "bytes", + "futures-util", + "http 1.2.0", + "http-body 1.0.1", + "http-body-util", + "jsonrpsee-types", + "serde", + "serde_json", + "thiserror", + "tokio", + "tracing", +] + +[[package]] +name = "jsonrpsee-http-client" +version = "0.24.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3638bc4617f96675973253b3a45006933bde93c2fd8a6170b33c777cc389e5b" +dependencies = [ + "async-trait", + "base64 0.22.1", + "http-body 1.0.1", + "hyper 1.5.2", + "hyper-rustls", + "hyper-util", + "jsonrpsee-core", + "jsonrpsee-types", + "rustls", + "rustls-platform-verifier", + "serde", + "serde_json", + "thiserror", + "tokio", + "tower", + "tracing", + "url 2.5.4", +] + +[[package]] +name = "jsonrpsee-types" +version = "0.24.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a178c60086f24cc35bb82f57c651d0d25d99c4742b4d335de04e97fa1f08a8a1" +dependencies = [ + "http 1.2.0", + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "jubjub" version = "0.9.0" @@ -2783,6 +3024,7 @@ dependencies = [ "jsonrpc-core-client", "jsonrpc-derive", "jsonrpc-http-server", + "jsonrpsee", "noir_fuzzer", "noirc_abi", "noirc_driver", @@ -2794,6 +3036,7 @@ dependencies = [ "rayon", "serde", "thiserror", + "tokio", "tracing", "walkdir", ] @@ -3227,7 +3470,7 @@ version = "1.0.0-beta.0" dependencies = [ "acvm", "iter-extended", - "jsonrpc", + "jsonrpsee", "serde", "serde_json", "thiserror", @@ -3364,6 +3607,12 @@ version = "11.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b410bbe7e14ab526a0e86877eb47c6996a2bd7746f027ba551028c925390e4e9" +[[package]] +name = "openssl-probe" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" + [[package]] name = "overload" version = "0.1.1" @@ -3546,6 +3795,26 @@ dependencies = [ "siphasher", ] +[[package]] +name = "pin-project" +version = "1.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be57f64e946e500c8ee36ef6331845d40a93055567ec57e8fae13efd33759b95" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c0f5fad0874fc7abcd4d750e76917eaebbecaa2c20bde22e1dbeeba8beb758c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", +] + [[package]] name = "pin-project-lite" version = "0.2.15" @@ -4037,6 +4306,21 @@ dependencies = [ "bytemuck", ] +[[package]] +name = "ring" +version = "0.17.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" +dependencies = [ + "cc", + "cfg-if 1.0.0", + "getrandom 0.2.15", + "libc", + "spin", + "untrusted", + "windows-sys 0.52.0", +] + [[package]] name = "rust-embed" version = "6.8.1" @@ -4105,6 +4389,87 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "rustls" +version = "0.23.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5065c3f250cbd332cd894be57c40fa52387247659b14a2d6041d121547903b1b" +dependencies = [ + "log", + "once_cell", + "ring", + "rustls-pki-types", + "rustls-webpki", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls-native-certs" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5bfb394eeed242e909609f56089eecfe5fda225042e8b171791b9c95f5931e5" +dependencies = [ + "openssl-probe", + "rustls-pemfile", + "rustls-pki-types", + "schannel", + "security-framework", +] + +[[package]] +name = "rustls-pemfile" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" +dependencies = [ + "rustls-pki-types", +] + +[[package]] +name = "rustls-pki-types" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2bf47e6ff922db3825eb750c4e2ff784c6ff8fb9e13046ef6a1d1c5401b0b37" + +[[package]] +name = "rustls-platform-verifier" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "afbb878bdfdf63a336a5e63561b1835e7a8c91524f51621db870169eac84b490" +dependencies = [ + "core-foundation", + "core-foundation-sys", + "jni", + "log", + "once_cell", + "rustls", + "rustls-native-certs", + "rustls-platform-verifier-android", + "rustls-webpki", + "security-framework", + "security-framework-sys", + "webpki-roots", + "winapi", +] + +[[package]] +name = "rustls-platform-verifier-android" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f" + +[[package]] +name = "rustls-webpki" +version = "0.102.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9" +dependencies = [ + "ring", + "rustls-pki-types", + "untrusted", +] + [[package]] name = "rustversion" version = "1.0.18" @@ -4225,6 +4590,15 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "schannel" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d" +dependencies = [ + "windows-sys 0.59.0", +] + [[package]] name = "scoped-tls" version = "1.0.1" @@ -4251,6 +4625,30 @@ dependencies = [ "zeroize", ] +[[package]] +name = "security-framework" +version = "2.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" +dependencies = [ + "bitflags 2.6.0", + "core-foundation", + "core-foundation-sys", + "libc", + "num-bigint", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa39c7303dc58b5543c94d22c1766b0d31f2ee58306363ea622b10bbc075eaa2" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "semver" version = "1.0.23" @@ -4862,9 +5260,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.41.1" +version = "1.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22cfb5bee7a6a52939ca9224d6ac897bb669134078daa8735560897f69de4d33" +checksum = "5cec9b21b0450273377fc97bd4c33a8acffc8c996c987a7c5b319a0083707551" dependencies = [ "backtrace", "bytes", @@ -4887,6 +5285,16 @@ dependencies = [ "syn 2.0.87", ] +[[package]] +name = "tokio-rustls" +version = "0.26.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f6d0975eaace0cf0fcadee4e4aaa5da15b5c079146f2cffb67c113be122bf37" +dependencies = [ + "rustls", + "tokio", +] + [[package]] name = "tokio-stream" version = "0.1.16" @@ -4975,6 +5383,10 @@ version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" dependencies = [ + "futures-core", + "futures-util", + "pin-project", + "pin-project-lite", "tower-layer", "tower-service", "tracing", @@ -5188,6 +5600,12 @@ version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + [[package]] name = "url" version = "1.7.2" @@ -5399,6 +5817,15 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "webpki-roots" +version = "0.26.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d642ff16b7e79272ae451b7322067cdc17cadf68c23264be9d94a32319efe7e" +dependencies = [ + "rustls-pki-types", +] + [[package]] name = "winapi" version = "0.3.9" @@ -5421,7 +5848,7 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ - "windows-sys 0.48.0", + "windows-sys 0.59.0", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 0acee2a040b..6e70dd1c552 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -149,6 +149,7 @@ similar-asserts = "1.5.0" tempfile = "3.6.0" test-case = "3.3.1" jsonrpc = { version = "0.16.0", features = ["minreq_http"] } +jsonrpsee = { version = "0.24.7", features = ["http-client"] } flate2 = "1.0.24" color-eyre = "0.6.2" rand = "0.8.5" @@ -159,7 +160,7 @@ sha2 = { version = "0.10.6", features = ["compress"] } sha3 = "0.10.6" strum = "0.24" strum_macros = "0.24" - +tokio = { version = "1.42", features = ["rt"] } im = { version = "15.1", features = ["serde"] } tracing = "0.1.40" tracing-web = "0.1.3" diff --git a/compiler/noirc_printable_type/Cargo.toml b/compiler/noirc_printable_type/Cargo.toml index 8d0574aad64..bb965d12c4e 100644 --- a/compiler/noirc_printable_type/Cargo.toml +++ b/compiler/noirc_printable_type/Cargo.toml @@ -17,6 +17,6 @@ iter-extended.workspace = true serde.workspace = true serde_json.workspace = true thiserror.workspace = true -jsonrpc.workspace = true +jsonrpsee.workspace = true [dev-dependencies] diff --git a/compiler/noirc_printable_type/src/lib.rs b/compiler/noirc_printable_type/src/lib.rs index 6ae187da27f..f85dfcc8e1e 100644 --- a/compiler/noirc_printable_type/src/lib.rs +++ b/compiler/noirc_printable_type/src/lib.rs @@ -79,9 +79,9 @@ pub enum ForeignCallError { ParsingError(#[from] serde_json::Error), #[error("Failed calling external resolver. {0}")] - ExternalResolverError(#[from] jsonrpc::Error), + ExternalResolverError(#[from] jsonrpsee::core::client::Error), - #[error("Assert message resolved after an unsatisified constrain. {0}")] + #[error("Assert message resolved after an unsatisfied constrain. {0}")] ResolvedAssertMessage(String), } diff --git a/cspell.json b/cspell.json index 9a4bca1e339..9a69bd1a4e0 100644 --- a/cspell.json +++ b/cspell.json @@ -126,6 +126,7 @@ "jmpifs", "jmps", "jsdoc", + "jsonrpsee", "Jubjub", "keccak", "keccakf", diff --git a/tooling/nargo/Cargo.toml b/tooling/nargo/Cargo.toml index 1dbb9978b0b..e50ae4b101b 100644 --- a/tooling/nargo/Cargo.toml +++ b/tooling/nargo/Cargo.toml @@ -21,10 +21,11 @@ noirc_errors.workspace = true noirc_frontend.workspace = true noirc_printable_type.workspace = true iter-extended.workspace = true +rayon.workspace = true thiserror.workspace = true +tokio.workspace = true tracing.workspace = true -rayon.workspace = true -jsonrpc.workspace = true +jsonrpsee.workspace = true rand.workspace = true serde.workspace = true walkdir = "2.5.0" @@ -34,6 +35,7 @@ noir_fuzzer.workspace = true proptest.workspace = true [dev-dependencies] +jsonrpc.workspace = true jsonrpc-http-server = "18.0" jsonrpc-core-client = "18.0" jsonrpc-derive = "18.0" diff --git a/tooling/nargo/src/foreign_calls/rpc.rs b/tooling/nargo/src/foreign_calls/rpc.rs index 0653eb1c7e3..cab88d98da0 100644 --- a/tooling/nargo/src/foreign_calls/rpc.rs +++ b/tooling/nargo/src/foreign_calls/rpc.rs @@ -1,7 +1,11 @@ use std::path::PathBuf; use acvm::{acir::brillig::ForeignCallResult, pwg::ForeignCallWaitInfo, AcirField}; -use jsonrpc::{arg as build_json_rpc_arg, minreq_http::Builder, Client}; +use jsonrpsee::{ + core::client::ClientT, + http_client::{HttpClient, HttpClientBuilder}, + rpc_params, +}; use noirc_printable_type::ForeignCallError; use serde::{Deserialize, Serialize}; @@ -15,11 +19,14 @@ pub(crate) struct RPCForeignCallExecutor { /// instantiations of `DefaultForeignCallExecutor`. id: u64, /// JSON RPC client to resolve foreign calls - external_resolver: Client, + external_resolver: HttpClient, /// Root path to the program or workspace in execution. root_path: Option, /// Name of the package in execution package_name: Option, + /// Runtime to execute asynchronous tasks on. + /// See [bridging](https://tokio.rs/tokio/topics/bridging). + rt: tokio::runtime::Runtime, } #[derive(Debug, Serialize, Deserialize)] @@ -31,15 +38,16 @@ struct ResolveForeignCallRequest { /// performed in parallel. session_id: u64, - #[serde(flatten)] /// The foreign call which the external RPC server is to provide a response for. + #[serde(flatten)] function_call: ForeignCallWaitInfo, - #[serde(skip_serializing_if = "Option::is_none")] /// Root path to the program or workspace in execution. - root_path: Option, #[serde(skip_serializing_if = "Option::is_none")] + root_path: Option, + /// Name of the package in execution + #[serde(skip_serializing_if = "Option::is_none")] package_name: Option, } @@ -50,18 +58,33 @@ impl RPCForeignCallExecutor { root_path: Option, package_name: Option, ) -> Self { - let mut transport_builder = - Builder::new().url(resolver_url).expect("Invalid oracle resolver URL"); + let mut client_builder = HttpClientBuilder::new(); if let Some(Ok(timeout)) = std::env::var("NARGO_FOREIGN_CALL_TIMEOUT").ok().map(|timeout| timeout.parse()) { let timeout_duration = std::time::Duration::from_millis(timeout); - transport_builder = transport_builder.timeout(timeout_duration); + client_builder = client_builder.request_timeout(timeout_duration); }; - let oracle_resolver = Client::with_transport(transport_builder.build()); - RPCForeignCallExecutor { external_resolver: oracle_resolver, id, root_path, package_name } + let oracle_resolver = + client_builder.build(resolver_url).expect("Invalid oracle resolver URL"); + + // Opcodes are executed in the `ProgramExecutor::execute_circuit` one by one in a loop, + // we don't need a concurrent thread pool. + let rt = tokio::runtime::Builder::new_current_thread() + .enable_time() + .enable_io() + .build() + .expect("failed to build tokio runtime"); + + RPCForeignCallExecutor { + external_resolver: oracle_resolver, + id, + root_path, + package_name, + rt, + } } } @@ -72,18 +95,16 @@ impl Deserialize<'a>> ForeignCallExecutor &mut self, foreign_call: &ForeignCallWaitInfo, ) -> Result, ForeignCallError> { - let encoded_params = vec![build_json_rpc_arg(ResolveForeignCallRequest { + let encoded_params = rpc_params!(ResolveForeignCallRequest { session_id: self.id, function_call: foreign_call.clone(), root_path: self.root_path.clone().map(|path| path.to_str().unwrap().to_string()), package_name: self.package_name.clone(), - })]; - - let req = self.external_resolver.build_request("resolve_foreign_call", &encoded_params); - - let response = self.external_resolver.send_request(req)?; + }); - let parsed_response: ForeignCallResult = response.result()?; + let parsed_response = self + .rt + .block_on(self.external_resolver.request("resolve_foreign_call", encoded_params))?; Ok(parsed_response) } From 159bcbc4fcc0cfec415f585c25ac220a077d4be4 Mon Sep 17 00:00:00 2001 From: Akosh Farkash Date: Tue, 17 Dec 2024 20:17:33 +0000 Subject: [PATCH 02/21] Rewrite the test to use jsonrpsee --- Cargo.lock | 771 +++++++------------------ Cargo.toml | 5 +- cspell.json | 1 + tooling/nargo/Cargo.toml | 6 +- tooling/nargo/src/foreign_calls/rpc.rs | 162 ++++-- 5 files changed, 324 insertions(+), 621 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 22cd2f58a14..44e999f8cde 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -31,7 +31,7 @@ dependencies = [ "ark-bls12-381", "ark-bn254", "ark-ff", - "cfg-if 1.0.0", + "cfg-if", "hex", "num-bigint", "proptest", @@ -88,9 +88,9 @@ dependencies = [ "nargo", "paste", "proptest", - "rand 0.8.5", + "rand", "thiserror", - "toml 0.7.8", + "toml", "tracing-appender", "tracing-subscriber", ] @@ -104,7 +104,7 @@ dependencies = [ "build-data", "console_error_panic_hook", "const-str", - "getrandom 0.2.15", + "getrandom", "gloo-utils", "js-sys", "pkg-config", @@ -143,8 +143,8 @@ version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" dependencies = [ - "cfg-if 1.0.0", - "getrandom 0.2.15", + "cfg-if", + "getrandom", "once_cell", "version_check", "zerocopy", @@ -370,7 +370,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94893f1e0c6eeab764ade8dc4c0db24caf4fe7cbbaafc0eba0a9030f447b5185" dependencies = [ "num-traits", - "rand 0.8.5", + "rand", ] [[package]] @@ -422,7 +422,7 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "138985dd8aefbefeaa66b01b7f5b2b6b4c333fcef1cc5f32c63a2aabe37d6de3" dependencies = [ - "futures 0.3.31", + "futures", "lsp-types 0.94.1", "pin-project-lite", "rustix", @@ -467,7 +467,7 @@ checksum = "26b05800d2e817c8b3b4b54abd461726265fa9789ae34330622f2db9ee696f9d" dependencies = [ "addr2line", "cc", - "cfg-if 1.0.0", + "cfg-if", "libc", "miniz_oxide 0.7.4", "object", @@ -480,12 +480,6 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "349a06037c7bf932dd7e7d1f653678b2038b9ad46a74102f1fc7bd7872678cce" -[[package]] -name = "base64" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" - [[package]] name = "base64" version = "0.21.7" @@ -590,7 +584,7 @@ dependencies = [ "arrayref", "arrayvec", "cc", - "cfg-if 1.0.0", + "cfg-if", "constant_time_eq", ] @@ -612,7 +606,7 @@ dependencies = [ "ff 0.12.1", "group 0.12.1", "pairing", - "rand_core 0.6.4", + "rand_core", "subtle", ] @@ -752,12 +746,6 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" -[[package]] -name = "cfg-if" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" - [[package]] name = "cfg-if" version = "1.0.0" @@ -892,7 +880,7 @@ checksum = "fc4159b76af02757139baf42c0c971c6dc155330999fbfd8eddb29b97fb2db68" dependencies = [ "codespan-reporting", "lsp-types 0.88.0", - "url 2.5.4", + "url", ] [[package]] @@ -973,7 +961,7 @@ version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "wasm-bindgen", ] @@ -1015,12 +1003,6 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6" -[[package]] -name = "convert_case" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" - [[package]] name = "convert_case" version = "0.6.0" @@ -1052,7 +1034,7 @@ version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96e58d342ad113c2b878f16d5d034c03be492ae460cdbc02b7f0f2284d310c7d" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", ] [[package]] @@ -1070,7 +1052,7 @@ version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", ] [[package]] @@ -1156,7 +1138,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef2b4b23cddf68b89b8f8069890e8c270d54e2d5fe1b143820234805e4cb17ef" dependencies = [ "generic-array", - "rand_core 0.6.4", + "rand_core", "subtle", "zeroize", ] @@ -1244,12 +1226,12 @@ version = "6.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5041cc499144891f3790297212f32a74fb938e5136a14943f338ef9e0ae276cf" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "crossbeam-utils", "hashbrown 0.14.5", "lock_api", "once_cell", - "parking_lot_core 0.9.10", + "parking_lot_core", ] [[package]] @@ -1292,19 +1274,6 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "derive_more" -version = "0.99.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f33878137e4dafd7fa914ad4e259e18a4e8e532b9617a2d0150262bf53abfce" -dependencies = [ - "convert_case 0.4.0", - "proc-macro2", - "quote", - "rustc_version", - "syn 2.0.87", -] - [[package]] name = "difflib" version = "0.4.0" @@ -1337,7 +1306,7 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "dirs-sys-next", ] @@ -1427,7 +1396,7 @@ dependencies = [ "generic-array", "group 0.12.1", "pkcs8", - "rand_core 0.6.4", + "rand_core", "sec1", "subtle", "zeroize", @@ -1538,7 +1507,7 @@ version = "3.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef033ed5e9bad94e55838ca0ca906db0e043f517adda0c8b79c7a8c66c93c1b5" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "rustix", "windows-sys 0.48.0", ] @@ -1550,7 +1519,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d013fc25338cc558c5c2cfbad646908fb23591e2404481826742b651c9af7160" dependencies = [ "bitvec", - "rand_core 0.6.4", + "rand_core", "subtle", ] @@ -1561,7 +1530,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" dependencies = [ "bitvec", - "rand_core 0.6.4", + "rand_core", "subtle", ] @@ -1599,7 +1568,7 @@ version = "0.2.25" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "35c0522e981e68cbfa8c3f978441a5f34b30b96e146b33cd3359176b50fe8586" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "libc", "libredox 0.1.3", "windows-sys 0.59.0", @@ -1663,7 +1632,7 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" dependencies = [ - "percent-encoding 2.3.1", + "percent-encoding", ] [[package]] @@ -1681,12 +1650,6 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" -[[package]] -name = "futures" -version = "0.1.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a471a38ef8ed83cd6e40aa59c1ffe17db6855c18e3604d9c4ed8c08ebc28678" - [[package]] name = "futures" version = "0.3.31" @@ -1695,7 +1658,6 @@ checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" dependencies = [ "futures-channel", "futures-core", - "futures-executor", "futures-io", "futures-sink", "futures-task", @@ -1718,18 +1680,6 @@ version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" -[[package]] -name = "futures-executor" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" -dependencies = [ - "futures-core", - "futures-task", - "futures-util", - "num_cpus", -] - [[package]] name = "futures-io" version = "0.3.31" @@ -1765,7 +1715,6 @@ version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" dependencies = [ - "futures 0.1.31", "futures-channel", "futures-core", "futures-io", @@ -1797,27 +1746,16 @@ dependencies = [ "version_check", ] -[[package]] -name = "getrandom" -version = "0.1.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" -dependencies = [ - "cfg-if 1.0.0", - "libc", - "wasi 0.9.0+wasi-snapshot-preview1", -] - [[package]] name = "getrandom" version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "js-sys", "libc", - "wasi 0.11.0+wasi-snapshot-preview1", + "wasi", "wasm-bindgen", ] @@ -1878,7 +1816,7 @@ checksum = "5dfbfb3a6cfbd390d5c9564ab283a0349b9b9fcd46a706c1eb10e0db70bfbac7" dependencies = [ "ff 0.12.1", "memuse", - "rand_core 0.6.4", + "rand_core", "subtle", ] @@ -1889,7 +1827,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" dependencies = [ "ff 0.13.0", - "rand_core 0.6.4", + "rand_core", "subtle", ] @@ -1904,11 +1842,11 @@ dependencies = [ "fnv", "futures-core", "futures-sink", - "http 1.2.0", + "http", "indexmap 2.6.0", "slab", "tokio", - "tokio-util 0.7.12", + "tokio-util", "tracing", ] @@ -1918,7 +1856,7 @@ version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "crunchy", ] @@ -1941,7 +1879,7 @@ dependencies = [ "ff 0.12.1", "group 0.12.1", "pasta_curves 0.4.1", - "rand_core 0.6.4", + "rand_core", "rayon", ] @@ -2020,17 +1958,6 @@ dependencies = [ "digest", ] -[[package]] -name = "http" -version = "0.2.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" -dependencies = [ - "bytes", - "fnv", - "itoa", -] - [[package]] name = "http" version = "1.2.0" @@ -2042,17 +1969,6 @@ dependencies = [ "itoa", ] -[[package]] -name = "http-body" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" -dependencies = [ - "bytes", - "http 0.2.12", - "pin-project-lite", -] - [[package]] name = "http-body" version = "1.0.1" @@ -2060,7 +1976,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" dependencies = [ "bytes", - "http 1.2.0", + "http", ] [[package]] @@ -2071,8 +1987,8 @@ checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" dependencies = [ "bytes", "futures-util", - "http 1.2.0", - "http-body 1.0.1", + "http", + "http-body", "pin-project-lite", ] @@ -2088,29 +2004,6 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" -[[package]] -name = "hyper" -version = "0.14.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c08302e8fa335b151b788c775ff56e7a03ae64ff85c548ee820fecb70356e85" -dependencies = [ - "bytes", - "futures-channel", - "futures-core", - "futures-util", - "http 0.2.12", - "http-body 0.4.6", - "httparse", - "httpdate", - "itoa", - "pin-project-lite", - "socket2", - "tokio", - "tower-service", - "tracing", - "want", -] - [[package]] name = "hyper" version = "1.5.2" @@ -2121,9 +2014,10 @@ dependencies = [ "futures-channel", "futures-util", "h2", - "http 1.2.0", - "http-body 1.0.1", + "http", + "http-body", "httparse", + "httpdate", "itoa", "pin-project-lite", "smallvec", @@ -2138,8 +2032,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08afdbb5c31130e3034af566421053ab03787c640246a446327f550d11bcb333" dependencies = [ "futures-util", - "http 1.2.0", - "hyper 1.5.2", + "http", + "hyper", "hyper-util", "log", "rustls", @@ -2158,9 +2052,9 @@ dependencies = [ "bytes", "futures-channel", "futures-util", - "http 1.2.0", - "http-body 1.0.1", - "hyper 1.5.2", + "http", + "http-body", + "hyper", "pin-project-lite", "socket2", "tokio", @@ -2321,17 +2215,6 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" -[[package]] -name = "idna" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e" -dependencies = [ - "matches", - "unicode-bidi", - "unicode-normalization", -] - [[package]] name = "idna" version = "1.0.3" @@ -2376,7 +2259,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d0acd33ff0285af998aaf9b57342af478078f53492322fafc47450e09397e0e9" dependencies = [ "bitmaps", - "rand_core 0.6.4", + "rand_core", "rand_xoshiro", "serde", "sized-chunks", @@ -2479,15 +2362,6 @@ dependencies = [ "libc", ] -[[package]] -name = "instant" -version = "0.1.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" -dependencies = [ - "cfg-if 1.0.0", -] - [[package]] name = "is-terminal" version = "0.4.13" @@ -2553,120 +2427,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "jsonrpc" -version = "0.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34efde8d2422fb79ed56db1d3aea8fa5b583351d15a26770cdee2f88813dd702" -dependencies = [ - "base64 0.13.1", - "minreq", - "serde", - "serde_json", -] - -[[package]] -name = "jsonrpc-client-transports" -version = "18.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2b99d4207e2a04fb4581746903c2bb7eb376f88de9c699d0f3e10feeac0cd3a" -dependencies = [ - "derive_more", - "futures 0.3.31", - "jsonrpc-core", - "jsonrpc-pubsub", - "log", - "serde", - "serde_json", - "url 1.7.2", -] - -[[package]] -name = "jsonrpc-core" -version = "18.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14f7f76aef2d054868398427f6c54943cf3d1caa9a7ec7d0c38d69df97a965eb" -dependencies = [ - "futures 0.3.31", - "futures-executor", - "futures-util", - "log", - "serde", - "serde_derive", - "serde_json", -] - -[[package]] -name = "jsonrpc-core-client" -version = "18.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b51da17abecbdab3e3d4f26b01c5ec075e88d3abe3ab3b05dc9aa69392764ec0" -dependencies = [ - "futures 0.3.31", - "jsonrpc-client-transports", -] - -[[package]] -name = "jsonrpc-derive" -version = "18.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b939a78fa820cdfcb7ee7484466746a7377760970f6f9c6fe19f9edcc8a38d2" -dependencies = [ - "proc-macro-crate", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "jsonrpc-http-server" -version = "18.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1dea6e07251d9ce6a552abfb5d7ad6bc290a4596c8dcc3d795fae2bbdc1f3ff" -dependencies = [ - "futures 0.3.31", - "hyper 0.14.31", - "jsonrpc-core", - "jsonrpc-server-utils", - "log", - "net2", - "parking_lot 0.11.2", - "unicase", -] - -[[package]] -name = "jsonrpc-pubsub" -version = "18.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "240f87695e6c6f62fb37f05c02c04953cf68d6408b8c1c89de85c7a0125b1011" -dependencies = [ - "futures 0.3.31", - "jsonrpc-core", - "lazy_static", - "log", - "parking_lot 0.11.2", - "rand 0.7.3", - "serde", -] - -[[package]] -name = "jsonrpc-server-utils" -version = "18.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa4fdea130485b572c39a460d50888beb00afb3e35de23ccd7fad8ff19f0e0d4" -dependencies = [ - "bytes", - "futures 0.3.31", - "globset", - "jsonrpc-core", - "lazy_static", - "log", - "tokio", - "tokio-stream", - "tokio-util 0.6.10", - "unicase", -] - [[package]] name = "jsonrpsee" version = "0.24.7" @@ -2675,7 +2435,11 @@ checksum = "c5c71d8c1a731cc4227c2f698d377e7848ca12c8a48866fc5e6951c43a4db843" dependencies = [ "jsonrpsee-core", "jsonrpsee-http-client", + "jsonrpsee-proc-macros", + "jsonrpsee-server", "jsonrpsee-types", + "tokio", + "tracing", ] [[package]] @@ -2687,10 +2451,13 @@ dependencies = [ "async-trait", "bytes", "futures-util", - "http 1.2.0", - "http-body 1.0.1", + "http", + "http-body", "http-body-util", "jsonrpsee-types", + "parking_lot", + "rand", + "rustc-hash 2.1.0", "serde", "serde_json", "thiserror", @@ -2706,8 +2473,8 @@ checksum = "b3638bc4617f96675973253b3a45006933bde93c2fd8a6170b33c777cc389e5b" dependencies = [ "async-trait", "base64 0.22.1", - "http-body 1.0.1", - "hyper 1.5.2", + "http-body", + "hyper", "hyper-rustls", "hyper-util", "jsonrpsee-core", @@ -2720,7 +2487,47 @@ dependencies = [ "tokio", "tower", "tracing", - "url 2.5.4", + "url", +] + +[[package]] +name = "jsonrpsee-proc-macros" +version = "0.24.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c06c01ae0007548e73412c08e2285ffe5d723195bf268bce67b1b77c3bb2a14d" +dependencies = [ + "heck 0.5.0", + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 2.0.87", +] + +[[package]] +name = "jsonrpsee-server" +version = "0.24.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82ad8ddc14be1d4290cd68046e7d1d37acd408efed6d3ca08aefcc3ad6da069c" +dependencies = [ + "futures-util", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-util", + "jsonrpsee-core", + "jsonrpsee-types", + "pin-project", + "route-recognizer", + "serde", + "serde_json", + "soketto", + "thiserror", + "tokio", + "tokio-stream", + "tokio-util", + "tower", + "tracing", ] [[package]] @@ -2729,7 +2536,7 @@ version = "0.24.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a178c60086f24cc35bb82f57c651d0d25d99c4742b4d335de04e97fa1f08a8a1" dependencies = [ - "http 1.2.0", + "http", "serde", "serde_json", "thiserror", @@ -2745,7 +2552,7 @@ dependencies = [ "bls12_381", "ff 0.12.1", "group 0.12.1", - "rand_core 0.6.4", + "rand_core", "subtle", ] @@ -2755,7 +2562,7 @@ version = "0.11.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72c1e0b51e7ec0a97369623508396067a486bd0cbed95a2659a4b863d28cfc8b" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "ecdsa", "elliptic-curve", "sha2", @@ -2898,7 +2705,7 @@ dependencies = [ "serde", "serde_json", "serde_repr", - "url 2.5.4", + "url", ] [[package]] @@ -2911,7 +2718,7 @@ dependencies = [ "serde", "serde_json", "serde_repr", - "url 2.5.4", + "url", ] [[package]] @@ -2923,12 +2730,6 @@ dependencies = [ "regex-automata 0.1.10", ] -[[package]] -name = "matches" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5" - [[package]] name = "memchr" version = "2.7.4" @@ -2977,17 +2778,6 @@ dependencies = [ "adler2", ] -[[package]] -name = "minreq" -version = "2.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "763d142cdff44aaadd9268bebddb156ef6c65a0e13486bb81673cf2d8739f9b0" -dependencies = [ - "log", - "serde", - "serde_json", -] - [[package]] name = "mio" version = "0.8.11" @@ -2996,7 +2786,7 @@ checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" dependencies = [ "libc", "log", - "wasi 0.11.0+wasi-snapshot-preview1", + "wasi", "windows-sys 0.48.0", ] @@ -3008,7 +2798,7 @@ checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec" dependencies = [ "hermit-abi 0.3.9", "libc", - "wasi 0.11.0+wasi-snapshot-preview1", + "wasi", "windows-sys 0.52.0", ] @@ -3019,11 +2809,6 @@ dependencies = [ "acvm", "fm", "iter-extended", - "jsonrpc", - "jsonrpc-core", - "jsonrpc-core-client", - "jsonrpc-derive", - "jsonrpc-http-server", "jsonrpsee", "noir_fuzzer", "noirc_abi", @@ -3032,7 +2817,7 @@ dependencies = [ "noirc_frontend", "noirc_printable_type", "proptest", - "rand 0.8.5", + "rand", "rayon", "serde", "thiserror", @@ -3097,8 +2882,8 @@ dependencies = [ "test-case", "thiserror", "tokio", - "tokio-util 0.7.12", - "toml 0.7.8", + "tokio-util", + "toml", "tower", "tracing-appender", "tracing-subscriber", @@ -3112,7 +2897,7 @@ dependencies = [ "serde", "similar-asserts", "thiserror", - "toml 0.7.8", + "toml", ] [[package]] @@ -3129,19 +2914,8 @@ dependencies = [ "tempfile", "test-case", "thiserror", - "toml 0.7.8", - "url 2.5.4", -] - -[[package]] -name = "net2" -version = "0.2.39" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b13b648036a2339d06de780866fbdfda0dde886de7b3af2ddeba8b14f4ee34ac" -dependencies = [ - "cfg-if 0.1.10", - "libc", - "winapi", + "toml", + "url", ] [[package]] @@ -3161,7 +2935,7 @@ checksum = "8f3790c00a0150112de0f4cd161e3d7fc4b2d8a5542ffc35f099a2562aecb35c" dependencies = [ "bitflags 1.3.2", "cc", - "cfg-if 1.0.0", + "cfg-if", "libc", "memoffset", ] @@ -3174,7 +2948,7 @@ checksum = "f346ff70e7dbfd675fe90590b92d59ef2de15a8779ae305ebcbfd3f0caf59be4" dependencies = [ "autocfg", "bitflags 1.3.2", - "cfg-if 1.0.0", + "cfg-if", "libc", "memoffset", "pin-utils", @@ -3187,7 +2961,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "598beaf3cc6fdd9a5dfb1630c2800c7acd31df7aaf0f565796fba2b53ca1af1b" dependencies = [ "bitflags 1.3.2", - "cfg-if 1.0.0", + "cfg-if", "libc", ] @@ -3223,7 +2997,7 @@ dependencies = [ "noirc_abi", "noirc_artifacts", "proptest", - "rand 0.8.5", + "rand", ] [[package]] @@ -3245,7 +3019,7 @@ dependencies = [ "acvm", "async-lsp", "codespan-lsp", - "convert_case 0.6.0", + "convert_case", "fm", "fxhash", "lsp-types 0.94.1", @@ -3299,7 +3073,7 @@ dependencies = [ "build-data", "console_error_panic_hook", "fm", - "getrandom 0.2.15", + "getrandom", "gloo-utils", "js-sys", "nargo", @@ -3331,7 +3105,7 @@ dependencies = [ "strum", "strum_macros", "thiserror", - "toml 0.7.8", + "toml", ] [[package]] @@ -3341,7 +3115,7 @@ dependencies = [ "acvm", "build-data", "console_error_panic_hook", - "getrandom 0.2.15", + "getrandom", "gloo-utils", "iter-extended", "js-sys", @@ -3412,7 +3186,7 @@ version = "1.0.0-beta.0" dependencies = [ "acvm", "bn254_blackbox_solver", - "cfg-if 1.0.0", + "cfg-if", "chrono", "fxhash", "im", @@ -3440,7 +3214,7 @@ dependencies = [ "acvm", "base64 0.21.7", "bn254_blackbox_solver", - "cfg-if 1.0.0", + "cfg-if", "fm", "im", "iter-extended", @@ -3453,7 +3227,7 @@ dependencies = [ "proptest", "proptest-derive 0.5.0", "rangemap", - "rustc-hash", + "rustc-hash 1.1.0", "serde", "serde_json", "small-ord-set", @@ -3511,7 +3285,7 @@ dependencies = [ "file-id", "log", "notify", - "parking_lot 0.12.3", + "parking_lot", "walkdir", ] @@ -3570,16 +3344,6 @@ dependencies = [ "libm", ] -[[package]] -name = "num_cpus" -version = "1.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" -dependencies = [ - "hermit-abi 0.3.9", - "libc", -] - [[package]] name = "numtoa" version = "0.1.0" @@ -3645,17 +3409,6 @@ dependencies = [ "group 0.12.1", ] -[[package]] -name = "parking_lot" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" -dependencies = [ - "instant", - "lock_api", - "parking_lot_core 0.8.6", -] - [[package]] name = "parking_lot" version = "0.12.3" @@ -3663,21 +3416,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" dependencies = [ "lock_api", - "parking_lot_core 0.9.10", -] - -[[package]] -name = "parking_lot_core" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60a2cfe6f0ad2bfc16aefa463b497d5c7a5ecd44a23efa72aa342d90177356dc" -dependencies = [ - "cfg-if 1.0.0", - "instant", - "libc", - "redox_syscall 0.2.16", - "smallvec", - "winapi", + "parking_lot_core", ] [[package]] @@ -3686,7 +3425,7 @@ version = "0.9.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "libc", "redox_syscall 0.5.7", "smallvec", @@ -3703,7 +3442,7 @@ dependencies = [ "ff 0.12.1", "group 0.12.1", "lazy_static", - "rand 0.8.5", + "rand", "static_assertions", "subtle", ] @@ -3718,7 +3457,7 @@ dependencies = [ "ff 0.13.0", "group 0.13.0", "lazy_static", - "rand 0.8.5", + "rand", "static_assertions", "subtle", ] @@ -3729,12 +3468,6 @@ version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" -[[package]] -name = "percent-encoding" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831" - [[package]] name = "percent-encoding" version = "2.3.1" @@ -3769,7 +3502,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5d5285893bb5eb82e6aaf5d59ee909a06a16737a8970984dd7746ba9283498d6" dependencies = [ "phf_shared", - "rand 0.8.5", + "rand", ] [[package]] @@ -3885,7 +3618,7 @@ checksum = "ebbe2f8898beba44815fdc9e5a4ae9c929e21c5dc29b0c774a15555f7f58d6d0" dependencies = [ "aligned-vec", "backtrace", - "cfg-if 1.0.0", + "cfg-if", "criterion", "findshlibs", "inferno", @@ -3893,7 +3626,7 @@ dependencies = [ "log", "nix 0.26.4", "once_cell", - "parking_lot 0.12.3", + "parking_lot", "smallvec", "symbolic-demangle", "tempfile", @@ -3966,11 +3699,11 @@ dependencies = [ [[package]] name = "proc-macro-crate" -version = "0.1.5" +version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d6ea3c4595b96363c13943497db34af4460fb474a95c43f4446ad341b8c9785" +checksum = "8ecf48c7ca261d60b74ab1a7b20da18bede46776b2e55535cb958eb595c5fa7b" dependencies = [ - "toml 0.5.11", + "toml_edit 0.22.22", ] [[package]] @@ -3999,8 +3732,8 @@ dependencies = [ "bitflags 2.6.0", "lazy_static", "num-traits", - "rand 0.8.5", - "rand_chacha 0.3.1", + "rand", + "rand_chacha", "rand_xorshift", "regex-syntax 0.8.5", "rusty-fork", @@ -4070,19 +3803,6 @@ dependencies = [ "nibble_vec", ] -[[package]] -name = "rand" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" -dependencies = [ - "getrandom 0.1.16", - "libc", - "rand_chacha 0.2.2", - "rand_core 0.5.1", - "rand_hc", -] - [[package]] name = "rand" version = "0.8.5" @@ -4090,18 +3810,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", - "rand_chacha 0.3.1", - "rand_core 0.6.4", -] - -[[package]] -name = "rand_chacha" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" -dependencies = [ - "ppv-lite86", - "rand_core 0.5.1", + "rand_chacha", + "rand_core", ] [[package]] @@ -4111,16 +3821,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", - "rand_core 0.6.4", -] - -[[package]] -name = "rand_core" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" -dependencies = [ - "getrandom 0.1.16", + "rand_core", ] [[package]] @@ -4129,16 +3830,7 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom 0.2.15", -] - -[[package]] -name = "rand_hc" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" -dependencies = [ - "rand_core 0.5.1", + "getrandom", ] [[package]] @@ -4147,7 +3839,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f" dependencies = [ - "rand_core 0.6.4", + "rand_core", ] [[package]] @@ -4156,7 +3848,7 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6f97cdb2a36ed4183de61b2f824cc45c9f1037f28afe0a322e9fff4c108b5aaa" dependencies = [ - "rand_core 0.6.4", + "rand_core", ] [[package]] @@ -4185,15 +3877,6 @@ dependencies = [ "crossbeam-utils", ] -[[package]] -name = "redox_syscall" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" -dependencies = [ - "bitflags 1.3.2", -] - [[package]] name = "redox_syscall" version = "0.4.1" @@ -4224,7 +3907,7 @@ version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" dependencies = [ - "getrandom 0.2.15", + "getrandom", "libredox 0.1.3", "thiserror", ] @@ -4313,14 +3996,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" dependencies = [ "cc", - "cfg-if 1.0.0", - "getrandom 0.2.15", + "cfg-if", + "getrandom", "libc", "spin", "untrusted", "windows-sys 0.52.0", ] +[[package]] +name = "route-recognizer" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "afab94fb28594581f62d981211a9a4d53cc8130bbcbbb89a0440d9b8e81a7746" + [[package]] name = "rust-embed" version = "6.8.1" @@ -4367,6 +4056,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" +[[package]] +name = "rustc-hash" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7fb8039b3032c191086b10f11f319a6e99e1e82889c5cc6046f515c9db1d497" + [[package]] name = "rustc_version" version = "0.4.1" @@ -4495,7 +4190,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "db7826789c0e25614b03e5a54a0717a86f9ff6e6e5247f92b369472869320039" dependencies = [ "bitflags 1.3.2", - "cfg-if 1.0.0", + "cfg-if", "clipboard-win", "dirs-next", "fd-lock", @@ -4774,13 +4469,24 @@ dependencies = [ "syn 2.0.87", ] +[[package]] +name = "sha1" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + [[package]] name = "sha2" version = "0.10.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "cpufeatures", "digest", ] @@ -4823,7 +4529,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c" dependencies = [ "digest", - "rand_core 0.6.4", + "rand_core", ] [[package]] @@ -4911,6 +4617,22 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "soketto" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e859df029d160cb88608f5d7df7fb4753fd20fdfb4de5644f3d8b8440841721" +dependencies = [ + "base64 0.22.1", + "bytes", + "futures", + "http", + "httparse", + "log", + "rand", + "sha1", +] + [[package]] name = "spin" version = "0.9.8" @@ -5050,7 +4772,7 @@ version = "3.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28cce251fcbc87fac86a866eeb0d6c2d536fc16d06f184bb61aeae11aa4cee0c" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "fastrand", "once_cell", "rustix", @@ -5123,7 +4845,7 @@ version = "3.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "adcb7fd841cd518e279be3d5a3eb0636409487998a4aff22f3de87b81e88384f" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "proc-macro2", "quote", "syn 2.0.87", @@ -5188,7 +4910,7 @@ version = "1.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "once_cell", ] @@ -5243,21 +4965,6 @@ dependencies = [ "serde_json", ] -[[package]] -name = "tinyvec" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938" -dependencies = [ - "tinyvec_macros", -] - -[[package]] -name = "tinyvec_macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" - [[package]] name = "tokio" version = "1.42.0" @@ -5297,27 +5004,14 @@ dependencies = [ [[package]] name = "tokio-stream" -version = "0.1.16" +version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f4e6ce100d0eb49a2734f8c0812bcd324cf357d21810932c5df6b96ef2b86f1" +checksum = "eca58d7bba4a75707817a2c44174253f9236b2d5fbd055602e9d5c07c139a047" dependencies = [ "futures-core", "pin-project-lite", "tokio", -] - -[[package]] -name = "tokio-util" -version = "0.6.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36943ee01a6d67977dd3f84a5a1d2efeb4ada3a1ae771cadfaa535d9d9fc6507" -dependencies = [ - "bytes", - "futures-core", - "futures-sink", - "log", - "pin-project-lite", - "tokio", + "tokio-util", ] [[package]] @@ -5334,15 +5028,6 @@ dependencies = [ "tokio", ] -[[package]] -name = "toml" -version = "0.5.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" -dependencies = [ - "serde", -] - [[package]] name = "toml" version = "0.7.8" @@ -5352,7 +5037,7 @@ dependencies = [ "serde", "serde_spanned", "toml_datetime", - "toml_edit", + "toml_edit 0.19.15", ] [[package]] @@ -5374,7 +5059,18 @@ dependencies = [ "serde", "serde_spanned", "toml_datetime", - "winnow", + "winnow 0.5.40", +] + +[[package]] +name = "toml_edit" +version = "0.22.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" +dependencies = [ + "indexmap 2.6.0", + "toml_datetime", + "winnow 0.6.20", ] [[package]] @@ -5549,18 +5245,6 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" -[[package]] -name = "unicase" -version = "2.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e51b68083f157f853b6379db119d1c1be0e6e4dec98101079dec41f6f5cf6df" - -[[package]] -name = "unicode-bidi" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ab17db44d7388991a428b2ee655ce0c212e862eff1768a455c58f9aad6e7893" - [[package]] name = "unicode-ident" version = "1.0.13" @@ -5573,15 +5257,6 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3b09c83c3c29d37506a3e260c08c03743a6bb66a9cd432c6934ab501a190571f" -[[package]] -name = "unicode-normalization" -version = "0.1.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956" -dependencies = [ - "tinyvec", -] - [[package]] name = "unicode-segmentation" version = "1.12.0" @@ -5606,17 +5281,6 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" -[[package]] -name = "url" -version = "1.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd4e7c0d531266369519a4aa4f399d748bd37043b00bde1e4ff1f60a120b355a" -dependencies = [ - "idna 0.1.5", - "matches", - "percent-encoding 1.0.1", -] - [[package]] name = "url" version = "2.5.4" @@ -5624,8 +5288,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" dependencies = [ "form_urlencoded", - "idna 1.0.3", - "percent-encoding 2.3.1", + "idna", + "percent-encoding", "serde", ] @@ -5703,12 +5367,6 @@ dependencies = [ "try-lock", ] -[[package]] -name = "wasi" -version = "0.9.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" - [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" @@ -5721,7 +5379,7 @@ version = "0.2.86" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5bba0e8cb82ba49ff4e229459ff22a191bbe9a1cb3a341610c9c33efc27ddf73" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "serde", "serde_json", "wasm-bindgen-macro", @@ -5748,7 +5406,7 @@ version = "0.4.36" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2d1985d03709c53167ce907ff394f5316aa22cb4e12761295c5dc57dacb6297e" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "js-sys", "wasm-bindgen", "web-sys", @@ -6023,6 +5681,15 @@ dependencies = [ "memchr", ] +[[package]] +name = "winnow" +version = "0.6.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b" +dependencies = [ + "memchr", +] + [[package]] name = "write16" version = "1.0.0" @@ -6164,7 +5831,7 @@ dependencies = [ "blake2", "bls12_381", "byteorder", - "cfg-if 1.0.0", + "cfg-if", "group 0.12.1", "group 0.13.0", "halo2", @@ -6172,7 +5839,7 @@ dependencies = [ "jubjub", "lazy_static", "pasta_curves 0.5.1", - "rand 0.8.5", + "rand", "serde", "sha2", "sha3", diff --git a/Cargo.toml b/Cargo.toml index 6e70dd1c552..28e4e51c31b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -148,8 +148,7 @@ num-traits = "0.2" similar-asserts = "1.5.0" tempfile = "3.6.0" test-case = "3.3.1" -jsonrpc = { version = "0.16.0", features = ["minreq_http"] } -jsonrpsee = { version = "0.24.7", features = ["http-client"] } +jsonrpsee = { version = "0.24.7", features = ["http-client", "macros"] } flate2 = "1.0.24" color-eyre = "0.6.2" rand = "0.8.5" @@ -160,7 +159,7 @@ sha2 = { version = "0.10.6", features = ["compress"] } sha3 = "0.10.6" strum = "0.24" strum_macros = "0.24" -tokio = { version = "1.42", features = ["rt"] } +tokio = { version = "1.42", features = ["rt-multi-thread"] } im = { version = "15.1", features = ["serde"] } tracing = "0.1.40" tracing-web = "0.1.3" diff --git a/cspell.json b/cspell.json index 9a69bd1a4e0..b15d6bfc7b8 100644 --- a/cspell.json +++ b/cspell.json @@ -167,6 +167,7 @@ "nomicfoundation", "noncanonical", "nouner", + "oneshot", "overflowing", "pedersen", "peekable", diff --git a/tooling/nargo/Cargo.toml b/tooling/nargo/Cargo.toml index e50ae4b101b..4cd2d700c87 100644 --- a/tooling/nargo/Cargo.toml +++ b/tooling/nargo/Cargo.toml @@ -35,8 +35,4 @@ noir_fuzzer.workspace = true proptest.workspace = true [dev-dependencies] -jsonrpc.workspace = true -jsonrpc-http-server = "18.0" -jsonrpc-core-client = "18.0" -jsonrpc-derive = "18.0" -jsonrpc-core = "18.0" +jsonrpsee = { workspace = true, features = ["server"] } diff --git a/tooling/nargo/src/foreign_calls/rpc.rs b/tooling/nargo/src/foreign_calls/rpc.rs index cab88d98da0..3ac12df3810 100644 --- a/tooling/nargo/src/foreign_calls/rpc.rs +++ b/tooling/nargo/src/foreign_calls/rpc.rs @@ -26,7 +26,7 @@ pub(crate) struct RPCForeignCallExecutor { package_name: Option, /// Runtime to execute asynchronous tasks on. /// See [bridging](https://tokio.rs/tokio/topics/bridging). - rt: tokio::runtime::Runtime, + runtime: tokio::runtime::Runtime, } #[derive(Debug, Serialize, Deserialize)] @@ -51,6 +51,8 @@ struct ResolveForeignCallRequest { package_name: Option, } +type ResolveForeignCallResult = Result, ForeignCallError>; + impl RPCForeignCallExecutor { pub(crate) fn new( resolver_url: &str, @@ -72,7 +74,7 @@ impl RPCForeignCallExecutor { // Opcodes are executed in the `ProgramExecutor::execute_circuit` one by one in a loop, // we don't need a concurrent thread pool. - let rt = tokio::runtime::Builder::new_current_thread() + let runtime = tokio::runtime::Builder::new_current_thread() .enable_time() .enable_io() .build() @@ -83,18 +85,16 @@ impl RPCForeignCallExecutor { id, root_path, package_name, - rt, + runtime, } } } -impl Deserialize<'a>> ForeignCallExecutor - for RPCForeignCallExecutor +impl ForeignCallExecutor for RPCForeignCallExecutor +where + F: AcirField + Serialize + for<'a> Deserialize<'a>, { - fn execute( - &mut self, - foreign_call: &ForeignCallWaitInfo, - ) -> Result, ForeignCallError> { + fn execute(&mut self, foreign_call: &ForeignCallWaitInfo) -> ResolveForeignCallResult { let encoded_params = rpc_params!(ResolveForeignCallRequest { session_id: self.id, function_call: foreign_call.clone(), @@ -102,9 +102,9 @@ impl Deserialize<'a>> ForeignCallExecutor package_name: self.package_name.clone(), }); - let parsed_response = self - .rt - .block_on(self.external_resolver.request("resolve_foreign_call", encoded_params))?; + let parsed_response = self.runtime.block_on(async { + self.external_resolver.request("resolve_foreign_call", encoded_params).await + })?; Ok(parsed_response) } @@ -112,24 +112,28 @@ impl Deserialize<'a>> ForeignCallExecutor #[cfg(test)] mod tests { + use acvm::{ acir::brillig::ForeignCallParam, brillig_vm::brillig::ForeignCallResult, pwg::ForeignCallWaitInfo, FieldElement, }; - use jsonrpc_core::Result as RpcResult; - use jsonrpc_derive::rpc; - use jsonrpc_http_server::{Server, ServerBuilder}; - - use super::{ForeignCallExecutor, RPCForeignCallExecutor, ResolveForeignCallRequest}; + use jsonrpsee::proc_macros::rpc; + use jsonrpsee::server::Server; + use jsonrpsee::types::ErrorObjectOwned; + use tokio::sync::{mpsc, oneshot}; + + use super::{ + ForeignCallExecutor, RPCForeignCallExecutor, ResolveForeignCallRequest, + ResolveForeignCallResult, + }; - #[allow(unreachable_pub)] - #[rpc] - pub trait OracleResolver { - #[rpc(name = "resolve_foreign_call")] + #[rpc(server)] + trait OracleResolver { + #[method(name = "resolve_foreign_call")] fn resolve_foreign_call( &self, req: ResolveForeignCallRequest, - ) -> RpcResult>; + ) -> Result, ErrorObjectOwned>; } struct OracleResolverImpl; @@ -150,99 +154,135 @@ mod tests { } } - impl OracleResolver for OracleResolverImpl { + impl OracleResolverServer for OracleResolverImpl { fn resolve_foreign_call( &self, req: ResolveForeignCallRequest, - ) -> RpcResult> { + ) -> Result, ErrorObjectOwned> { let response = match req.function_call.function.as_str() { "sum" => self.sum(req.function_call.inputs[0].clone()), "echo" => self.echo(req.function_call.inputs[0].clone()), "id" => FieldElement::from(req.session_id as u128).into(), - _ => panic!("unexpected foreign call"), }; Ok(response) } } - fn build_oracle_server() -> (Server, String) { - let mut io = jsonrpc_core::IoHandler::new(); - io.extend_with(OracleResolverImpl.to_delegate()); + /// The test client send its request and a response channel. + type RPCForeignCallClientRequest = ( + ForeignCallWaitInfo, + oneshot::Sender>, + ); - // Choosing port 0 results in a random port being assigned. - let server = ServerBuilder::new(io) - .start_http(&"127.0.0.1:0".parse().expect("Invalid address")) - .expect("Could not start server"); + /// Async client used in the tests. + #[derive(Clone)] + struct RPCForeignCallClient { + tx: mpsc::UnboundedSender, + } - let url = format!("http://{}", server.address()); - (server, url) + impl RPCForeignCallExecutor { + /// Spawn and run the executor in the background until all clients are closed. + fn run(mut self) -> RPCForeignCallClient { + let (tx, mut rx) = mpsc::unbounded_channel::(); + let _ = tokio::task::spawn_blocking(move || { + while let Some((req, tx)) = rx.blocking_recv() { + let res = self.execute(&req); + let _ = tx.send(res); + } + }); + RPCForeignCallClient { tx } + } + } + + impl RPCForeignCallClient { + /// Asynchronously execute a foreign call. + async fn execute( + &self, + req: &ForeignCallWaitInfo, + ) -> ResolveForeignCallResult { + let (tx, rx) = oneshot::channel(); + self.tx.send((req.clone(), tx)).expect("failed to send to executor"); + rx.await.expect("failed to receive from executor") + } + } + + /// Start running the Oracle server or a random port, returning the listen URL. + async fn build_oracle_server() -> std::io::Result { + // Choosing port 0 results in a random port being assigned. + let server = Server::builder().build("127.0.0.1:0").await?; + let addr = server.local_addr()?; + let handle = server.start(OracleResolverImpl.into_rpc()); + let url = format!("http://{}", addr); + // In this test we don't care about doing shutdown so let's it run forever. + tokio::spawn(handle.stopped()); + Ok(url) } - #[test] - fn test_oracle_resolver_echo() { - let (server, url) = build_oracle_server(); + #[tokio::test(flavor = "multi_thread")] + async fn test_oracle_resolver_echo() -> std::io::Result<()> { + let url = build_oracle_server().await?; - let mut executor = RPCForeignCallExecutor::new(&url, 1, None, None); + let executor = RPCForeignCallExecutor::new(&url, 1, None, None).run(); let foreign_call: ForeignCallWaitInfo = ForeignCallWaitInfo { function: "echo".to_string(), inputs: vec![ForeignCallParam::Single(1_u128.into())], }; - let result = executor.execute(&foreign_call); + let result = executor.execute(&foreign_call).await; assert_eq!(result.unwrap(), ForeignCallResult { values: foreign_call.inputs }); - server.close(); + Ok(()) } - #[test] - fn test_oracle_resolver_sum() { - let (server, url) = build_oracle_server(); + #[tokio::test(flavor = "multi_thread")] + async fn test_oracle_resolver_sum() -> std::io::Result<()> { + let url = build_oracle_server().await?; - let mut executor = RPCForeignCallExecutor::new(&url, 2, None, None); + let executor = RPCForeignCallExecutor::new(&url, 2, None, None).run(); let foreign_call: ForeignCallWaitInfo = ForeignCallWaitInfo { function: "sum".to_string(), inputs: vec![ForeignCallParam::Array(vec![1_usize.into(), 2_usize.into()])], }; - let result = executor.execute(&foreign_call); + let result = executor.execute(&foreign_call).await; assert_eq!(result.unwrap(), FieldElement::from(3_usize).into()); - server.close(); + Ok(()) } - #[test] - fn foreign_call_executor_id_is_persistent() { - let (server, url) = build_oracle_server(); + #[tokio::test(flavor = "multi_thread")] + async fn foreign_call_executor_id_is_persistent() -> std::io::Result<()> { + let url = build_oracle_server().await?; - let mut executor = RPCForeignCallExecutor::new(&url, 3, None, None); + let executor = RPCForeignCallExecutor::new(&url, 3, None, None).run(); let foreign_call: ForeignCallWaitInfo = ForeignCallWaitInfo { function: "id".to_string(), inputs: Vec::new() }; - let result_1 = executor.execute(&foreign_call).unwrap(); - let result_2 = executor.execute(&foreign_call).unwrap(); + let result_1 = executor.execute(&foreign_call).await.unwrap(); + let result_2 = executor.execute(&foreign_call).await.unwrap(); assert_eq!(result_1, result_2); - server.close(); + Ok(()) } - #[test] - fn oracle_resolver_rpc_can_distinguish_executors() { - let (server, url) = build_oracle_server(); + #[tokio::test(flavor = "multi_thread")] + async fn oracle_resolver_rpc_can_distinguish_executors() -> std::io::Result<()> { + let url = build_oracle_server().await?; - let mut executor_1 = RPCForeignCallExecutor::new(&url, 4, None, None); - let mut executor_2 = RPCForeignCallExecutor::new(&url, 5, None, None); + let executor_1 = RPCForeignCallExecutor::new(&url, 4, None, None).run(); + let executor_2 = RPCForeignCallExecutor::new(&url, 5, None, None).run(); let foreign_call: ForeignCallWaitInfo = ForeignCallWaitInfo { function: "id".to_string(), inputs: Vec::new() }; - let result_1 = executor_1.execute(&foreign_call).unwrap(); - let result_2 = executor_2.execute(&foreign_call).unwrap(); + let result_1 = executor_1.execute(&foreign_call).await.unwrap(); + let result_2 = executor_2.execute(&foreign_call).await.unwrap(); assert_ne!(result_1, result_2); - server.close(); + Ok(()) } } From 118e1e3f6b2df2409eeecceda16b1be98c2d01d5 Mon Sep 17 00:00:00 2001 From: Akosh Farkash Date: Tue, 17 Dec 2024 20:18:05 +0000 Subject: [PATCH 03/21] Remove jsonrpc from deny --- deny.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/deny.toml b/deny.toml index 661c8095281..a2fda7b443e 100644 --- a/deny.toml +++ b/deny.toml @@ -66,7 +66,6 @@ exceptions = [ # so we prefer to not have dependencies using it # https://tldrlegal.com/license/creative-commons-cc0-1.0-universal { allow = ["CC0-1.0"], name = "more-asserts" }, - { allow = ["CC0-1.0"], name = "jsonrpc" }, { allow = ["CC0-1.0"], name = "notify" }, { allow = ["CC0-1.0"], name = "tiny-keccak" }, { allow = ["MPL-2.0"], name = "sized-chunks" }, From 8b742ff9dae3f416202780edc612dd0a30c229ed Mon Sep 17 00:00:00 2001 From: Akosh Farkash Date: Tue, 17 Dec 2024 20:23:24 +0000 Subject: [PATCH 04/21] Fix clippy --- tooling/nargo/src/foreign_calls/rpc.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/tooling/nargo/src/foreign_calls/rpc.rs b/tooling/nargo/src/foreign_calls/rpc.rs index 3ac12df3810..ef4f11b8a48 100644 --- a/tooling/nargo/src/foreign_calls/rpc.rs +++ b/tooling/nargo/src/foreign_calls/rpc.rs @@ -94,6 +94,9 @@ impl ForeignCallExecutor for RPCForeignCallExecutor where F: AcirField + Serialize + for<'a> Deserialize<'a>, { + /// Execute an async call blocking the current thread. + /// This method cannot be called from inside a `tokio` runtime, for that to work + /// we need to offload the execution into a different thread; see the tests. fn execute(&mut self, foreign_call: &ForeignCallWaitInfo) -> ResolveForeignCallResult { let encoded_params = rpc_params!(ResolveForeignCallRequest { session_id: self.id, @@ -112,7 +115,6 @@ where #[cfg(test)] mod tests { - use acvm::{ acir::brillig::ForeignCallParam, brillig_vm::brillig::ForeignCallResult, pwg::ForeignCallWaitInfo, FieldElement, @@ -185,12 +187,14 @@ mod tests { /// Spawn and run the executor in the background until all clients are closed. fn run(mut self) -> RPCForeignCallClient { let (tx, mut rx) = mpsc::unbounded_channel::(); - let _ = tokio::task::spawn_blocking(move || { + let handle = tokio::task::spawn_blocking(move || { while let Some((req, tx)) = rx.blocking_recv() { let res = self.execute(&req); let _ = tx.send(res); } }); + // The task will finish when the client goes out of scope. + drop(handle); RPCForeignCallClient { tx } } } From 84dba553fb762f38ff85b1817d415670a09186b5 Mon Sep 17 00:00:00 2001 From: Akosh Farkash Date: Tue, 17 Dec 2024 20:39:37 +0000 Subject: [PATCH 05/21] Add clarification for the 'ring' license --- deny.toml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/deny.toml b/deny.toml index a2fda7b443e..48628fb0045 100644 --- a/deny.toml +++ b/deny.toml @@ -71,8 +71,14 @@ exceptions = [ { allow = ["MPL-2.0"], name = "sized-chunks" }, { allow = ["MPL-2.0"], name = "webpki-roots" }, { allow = ["CDDL-1.0"], name = "inferno" }, + { allow = ["OpenSSL"], name = "ring" }, ] +[[licenses.clarify]] +crate = "ring" +expression = "ISC" +license-files = [{ path = "LICENSE", hash = 0xbd0eed23 }] + # This section is considered when running `cargo deny check sources`. # More documentation about the 'sources' section can be found here: # https://embarkstudios.github.io/cargo-deny/checks/sources/cfg.html From 5232698690159633ec95ed77eb0473f12bec48c8 Mon Sep 17 00:00:00 2001 From: Akosh Farkash Date: Wed, 18 Dec 2024 10:16:08 +0000 Subject: [PATCH 06/21] Added feature flags to nargo to be able to disable execution for Wasm --- Cargo.toml | 4 ++-- compiler/wasm/Cargo.toml | 7 ++++++- tooling/nargo/Cargo.toml | 21 +++++++++++++++------ tooling/nargo/src/foreign_calls/rpc.rs | 8 ++++---- tooling/nargo/src/lib.rs | 11 +++++++---- tooling/nargo/src/ops/mod.rs | 11 ++++++++--- tooling/nargo_cli/src/cli/execute_cmd.rs | 2 +- 7 files changed, 43 insertions(+), 21 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 28e4e51c31b..de68b595423 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -148,7 +148,7 @@ num-traits = "0.2" similar-asserts = "1.5.0" tempfile = "3.6.0" test-case = "3.3.1" -jsonrpsee = { version = "0.24.7", features = ["http-client", "macros"] } +jsonrpsee = { version = "0.24.7", features = ["client-core"] } flate2 = "1.0.24" color-eyre = "0.6.2" rand = "0.8.5" @@ -159,7 +159,7 @@ sha2 = { version = "0.10.6", features = ["compress"] } sha3 = "0.10.6" strum = "0.24" strum_macros = "0.24" -tokio = { version = "1.42", features = ["rt-multi-thread"] } +tokio = "1.42" im = { version = "15.1", features = ["serde"] } tracing = "0.1.40" tracing-web = "0.1.3" diff --git a/compiler/wasm/Cargo.toml b/compiler/wasm/Cargo.toml index 9951b23f609..b7bf7ce3c06 100644 --- a/compiler/wasm/Cargo.toml +++ b/compiler/wasm/Cargo.toml @@ -17,9 +17,9 @@ workspace = true crate-type = ["cdylib"] [dependencies] + acvm = { workspace = true, features = ["bn254"] } fm.workspace = true -nargo.workspace = true noirc_driver.workspace = true noirc_frontend = { workspace = true, features = ["bn254"] } noirc_errors.workspace = true @@ -33,6 +33,11 @@ gloo-utils.workspace = true tracing-subscriber.workspace = true tracing-web.workspace = true +# Disable the execution feature so we don't get the HTTP dependency which doesn't compile to Wasm. +# Cannot use `workspace = true` because it would unify all packages and compile with the default +# features on, ignoring the setting here, but with `path` it works. +nargo = { path = "../../tooling/nargo", default-features = false } + # This is an unused dependency, we are adding it # so that we can enable the js feature in getrandom. getrandom = { workspace = true, features = ["js"] } diff --git a/tooling/nargo/Cargo.toml b/tooling/nargo/Cargo.toml index 4cd2d700c87..88cfbc1b6c6 100644 --- a/tooling/nargo/Cargo.toml +++ b/tooling/nargo/Cargo.toml @@ -23,16 +23,25 @@ noirc_printable_type.workspace = true iter-extended.workspace = true rayon.workspace = true thiserror.workspace = true -tokio.workspace = true tracing.workspace = true -jsonrpsee.workspace = true -rand.workspace = true -serde.workspace = true walkdir = "2.5.0" +# Some dependencies are optional so we can compile to Wasm. +rand = { workspace = true, optional = true } +serde = { workspace = true, optional = true } +jsonrpsee = { workspace = true, optional = true } +tokio = { workspace = true, optional = true } + [target.'cfg(not(target_arch = "wasm32"))'.dependencies] -noir_fuzzer.workspace = true -proptest.workspace = true +noir_fuzzer = { workspace = true, optional = true } +proptest = { workspace = true, optional = true } [dev-dependencies] jsonrpsee = { workspace = true, features = ["server"] } + +[features] +default = ["execute", "test"] + +# Execution currently uses HTTP based Oracle resolvers; does not compile to Wasm. +execute = ["jsonrpsee/http-client", "jsonrpsee/macros", "tokio/rt", "serde"] +test = ["execute", "noir_fuzzer", "proptest", "rand"] diff --git a/tooling/nargo/src/foreign_calls/rpc.rs b/tooling/nargo/src/foreign_calls/rpc.rs index ef4f11b8a48..2ec28ca2156 100644 --- a/tooling/nargo/src/foreign_calls/rpc.rs +++ b/tooling/nargo/src/foreign_calls/rpc.rs @@ -223,7 +223,7 @@ mod tests { Ok(url) } - #[tokio::test(flavor = "multi_thread")] + #[tokio::test] async fn test_oracle_resolver_echo() -> std::io::Result<()> { let url = build_oracle_server().await?; @@ -240,7 +240,7 @@ mod tests { Ok(()) } - #[tokio::test(flavor = "multi_thread")] + #[tokio::test] async fn test_oracle_resolver_sum() -> std::io::Result<()> { let url = build_oracle_server().await?; @@ -257,7 +257,7 @@ mod tests { Ok(()) } - #[tokio::test(flavor = "multi_thread")] + #[tokio::test] async fn foreign_call_executor_id_is_persistent() -> std::io::Result<()> { let url = build_oracle_server().await?; @@ -273,7 +273,7 @@ mod tests { Ok(()) } - #[tokio::test(flavor = "multi_thread")] + #[tokio::test] async fn oracle_resolver_rpc_can_distinguish_executors() -> std::io::Result<()> { let url = build_oracle_server().await?; diff --git a/tooling/nargo/src/lib.rs b/tooling/nargo/src/lib.rs index ee7b2e4809a..694d4846536 100644 --- a/tooling/nargo/src/lib.rs +++ b/tooling/nargo/src/lib.rs @@ -9,11 +9,17 @@ pub mod constants; pub mod errors; -pub mod foreign_calls; pub mod ops; pub mod package; pub mod workspace; +#[cfg(feature = "execute")] +pub mod foreign_calls; + +pub use self::errors::NargoError; +#[cfg(feature = "execute")] +pub use self::foreign_calls::print::PrintOutput; + use std::{ collections::{BTreeMap, HashMap, HashSet}, path::PathBuf, @@ -29,9 +35,6 @@ use package::{Dependency, Package}; use rayon::prelude::*; use walkdir::WalkDir; -pub use self::errors::NargoError; -pub use self::foreign_calls::print::PrintOutput; - pub fn prepare_dependencies( context: &mut Context, parent_crate: CrateId, diff --git a/tooling/nargo/src/ops/mod.rs b/tooling/nargo/src/ops/mod.rs index 04efeb5a9ec..e6540eed834 100644 --- a/tooling/nargo/src/ops/mod.rs +++ b/tooling/nargo/src/ops/mod.rs @@ -3,15 +3,20 @@ pub use self::compile::{ collect_errors, compile_contract, compile_program, compile_program_with_debug_instrumenter, compile_workspace, report_errors, }; -pub use self::execute::{execute_program, execute_program_with_profiling}; pub use self::optimize::{optimize_contract, optimize_program}; pub use self::transform::{transform_contract, transform_program}; +#[cfg(feature = "execute")] +pub use self::execute::{execute_program, execute_program_with_profiling}; +#[cfg(feature = "test")] pub use self::test::{run_test, TestStatus}; mod check; mod compile; -mod execute; mod optimize; -mod test; mod transform; + +#[cfg(feature = "execute")] +mod execute; +#[cfg(feature = "test")] +mod test; diff --git a/tooling/nargo_cli/src/cli/execute_cmd.rs b/tooling/nargo_cli/src/cli/execute_cmd.rs index 49a23a7ea62..709caf71185 100644 --- a/tooling/nargo_cli/src/cli/execute_cmd.rs +++ b/tooling/nargo_cli/src/cli/execute_cmd.rs @@ -162,7 +162,7 @@ pub(crate) fn execute_program( diagnostic.report(&debug_artifact, false); } - Err(crate::errors::CliError::NargoError(err)) + Err(CliError::NargoError(err)) } } } From fff53f8ac6445da3d7599bffb05d916814019428 Mon Sep 17 00:00:00 2001 From: Akosh Farkash Date: Wed, 18 Dec 2024 10:35:19 +0000 Subject: [PATCH 07/21] Just use unwrap in tests --- tooling/nargo/src/foreign_calls/rpc.rs | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/tooling/nargo/src/foreign_calls/rpc.rs b/tooling/nargo/src/foreign_calls/rpc.rs index 2ec28ca2156..565a2a036c3 100644 --- a/tooling/nargo/src/foreign_calls/rpc.rs +++ b/tooling/nargo/src/foreign_calls/rpc.rs @@ -224,8 +224,8 @@ mod tests { } #[tokio::test] - async fn test_oracle_resolver_echo() -> std::io::Result<()> { - let url = build_oracle_server().await?; + async fn test_oracle_resolver_echo() { + let url = build_oracle_server().await.unwrap(); let executor = RPCForeignCallExecutor::new(&url, 1, None, None).run(); @@ -236,13 +236,11 @@ mod tests { let result = executor.execute(&foreign_call).await; assert_eq!(result.unwrap(), ForeignCallResult { values: foreign_call.inputs }); - - Ok(()) } #[tokio::test] - async fn test_oracle_resolver_sum() -> std::io::Result<()> { - let url = build_oracle_server().await?; + async fn test_oracle_resolver_sum() { + let url = build_oracle_server().await.unwrap(); let executor = RPCForeignCallExecutor::new(&url, 2, None, None).run(); @@ -253,13 +251,11 @@ mod tests { let result = executor.execute(&foreign_call).await; assert_eq!(result.unwrap(), FieldElement::from(3_usize).into()); - - Ok(()) } #[tokio::test] - async fn foreign_call_executor_id_is_persistent() -> std::io::Result<()> { - let url = build_oracle_server().await?; + async fn foreign_call_executor_id_is_persistent() { + let url = build_oracle_server().await.unwrap(); let executor = RPCForeignCallExecutor::new(&url, 3, None, None).run(); @@ -269,13 +265,11 @@ mod tests { let result_1 = executor.execute(&foreign_call).await.unwrap(); let result_2 = executor.execute(&foreign_call).await.unwrap(); assert_eq!(result_1, result_2); - - Ok(()) } #[tokio::test] - async fn oracle_resolver_rpc_can_distinguish_executors() -> std::io::Result<()> { - let url = build_oracle_server().await?; + async fn oracle_resolver_rpc_can_distinguish_executors() { + let url = build_oracle_server().await.unwrap(); let executor_1 = RPCForeignCallExecutor::new(&url, 4, None, None).run(); let executor_2 = RPCForeignCallExecutor::new(&url, 5, None, None).run(); @@ -286,7 +280,5 @@ mod tests { let result_1 = executor_1.execute(&foreign_call).await.unwrap(); let result_2 = executor_2.execute(&foreign_call).await.unwrap(); assert_ne!(result_1, result_2); - - Ok(()) } } From e2549dfdd8ea93a8d63a4404c2aaada62455018e Mon Sep 17 00:00:00 2001 From: Akosh Farkash Date: Wed, 18 Dec 2024 12:28:58 +0000 Subject: [PATCH 08/21] Update tooling/nargo/Cargo.toml --- tooling/nargo/Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tooling/nargo/Cargo.toml b/tooling/nargo/Cargo.toml index 88cfbc1b6c6..a964ac5c071 100644 --- a/tooling/nargo/Cargo.toml +++ b/tooling/nargo/Cargo.toml @@ -43,5 +43,5 @@ jsonrpsee = { workspace = true, features = ["server"] } default = ["execute", "test"] # Execution currently uses HTTP based Oracle resolvers; does not compile to Wasm. -execute = ["jsonrpsee/http-client", "jsonrpsee/macros", "tokio/rt", "serde"] -test = ["execute", "noir_fuzzer", "proptest", "rand"] +execute = ["jsonrpsee/http-client", "jsonrpsee/macros", "tokio/rt", "serde", "rand"] +test = ["execute", "noir_fuzzer", "proptest"] From 6ce326374eb83d51f22f4ca6a8367f2b80fcbc90 Mon Sep 17 00:00:00 2001 From: Akosh Farkash Date: Thu, 19 Dec 2024 09:17:33 +0000 Subject: [PATCH 09/21] feat!: Composable foreign call handlers (#6857) --- tooling/debugger/src/foreign_calls.rs | 52 +++++--- tooling/nargo/src/foreign_calls/layers.rs | 144 ++++++++++++++++++++++ tooling/nargo/src/foreign_calls/mocker.rs | 38 +++++- tooling/nargo/src/foreign_calls/mod.rs | 101 ++++++--------- tooling/nargo/src/foreign_calls/print.rs | 10 +- tooling/nargo/src/foreign_calls/rpc.rs | 4 +- tooling/nargo/src/ops/test.rs | 82 ++++-------- 7 files changed, 284 insertions(+), 147 deletions(-) create mode 100644 tooling/nargo/src/foreign_calls/layers.rs diff --git a/tooling/debugger/src/foreign_calls.rs b/tooling/debugger/src/foreign_calls.rs index 899ba892d8f..91242edecd5 100644 --- a/tooling/debugger/src/foreign_calls.rs +++ b/tooling/debugger/src/foreign_calls.rs @@ -4,7 +4,7 @@ use acvm::{ AcirField, FieldElement, }; use nargo::{ - foreign_calls::{DefaultForeignCallExecutor, ForeignCallExecutor}, + foreign_calls::{layers::Layer, DefaultForeignCallExecutor, ForeignCallExecutor}, PrintOutput, }; use noirc_artifacts::debug::{DebugArtifact, DebugVars, StackFrame}; @@ -44,23 +44,31 @@ pub trait DebugForeignCallExecutor: ForeignCallExecutor { fn current_stack_frame(&self) -> Option>; } -pub struct DefaultDebugForeignCallExecutor<'a> { - executor: DefaultForeignCallExecutor<'a, FieldElement>, +#[derive(Default)] +pub struct DefaultDebugForeignCallExecutor { pub debug_vars: DebugVars, } -impl<'a> DefaultDebugForeignCallExecutor<'a> { - pub fn new(output: PrintOutput<'a>) -> Self { - Self { - executor: DefaultForeignCallExecutor::new(output, None, None, None), - debug_vars: DebugVars::default(), - } +impl DefaultDebugForeignCallExecutor { + pub fn make( + output: PrintOutput<'_>, + ex: DefaultDebugForeignCallExecutor, + ) -> impl DebugForeignCallExecutor + '_ { + Layer::new(ex, DefaultForeignCallExecutor::new(output, None, None, None)) + } + + #[allow(clippy::new_ret_no_self, dead_code)] + pub fn new(output: PrintOutput<'_>) -> impl DebugForeignCallExecutor + '_ { + Self::make(output, Self::default()) } - pub fn from_artifact(output: PrintOutput<'a>, artifact: &DebugArtifact) -> Self { - let mut ex = Self::new(output); + pub fn from_artifact<'a>( + output: PrintOutput<'a>, + artifact: &DebugArtifact, + ) -> impl DebugForeignCallExecutor + 'a { + let mut ex = Self::default(); ex.load_artifact(artifact); - ex + Self::make(output, ex) } pub fn load_artifact(&mut self, artifact: &DebugArtifact) { @@ -73,7 +81,7 @@ impl<'a> DefaultDebugForeignCallExecutor<'a> { } } -impl DebugForeignCallExecutor for DefaultDebugForeignCallExecutor<'_> { +impl DebugForeignCallExecutor for DefaultDebugForeignCallExecutor { fn get_variables(&self) -> Vec> { self.debug_vars.get_variables() } @@ -91,7 +99,7 @@ fn debug_fn_id(value: &FieldElement) -> DebugFnId { DebugFnId(value.to_u128() as u32) } -impl ForeignCallExecutor for DefaultDebugForeignCallExecutor<'_> { +impl ForeignCallExecutor for DefaultDebugForeignCallExecutor { fn execute( &mut self, foreign_call: &ForeignCallWaitInfo, @@ -166,7 +174,21 @@ impl ForeignCallExecutor for DefaultDebugForeignCallExecutor<'_> { self.debug_vars.pop_fn(); Ok(ForeignCallResult::default()) } - None => self.executor.execute(foreign_call), + None => Err(ForeignCallError::NoHandler(foreign_call_name.to_string())), } } } + +impl DebugForeignCallExecutor for Layer +where + H: DebugForeignCallExecutor, + I: ForeignCallExecutor, +{ + fn get_variables(&self) -> Vec> { + self.handler().get_variables() + } + + fn current_stack_frame(&self) -> Option> { + self.handler().current_stack_frame() + } +} diff --git a/tooling/nargo/src/foreign_calls/layers.rs b/tooling/nargo/src/foreign_calls/layers.rs new file mode 100644 index 00000000000..16ea678f691 --- /dev/null +++ b/tooling/nargo/src/foreign_calls/layers.rs @@ -0,0 +1,144 @@ +use std::marker::PhantomData; + +use acvm::{acir::brillig::ForeignCallResult, pwg::ForeignCallWaitInfo, AcirField}; +use noirc_printable_type::ForeignCallError; + +use super::ForeignCallExecutor; + +/// Returns an empty result when called. +/// +/// If all executors have no handler for the given foreign call then we cannot +/// return a correct response to the ACVM. The best we can do is to return an empty response, +/// this allows us to ignore any foreign calls which exist solely to pass information from inside +/// the circuit to the environment (e.g. custom logging) as the execution will still be able to progress. +/// +/// We optimistically return an empty response for all oracle calls as the ACVM will error +/// should a response have been required. +pub struct Empty; + +impl ForeignCallExecutor for Empty { + fn execute( + &mut self, + _foreign_call: &ForeignCallWaitInfo, + ) -> Result, ForeignCallError> { + Ok(ForeignCallResult::default()) + } +} + +/// Returns `NoHandler` for every call. +pub struct Unhandled; + +impl ForeignCallExecutor for Unhandled { + fn execute( + &mut self, + foreign_call: &ForeignCallWaitInfo, + ) -> Result, ForeignCallError> { + Err(ForeignCallError::NoHandler(foreign_call.function.clone())) + } +} + +/// Forwards to the inner executor if its own handler doesn't handle the call. +pub struct Layer { + pub handler: H, + pub inner: I, + _field: PhantomData, +} + +impl ForeignCallExecutor for Layer +where + H: ForeignCallExecutor, + I: ForeignCallExecutor, +{ + fn execute( + &mut self, + foreign_call: &ForeignCallWaitInfo, + ) -> Result, ForeignCallError> { + match self.handler.execute(foreign_call) { + Err(ForeignCallError::NoHandler(_)) => self.inner.execute(foreign_call), + handled => handled, + } + } +} + +impl Layer { + /// Create a layer from two handlers + pub fn new(handler: H, inner: I) -> Self { + Self { handler, inner, _field: PhantomData } + } +} + +impl Layer { + /// Create a layer from a handler. + /// If the handler doesn't handle a call, a default empty response is returned. + pub fn or_empty(handler: H) -> Self { + Self { handler, inner: Empty, _field: PhantomData } + } +} + +impl Layer { + /// Create a layer from a handler. + /// If the handler doesn't handle a call, `NoHandler` error is returned. + pub fn or_unhandled(handler: H) -> Self { + Self { handler, inner: Unhandled, _field: PhantomData } + } +} + +impl Layer { + /// A base layer that doesn't handle anything. + pub fn unhandled() -> Self { + Self { handler: Unhandled, inner: Unhandled, _field: PhantomData } + } +} + +impl Layer { + /// Add another layer on top of this one. + pub fn add_layer(self, handler: J) -> Layer { + Layer::new(handler, self) + } + + pub fn handler(&self) -> &H { + &self.handler + } + + pub fn inner(&self) -> &I { + &self.inner + } +} + +/// Compose handlers. +pub trait Layering { + /// Layer an executor on top of this one. + /// The `other` executor will be called first. + fn add_layer(self, other: L) -> Layer + where + Self: Sized + ForeignCallExecutor, + L: ForeignCallExecutor; +} + +impl Layering for T { + fn add_layer(self, other: L) -> Layer + where + T: Sized + ForeignCallExecutor, + L: ForeignCallExecutor, + { + Layer::new(other, self) + } +} + +/// Support disabling a layer by making it optional. +/// This way we can still have a known static type for a composition, +/// because layers are always added, potentially wrapped in an `Option`. +impl ForeignCallExecutor for Option +where + H: ForeignCallExecutor, +{ + fn execute( + &mut self, + foreign_call: &ForeignCallWaitInfo, + ) -> Result, ForeignCallError> { + match self { + Some(handler) => handler.execute(foreign_call), + None => Err(ForeignCallError::NoHandler(foreign_call.function.clone())), + } + } +} diff --git a/tooling/nargo/src/foreign_calls/mocker.rs b/tooling/nargo/src/foreign_calls/mocker.rs index c93d16bbaf6..59ce7479cd4 100644 --- a/tooling/nargo/src/foreign_calls/mocker.rs +++ b/tooling/nargo/src/foreign_calls/mocker.rs @@ -1,3 +1,5 @@ +use std::marker::PhantomData; + use acvm::{ acir::brillig::{ForeignCallParam, ForeignCallResult}, pwg::ForeignCallWaitInfo, @@ -45,7 +47,7 @@ impl MockedCall { } #[derive(Debug, Default)] -pub(crate) struct MockForeignCallExecutor { +pub struct MockForeignCallExecutor { /// Mocks have unique ids used to identify them in Noir, allowing to update or remove them. last_mock_id: usize, /// The registered mocks @@ -78,8 +80,9 @@ impl MockForeignCallExecutor { } } -impl Deserialize<'a>> ForeignCallExecutor - for MockForeignCallExecutor +impl ForeignCallExecutor for MockForeignCallExecutor +where + F: AcirField + Serialize + for<'a> Deserialize<'a>, { fn execute( &mut self, @@ -174,3 +177,32 @@ impl Deserialize<'a>> ForeignCallExecutor } } } + +/// Handler that panics if any of the mock functions are called. +#[allow(dead_code)] // TODO: Make the mocker optional +pub(crate) struct DisabledMockForeignCallExecutor { + _field: PhantomData, +} + +impl ForeignCallExecutor for DisabledMockForeignCallExecutor { + fn execute( + &mut self, + foreign_call: &ForeignCallWaitInfo, + ) -> Result, ForeignCallError> { + let foreign_call_name = foreign_call.function.as_str(); + if let Some(call) = ForeignCall::lookup(foreign_call_name) { + match call { + ForeignCall::CreateMock + | ForeignCall::SetMockParams + | ForeignCall::GetMockLastParams + | ForeignCall::SetMockReturns + | ForeignCall::SetMockTimes + | ForeignCall::ClearMock => { + panic!("unexpected mock call: {}", foreign_call.function) + } + _ => {} + } + } + Err(ForeignCallError::NoHandler(foreign_call.function.clone())) + } +} diff --git a/tooling/nargo/src/foreign_calls/mod.rs b/tooling/nargo/src/foreign_calls/mod.rs index 65ff051bcbf..72311558250 100644 --- a/tooling/nargo/src/foreign_calls/mod.rs +++ b/tooling/nargo/src/foreign_calls/mod.rs @@ -1,6 +1,7 @@ use std::path::PathBuf; use acvm::{acir::brillig::ForeignCallResult, pwg::ForeignCallWaitInfo, AcirField}; +use layers::{Layer, Layering}; use mocker::MockForeignCallExecutor; use noirc_printable_type::ForeignCallError; use print::{PrintForeignCallExecutor, PrintOutput}; @@ -8,6 +9,7 @@ use rand::Rng; use rpc::RPCForeignCallExecutor; use serde::{Deserialize, Serialize}; +pub mod layers; pub(crate) mod mocker; pub(crate) mod print; pub(crate) mod rpc; @@ -64,77 +66,46 @@ impl ForeignCall { } } -#[derive(Debug, Default)] -pub struct DefaultForeignCallExecutor<'a, F> { - /// The executor for any [`ForeignCall::Print`] calls. - printer: PrintForeignCallExecutor<'a>, - mocker: MockForeignCallExecutor, - external: Option, -} +pub struct DefaultForeignCallExecutor; -impl<'a, F: Default> DefaultForeignCallExecutor<'a, F> { - pub fn new( +impl DefaultForeignCallExecutor { + #[allow(clippy::new_ret_no_self)] + pub fn new<'a, F>( output: PrintOutput<'a>, resolver_url: Option<&str>, root_path: Option, package_name: Option, - ) -> Self { - let id = rand::thread_rng().gen(); - let printer = PrintForeignCallExecutor { output }; - let external_resolver = resolver_url.map(|resolver_url| { - RPCForeignCallExecutor::new(resolver_url, id, root_path, package_name) - }); - DefaultForeignCallExecutor { - printer, - mocker: MockForeignCallExecutor::default(), - external: external_resolver, - } + ) -> impl ForeignCallExecutor + 'a + where + F: AcirField + Serialize + for<'de> Deserialize<'de> + 'a, + { + Self::with_base(layers::Empty, output, resolver_url, root_path, package_name) } -} - -impl<'a, F: AcirField + Serialize + for<'b> Deserialize<'b>> ForeignCallExecutor - for DefaultForeignCallExecutor<'a, F> -{ - fn execute( - &mut self, - foreign_call: &ForeignCallWaitInfo, - ) -> Result, ForeignCallError> { - let foreign_call_name = foreign_call.function.as_str(); - match ForeignCall::lookup(foreign_call_name) { - Some(ForeignCall::Print) => self.printer.execute(foreign_call), - Some( - ForeignCall::CreateMock - | ForeignCall::SetMockParams - | ForeignCall::GetMockLastParams - | ForeignCall::SetMockReturns - | ForeignCall::SetMockTimes - | ForeignCall::ClearMock, - ) => self.mocker.execute(foreign_call), - - None => { - // First check if there's any defined mock responses for this foreign call. - match self.mocker.execute(foreign_call) { - Err(ForeignCallError::NoHandler(_)) => (), - response_or_error => return response_or_error, - }; - if let Some(external_resolver) = &mut self.external { - // If the user has registered an external resolver then we forward any remaining oracle calls there. - match external_resolver.execute(foreign_call) { - Err(ForeignCallError::NoHandler(_)) => (), - response_or_error => return response_or_error, - }; - } - - // If all executors have no handler for the given foreign call then we cannot - // return a correct response to the ACVM. The best we can do is to return an empty response, - // this allows us to ignore any foreign calls which exist solely to pass information from inside - // the circuit to the environment (e.g. custom logging) as the execution will still be able to progress. - // - // We optimistically return an empty response for all oracle calls as the ACVM will error - // should a response have been required. - Ok(ForeignCallResult::default()) - } - } + pub fn with_base<'a, F, B>( + base: B, + output: PrintOutput<'a>, + resolver_url: Option<&str>, + root_path: Option, + package_name: Option, + ) -> DefaultForeignCallLayers<'a, B, F> + where + F: AcirField + Serialize + for<'de> Deserialize<'de> + 'a, + B: ForeignCallExecutor + 'a, + { + // Adding them in the opposite order, so print is the outermost layer. + base.add_layer(resolver_url.map(|resolver_url| { + let id = rand::thread_rng().gen(); + RPCForeignCallExecutor::new(resolver_url, id, root_path, package_name) + })) + .add_layer(MockForeignCallExecutor::default()) + .add_layer(PrintForeignCallExecutor::new(output)) } } + +/// Facilitate static typing of layers on a base layer, so inner layers can be accessed. +pub type DefaultForeignCallLayers<'a, B, F> = Layer< + PrintForeignCallExecutor<'a>, + Layer, Layer, B, F>, F>, + F, +>; diff --git a/tooling/nargo/src/foreign_calls/print.rs b/tooling/nargo/src/foreign_calls/print.rs index 8b2b5efd8b6..5dc006ca775 100644 --- a/tooling/nargo/src/foreign_calls/print.rs +++ b/tooling/nargo/src/foreign_calls/print.rs @@ -12,8 +12,14 @@ pub enum PrintOutput<'a> { } #[derive(Debug, Default)] -pub(crate) struct PrintForeignCallExecutor<'a> { - pub(crate) output: PrintOutput<'a>, +pub struct PrintForeignCallExecutor<'a> { + output: PrintOutput<'a>, +} + +impl<'a> PrintForeignCallExecutor<'a> { + pub fn new(output: PrintOutput<'a>) -> Self { + Self { output } + } } impl ForeignCallExecutor for PrintForeignCallExecutor<'_> { diff --git a/tooling/nargo/src/foreign_calls/rpc.rs b/tooling/nargo/src/foreign_calls/rpc.rs index 565a2a036c3..aa11c24bc9f 100644 --- a/tooling/nargo/src/foreign_calls/rpc.rs +++ b/tooling/nargo/src/foreign_calls/rpc.rs @@ -12,7 +12,7 @@ use serde::{Deserialize, Serialize}; use super::ForeignCallExecutor; #[derive(Debug)] -pub(crate) struct RPCForeignCallExecutor { +pub struct RPCForeignCallExecutor { /// A randomly generated id for this `DefaultForeignCallExecutor`. /// /// This is used so that a single `external_resolver` can distinguish between requests from multiple @@ -54,7 +54,7 @@ struct ResolveForeignCallRequest { type ResolveForeignCallResult = Result, ForeignCallError>; impl RPCForeignCallExecutor { - pub(crate) fn new( + pub fn new( resolver_url: &str, id: u64, root_path: Option, diff --git a/tooling/nargo/src/ops/test.rs b/tooling/nargo/src/ops/test.rs index 1306150518d..56afbbf29ec 100644 --- a/tooling/nargo/src/ops/test.rs +++ b/tooling/nargo/src/ops/test.rs @@ -13,16 +13,13 @@ use noirc_driver::{compile_no_check, CompileError, CompileOptions, DEFAULT_EXPRE use noirc_errors::{debug_info::DebugInfo, FileDiagnostic}; use noirc_frontend::hir::{def_map::TestFunction, Context}; use noirc_printable_type::ForeignCallError; -use rand::Rng; use serde::{Deserialize, Serialize}; use crate::{ errors::try_to_diagnose_runtime_error, foreign_calls::{ - mocker::MockForeignCallExecutor, - print::{PrintForeignCallExecutor, PrintOutput}, - rpc::RPCForeignCallExecutor, - ForeignCall, ForeignCallExecutor, + layers, print::PrintOutput, DefaultForeignCallExecutor, DefaultForeignCallLayers, + ForeignCallExecutor, }, NargoError, }; @@ -279,32 +276,31 @@ fn check_expected_failure_message( /// A specialized foreign call executor which tracks whether it has encountered any unknown foreign calls struct TestForeignCallExecutor<'a, F> { - /// The executor for any [`ForeignCall::Print`] calls. - printer: PrintForeignCallExecutor<'a>, - mocker: MockForeignCallExecutor, - external: Option, - + executor: DefaultForeignCallLayers<'a, layers::Unhandled, F>, encountered_unknown_foreign_call: bool, } -impl<'a, F: Default> TestForeignCallExecutor<'a, F> { +impl<'a, F> TestForeignCallExecutor<'a, F> +where + F: Default + AcirField + Serialize + for<'de> Deserialize<'de> + 'a, +{ + #[allow(clippy::new_ret_no_self)] fn new( output: PrintOutput<'a>, resolver_url: Option<&str>, root_path: Option, package_name: Option, ) -> Self { - let id = rand::thread_rng().gen(); - let printer = PrintForeignCallExecutor { output }; - let external_resolver = resolver_url.map(|resolver_url| { - RPCForeignCallExecutor::new(resolver_url, id, root_path, package_name) - }); - TestForeignCallExecutor { - printer, - mocker: MockForeignCallExecutor::default(), - external: external_resolver, - encountered_unknown_foreign_call: false, - } + // Use a base layer that doesn't handle anything, which we handle in the `execute` below. + let executor = DefaultForeignCallExecutor::with_base( + layers::Unhandled, + output, + resolver_url, + root_path, + package_name, + ); + + Self { executor, encountered_unknown_foreign_call: false } } } @@ -317,46 +313,12 @@ impl<'a, F: AcirField + Serialize + for<'b> Deserialize<'b>> ForeignCallExecutor ) -> Result, ForeignCallError> { // If the circuit has reached a new foreign call opcode then it can't have failed from any previous unknown foreign calls. self.encountered_unknown_foreign_call = false; - - let foreign_call_name = foreign_call.function.as_str(); - match ForeignCall::lookup(foreign_call_name) { - Some(ForeignCall::Print) => self.printer.execute(foreign_call), - - Some( - ForeignCall::CreateMock - | ForeignCall::SetMockParams - | ForeignCall::GetMockLastParams - | ForeignCall::SetMockReturns - | ForeignCall::SetMockTimes - | ForeignCall::ClearMock, - ) => self.mocker.execute(foreign_call), - - None => { - // First check if there's any defined mock responses for this foreign call. - match self.mocker.execute(foreign_call) { - Err(ForeignCallError::NoHandler(_)) => (), - response_or_error => return response_or_error, - }; - - if let Some(external_resolver) = &mut self.external { - // If the user has registered an external resolver then we forward any remaining oracle calls there. - match external_resolver.execute(foreign_call) { - Err(ForeignCallError::NoHandler(_)) => (), - response_or_error => return response_or_error, - }; - } - + match self.executor.execute(foreign_call) { + Err(ForeignCallError::NoHandler(_)) => { self.encountered_unknown_foreign_call = true; - - // If all executors have no handler for the given foreign call then we cannot - // return a correct response to the ACVM. The best we can do is to return an empty response, - // this allows us to ignore any foreign calls which exist solely to pass information from inside - // the circuit to the environment (e.g. custom logging) as the execution will still be able to progress. - // - // We optimistically return an empty response for all oracle calls as the ACVM will error - // should a response have been required. - Ok(ForeignCallResult::default()) + layers::Empty.execute(foreign_call) } + other => other, } } } From 54fc751c134114d029ec76a66639cee0e8f02e96 Mon Sep 17 00:00:00 2001 From: Akosh Farkash Date: Thu, 19 Dec 2024 09:20:22 +0000 Subject: [PATCH 10/21] feat!: `nargo::ops::test::run_test` generic in `ForeignCallExecutor` (#6858) --- tooling/lsp/src/requests/test_run.rs | 13 +++- tooling/nargo/Cargo.toml | 11 ++-- tooling/nargo/src/foreign_calls/default.rs | 59 ++++++++++++++++++ tooling/nargo/src/foreign_calls/mocker.rs | 3 +- tooling/nargo/src/foreign_calls/mod.rs | 66 ++++---------------- tooling/nargo/src/lib.rs | 5 +- tooling/nargo/src/ops/mod.rs | 9 +-- tooling/nargo/src/ops/test.rs | 70 ++++++++-------------- tooling/nargo_cli/src/cli/test_cmd.rs | 17 ++++-- tooling/nargo_cli/tests/stdlib-tests.rs | 13 +++- 10 files changed, 136 insertions(+), 130 deletions(-) create mode 100644 tooling/nargo/src/foreign_calls/default.rs diff --git a/tooling/lsp/src/requests/test_run.rs b/tooling/lsp/src/requests/test_run.rs index 72ae6695b82..56fcb0325c3 100644 --- a/tooling/lsp/src/requests/test_run.rs +++ b/tooling/lsp/src/requests/test_run.rs @@ -3,6 +3,7 @@ use std::future::{self, Future}; use crate::insert_all_files_for_workspace_into_file_manager; use async_lsp::{ErrorCode, ResponseError}; use nargo::{ + foreign_calls::DefaultForeignCallExecutor, ops::{run_test, TestStatus}, PrintOutput, }; @@ -88,10 +89,16 @@ fn on_test_run_request_inner( &mut context, &test_function, PrintOutput::Stdout, - None, - Some(workspace.root_dir.clone()), - Some(package.name.to_string()), &CompileOptions::default(), + |output, base| { + DefaultForeignCallExecutor::with_base( + base, + output, + None, + Some(workspace.root_dir.clone()), + Some(package.name.to_string()), + ) + }, ); let result = match test_result { TestStatus::Pass => NargoTestRunResult { diff --git a/tooling/nargo/Cargo.toml b/tooling/nargo/Cargo.toml index a964ac5c071..9aa5f3ba530 100644 --- a/tooling/nargo/Cargo.toml +++ b/tooling/nargo/Cargo.toml @@ -27,21 +27,20 @@ tracing.workspace = true walkdir = "2.5.0" # Some dependencies are optional so we can compile to Wasm. -rand = { workspace = true, optional = true } serde = { workspace = true, optional = true } jsonrpsee = { workspace = true, optional = true } tokio = { workspace = true, optional = true } +rand = { workspace = true, optional = true } [target.'cfg(not(target_arch = "wasm32"))'.dependencies] -noir_fuzzer = { workspace = true, optional = true } -proptest = { workspace = true, optional = true } +noir_fuzzer = { workspace = true } +proptest = { workspace = true } [dev-dependencies] jsonrpsee = { workspace = true, features = ["server"] } [features] -default = ["execute", "test"] +default = ["rpc"] # Execution currently uses HTTP based Oracle resolvers; does not compile to Wasm. -execute = ["jsonrpsee/http-client", "jsonrpsee/macros", "tokio/rt", "serde", "rand"] -test = ["execute", "noir_fuzzer", "proptest"] +rpc = ["jsonrpsee/http-client", "jsonrpsee/macros", "tokio/rt", "serde", "rand"] diff --git a/tooling/nargo/src/foreign_calls/default.rs b/tooling/nargo/src/foreign_calls/default.rs new file mode 100644 index 00000000000..2cce946e3c2 --- /dev/null +++ b/tooling/nargo/src/foreign_calls/default.rs @@ -0,0 +1,59 @@ +use std::path::PathBuf; + +use acvm::AcirField; +use rand::Rng; +use serde::{Deserialize, Serialize}; + +use crate::PrintOutput; + +use super::{ + layers::{self, Layer, Layering}, + mocker::MockForeignCallExecutor, + print::PrintForeignCallExecutor, + rpc::RPCForeignCallExecutor, + ForeignCallExecutor, +}; + +pub struct DefaultForeignCallExecutor; + +impl DefaultForeignCallExecutor { + #[allow(clippy::new_ret_no_self)] + pub fn new<'a, F>( + output: PrintOutput<'a>, + resolver_url: Option<&str>, + root_path: Option, + package_name: Option, + ) -> impl ForeignCallExecutor + 'a + where + F: AcirField + Serialize + for<'de> Deserialize<'de> + 'a, + { + Self::with_base(layers::Empty, output, resolver_url, root_path, package_name) + } + + pub fn with_base<'a, F, B>( + base: B, + output: PrintOutput<'a>, + resolver_url: Option<&str>, + root_path: Option, + package_name: Option, + ) -> DefaultForeignCallLayers<'a, B, F> + where + F: AcirField + Serialize + for<'de> Deserialize<'de> + 'a, + B: ForeignCallExecutor + 'a, + { + // Adding them in the opposite order, so print is the outermost layer. + base.add_layer(resolver_url.map(|resolver_url| { + let id = rand::thread_rng().gen(); + RPCForeignCallExecutor::new(resolver_url, id, root_path, package_name) + })) + .add_layer(MockForeignCallExecutor::default()) + .add_layer(PrintForeignCallExecutor::new(output)) + } +} + +/// Facilitate static typing of layers on a base layer, so inner layers can be accessed. +pub type DefaultForeignCallLayers<'a, B, F> = Layer< + PrintForeignCallExecutor<'a>, + Layer, Layer, B, F>, F>, + F, +>; diff --git a/tooling/nargo/src/foreign_calls/mocker.rs b/tooling/nargo/src/foreign_calls/mocker.rs index 59ce7479cd4..42d788fcfc6 100644 --- a/tooling/nargo/src/foreign_calls/mocker.rs +++ b/tooling/nargo/src/foreign_calls/mocker.rs @@ -6,7 +6,6 @@ use acvm::{ AcirField, }; use noirc_printable_type::{decode_string_value, ForeignCallError}; -use serde::{Deserialize, Serialize}; use super::{ForeignCall, ForeignCallExecutor}; @@ -82,7 +81,7 @@ impl MockForeignCallExecutor { impl ForeignCallExecutor for MockForeignCallExecutor where - F: AcirField + Serialize + for<'a> Deserialize<'a>, + F: AcirField, { fn execute( &mut self, diff --git a/tooling/nargo/src/foreign_calls/mod.rs b/tooling/nargo/src/foreign_calls/mod.rs index 72311558250..a47a2ba8db8 100644 --- a/tooling/nargo/src/foreign_calls/mod.rs +++ b/tooling/nargo/src/foreign_calls/mod.rs @@ -1,18 +1,16 @@ -use std::path::PathBuf; - -use acvm::{acir::brillig::ForeignCallResult, pwg::ForeignCallWaitInfo, AcirField}; -use layers::{Layer, Layering}; -use mocker::MockForeignCallExecutor; +use acvm::{acir::brillig::ForeignCallResult, pwg::ForeignCallWaitInfo}; use noirc_printable_type::ForeignCallError; -use print::{PrintForeignCallExecutor, PrintOutput}; -use rand::Rng; -use rpc::RPCForeignCallExecutor; -use serde::{Deserialize, Serialize}; pub mod layers; -pub(crate) mod mocker; -pub(crate) mod print; -pub(crate) mod rpc; +pub mod mocker; +pub mod print; + +#[cfg(feature = "rpc")] +pub mod default; +#[cfg(feature = "rpc")] +pub mod rpc; +#[cfg(feature = "rpc")] +pub use default::DefaultForeignCallExecutor; pub trait ForeignCallExecutor { fn execute( @@ -65,47 +63,3 @@ impl ForeignCall { } } } - -pub struct DefaultForeignCallExecutor; - -impl DefaultForeignCallExecutor { - #[allow(clippy::new_ret_no_self)] - pub fn new<'a, F>( - output: PrintOutput<'a>, - resolver_url: Option<&str>, - root_path: Option, - package_name: Option, - ) -> impl ForeignCallExecutor + 'a - where - F: AcirField + Serialize + for<'de> Deserialize<'de> + 'a, - { - Self::with_base(layers::Empty, output, resolver_url, root_path, package_name) - } - - pub fn with_base<'a, F, B>( - base: B, - output: PrintOutput<'a>, - resolver_url: Option<&str>, - root_path: Option, - package_name: Option, - ) -> DefaultForeignCallLayers<'a, B, F> - where - F: AcirField + Serialize + for<'de> Deserialize<'de> + 'a, - B: ForeignCallExecutor + 'a, - { - // Adding them in the opposite order, so print is the outermost layer. - base.add_layer(resolver_url.map(|resolver_url| { - let id = rand::thread_rng().gen(); - RPCForeignCallExecutor::new(resolver_url, id, root_path, package_name) - })) - .add_layer(MockForeignCallExecutor::default()) - .add_layer(PrintForeignCallExecutor::new(output)) - } -} - -/// Facilitate static typing of layers on a base layer, so inner layers can be accessed. -pub type DefaultForeignCallLayers<'a, B, F> = Layer< - PrintForeignCallExecutor<'a>, - Layer, Layer, B, F>, F>, - F, ->; diff --git a/tooling/nargo/src/lib.rs b/tooling/nargo/src/lib.rs index 694d4846536..5a226449458 100644 --- a/tooling/nargo/src/lib.rs +++ b/tooling/nargo/src/lib.rs @@ -9,15 +9,12 @@ pub mod constants; pub mod errors; +pub mod foreign_calls; pub mod ops; pub mod package; pub mod workspace; -#[cfg(feature = "execute")] -pub mod foreign_calls; - pub use self::errors::NargoError; -#[cfg(feature = "execute")] pub use self::foreign_calls::print::PrintOutput; use std::{ diff --git a/tooling/nargo/src/ops/mod.rs b/tooling/nargo/src/ops/mod.rs index e6540eed834..7a52a829be3 100644 --- a/tooling/nargo/src/ops/mod.rs +++ b/tooling/nargo/src/ops/mod.rs @@ -6,17 +6,12 @@ pub use self::compile::{ pub use self::optimize::{optimize_contract, optimize_program}; pub use self::transform::{transform_contract, transform_program}; -#[cfg(feature = "execute")] pub use self::execute::{execute_program, execute_program_with_profiling}; -#[cfg(feature = "test")] pub use self::test::{run_test, TestStatus}; mod check; mod compile; -mod optimize; -mod transform; - -#[cfg(feature = "execute")] mod execute; -#[cfg(feature = "test")] +mod optimize; mod test; +mod transform; diff --git a/tooling/nargo/src/ops/test.rs b/tooling/nargo/src/ops/test.rs index 56afbbf29ec..660770e6ae1 100644 --- a/tooling/nargo/src/ops/test.rs +++ b/tooling/nargo/src/ops/test.rs @@ -1,5 +1,3 @@ -use std::path::PathBuf; - use acvm::{ acir::{ brillig::ForeignCallResult, @@ -13,14 +11,10 @@ use noirc_driver::{compile_no_check, CompileError, CompileOptions, DEFAULT_EXPRE use noirc_errors::{debug_info::DebugInfo, FileDiagnostic}; use noirc_frontend::hir::{def_map::TestFunction, Context}; use noirc_printable_type::ForeignCallError; -use serde::{Deserialize, Serialize}; use crate::{ errors::try_to_diagnose_runtime_error, - foreign_calls::{ - layers, print::PrintOutput, DefaultForeignCallExecutor, DefaultForeignCallLayers, - ForeignCallExecutor, - }, + foreign_calls::{layers, print::PrintOutput, ForeignCallExecutor}, NargoError, }; @@ -41,16 +35,19 @@ impl TestStatus { } #[allow(clippy::too_many_arguments)] -pub fn run_test>( +pub fn run_test<'a, B, F, E>( blackbox_solver: &B, context: &mut Context, test_function: &TestFunction, - output: PrintOutput<'_>, - foreign_call_resolver_url: Option<&str>, - root_path: Option, - package_name: Option, + output: PrintOutput<'a>, config: &CompileOptions, -) -> TestStatus { + foreign_call_executor: F, +) -> TestStatus +where + B: BlackBoxFunctionSolver, + F: Fn(PrintOutput<'a>, layers::Unhandled) -> E + 'a, + E: ForeignCallExecutor, +{ let test_function_has_no_arguments = context .def_interner .function_meta(&test_function.get_id()) @@ -67,12 +64,8 @@ pub fn run_test>( if test_function_has_no_arguments { // Run the backend to ensure the PWG evaluates functions like std::hash::pedersen, // otherwise constraints involving these expressions will not error. - let mut foreign_call_executor = TestForeignCallExecutor::new( - output, - foreign_call_resolver_url, - root_path, - package_name, - ); + let mut foreign_call_executor = + TestForeignCallExecutor::new(output, &foreign_call_executor); let circuit_execution = execute_program( &compiled_program.program, @@ -134,11 +127,9 @@ pub fn run_test>( program, initial_witness, blackbox_solver, - &mut TestForeignCallExecutor::::new( + &mut TestForeignCallExecutor::new( PrintOutput::None, - foreign_call_resolver_url, - root_path.clone(), - package_name.clone(), + &foreign_call_executor, ), ); @@ -275,37 +266,28 @@ fn check_expected_failure_message( } /// A specialized foreign call executor which tracks whether it has encountered any unknown foreign calls -struct TestForeignCallExecutor<'a, F> { - executor: DefaultForeignCallLayers<'a, layers::Unhandled, F>, +struct TestForeignCallExecutor { + executor: E, encountered_unknown_foreign_call: bool, } -impl<'a, F> TestForeignCallExecutor<'a, F> -where - F: Default + AcirField + Serialize + for<'de> Deserialize<'de> + 'a, -{ +impl TestForeignCallExecutor { #[allow(clippy::new_ret_no_self)] - fn new( - output: PrintOutput<'a>, - resolver_url: Option<&str>, - root_path: Option, - package_name: Option, - ) -> Self { + fn new<'a, F>(output: PrintOutput<'a>, foreign_call_executor: &F) -> Self + where + F: Fn(PrintOutput<'a>, layers::Unhandled) -> E + 'a, + { // Use a base layer that doesn't handle anything, which we handle in the `execute` below. - let executor = DefaultForeignCallExecutor::with_base( - layers::Unhandled, - output, - resolver_url, - root_path, - package_name, - ); + let executor = foreign_call_executor(output, layers::Unhandled); Self { executor, encountered_unknown_foreign_call: false } } } -impl<'a, F: AcirField + Serialize + for<'b> Deserialize<'b>> ForeignCallExecutor - for TestForeignCallExecutor<'a, F> +impl ForeignCallExecutor for TestForeignCallExecutor +where + F: AcirField, + E: ForeignCallExecutor, { fn execute( &mut self, diff --git a/tooling/nargo_cli/src/cli/test_cmd.rs b/tooling/nargo_cli/src/cli/test_cmd.rs index 1fd4ed2d873..f4f50acd37c 100644 --- a/tooling/nargo_cli/src/cli/test_cmd.rs +++ b/tooling/nargo_cli/src/cli/test_cmd.rs @@ -14,8 +14,9 @@ use clap::Args; use fm::FileManager; use formatters::{Formatter, JsonFormatter, PrettyFormatter, TerseFormatter}; use nargo::{ - insert_all_files_for_workspace_into_file_manager, ops::TestStatus, package::Package, parse_all, - prepare_package, workspace::Workspace, PrintOutput, + foreign_calls::DefaultForeignCallExecutor, insert_all_files_for_workspace_into_file_manager, + ops::TestStatus, package::Package, parse_all, prepare_package, workspace::Workspace, + PrintOutput, }; use nargo_toml::{get_package_manifest, resolve_workspace_from_toml}; use noirc_driver::{check_crate, CompileOptions, NOIR_ARTIFACT_VERSION_STRING}; @@ -494,10 +495,16 @@ impl<'a> TestRunner<'a> { &mut context, test_function, PrintOutput::String(&mut output_string), - foreign_call_resolver_url, - root_path, - Some(package_name), &self.args.compile_options, + |output, base| { + DefaultForeignCallExecutor::with_base( + base, + output, + foreign_call_resolver_url, + root_path.clone(), + Some(package_name.clone()), + ) + }, ); (test_status, output_string) } diff --git a/tooling/nargo_cli/tests/stdlib-tests.rs b/tooling/nargo_cli/tests/stdlib-tests.rs index 29b871814b8..bd08b0fd156 100644 --- a/tooling/nargo_cli/tests/stdlib-tests.rs +++ b/tooling/nargo_cli/tests/stdlib-tests.rs @@ -2,6 +2,7 @@ #![allow(clippy::items_after_test_module)] use clap::Parser; use fm::FileManager; +use nargo::foreign_calls::DefaultForeignCallExecutor; use nargo::PrintOutput; use noirc_driver::{check_crate, file_manager_with_stdlib, CompileOptions}; use noirc_frontend::hir::FunctionNameMatch; @@ -88,10 +89,16 @@ fn run_stdlib_tests(force_brillig: bool, inliner_aggressiveness: i64) { &mut context, &test_function, PrintOutput::Stdout, - None, - Some(dummy_package.root_dir.clone()), - Some(dummy_package.name.to_string()), &CompileOptions { force_brillig, inliner_aggressiveness, ..Default::default() }, + |output, base| { + DefaultForeignCallExecutor::with_base( + base, + output, + None, + Some(dummy_package.root_dir.clone()), + Some(dummy_package.name.to_string()), + ) + }, ); (test_name, status) }) From ee7901672aff2ac6f5224162a8f69e9da8a403bd Mon Sep 17 00:00:00 2001 From: Akosh Farkash Date: Thu, 19 Dec 2024 09:46:40 +0000 Subject: [PATCH 11/21] Layer doesn't need F --- tooling/debugger/src/foreign_calls.rs | 2 +- tooling/nargo/src/foreign_calls/default.rs | 3 +-- tooling/nargo/src/foreign_calls/layers.rs | 31 ++++++++++------------ 3 files changed, 16 insertions(+), 20 deletions(-) diff --git a/tooling/debugger/src/foreign_calls.rs b/tooling/debugger/src/foreign_calls.rs index 91242edecd5..740f6e3d76c 100644 --- a/tooling/debugger/src/foreign_calls.rs +++ b/tooling/debugger/src/foreign_calls.rs @@ -179,7 +179,7 @@ impl ForeignCallExecutor for DefaultDebugForeignCallExecutor { } } -impl DebugForeignCallExecutor for Layer +impl DebugForeignCallExecutor for Layer where H: DebugForeignCallExecutor, I: ForeignCallExecutor, diff --git a/tooling/nargo/src/foreign_calls/default.rs b/tooling/nargo/src/foreign_calls/default.rs index 2cce946e3c2..1929161bf11 100644 --- a/tooling/nargo/src/foreign_calls/default.rs +++ b/tooling/nargo/src/foreign_calls/default.rs @@ -54,6 +54,5 @@ impl DefaultForeignCallExecutor { /// Facilitate static typing of layers on a base layer, so inner layers can be accessed. pub type DefaultForeignCallLayers<'a, B, F> = Layer< PrintForeignCallExecutor<'a>, - Layer, Layer, B, F>, F>, - F, + Layer, Layer, B>>, >; diff --git a/tooling/nargo/src/foreign_calls/layers.rs b/tooling/nargo/src/foreign_calls/layers.rs index 16ea678f691..25df4e904aa 100644 --- a/tooling/nargo/src/foreign_calls/layers.rs +++ b/tooling/nargo/src/foreign_calls/layers.rs @@ -1,5 +1,3 @@ -use std::marker::PhantomData; - use acvm::{acir::brillig::ForeignCallResult, pwg::ForeignCallWaitInfo, AcirField}; use noirc_printable_type::ForeignCallError; @@ -38,13 +36,12 @@ impl ForeignCallExecutor for Unhandled { } /// Forwards to the inner executor if its own handler doesn't handle the call. -pub struct Layer { +pub struct Layer { pub handler: H, pub inner: I, - _field: PhantomData, } -impl ForeignCallExecutor for Layer +impl ForeignCallExecutor for Layer where H: ForeignCallExecutor, I: ForeignCallExecutor, @@ -60,39 +57,39 @@ where } } -impl Layer { +impl Layer { /// Create a layer from two handlers pub fn new(handler: H, inner: I) -> Self { - Self { handler, inner, _field: PhantomData } + Self { handler, inner } } } -impl Layer { +impl Layer { /// Create a layer from a handler. /// If the handler doesn't handle a call, a default empty response is returned. pub fn or_empty(handler: H) -> Self { - Self { handler, inner: Empty, _field: PhantomData } + Self { handler, inner: Empty } } } -impl Layer { +impl Layer { /// Create a layer from a handler. /// If the handler doesn't handle a call, `NoHandler` error is returned. pub fn or_unhandled(handler: H) -> Self { - Self { handler, inner: Unhandled, _field: PhantomData } + Self { handler, inner: Unhandled } } } -impl Layer { +impl Layer { /// A base layer that doesn't handle anything. pub fn unhandled() -> Self { - Self { handler: Unhandled, inner: Unhandled, _field: PhantomData } + Self { handler: Unhandled, inner: Unhandled } } } -impl Layer { +impl Layer { /// Add another layer on top of this one. - pub fn add_layer(self, handler: J) -> Layer { + pub fn add_layer(self, handler: J) -> Layer { Layer::new(handler, self) } @@ -109,14 +106,14 @@ impl Layer { pub trait Layering { /// Layer an executor on top of this one. /// The `other` executor will be called first. - fn add_layer(self, other: L) -> Layer + fn add_layer(self, other: L) -> Layer where Self: Sized + ForeignCallExecutor, L: ForeignCallExecutor; } impl Layering for T { - fn add_layer(self, other: L) -> Layer + fn add_layer(self, other: L) -> Layer where T: Sized + ForeignCallExecutor, L: ForeignCallExecutor, From d0d5c1a68b90f82a90c91e6aea0f473671e05e3e Mon Sep 17 00:00:00 2001 From: Akosh Farkash Date: Thu, 19 Dec 2024 09:48:14 +0000 Subject: [PATCH 12/21] Use add_layer in debug --- tooling/debugger/src/foreign_calls.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/tooling/debugger/src/foreign_calls.rs b/tooling/debugger/src/foreign_calls.rs index 740f6e3d76c..1cd133e238d 100644 --- a/tooling/debugger/src/foreign_calls.rs +++ b/tooling/debugger/src/foreign_calls.rs @@ -4,7 +4,10 @@ use acvm::{ AcirField, FieldElement, }; use nargo::{ - foreign_calls::{layers::Layer, DefaultForeignCallExecutor, ForeignCallExecutor}, + foreign_calls::{ + layers::{Layer, Layering}, + DefaultForeignCallExecutor, ForeignCallExecutor, + }, PrintOutput, }; use noirc_artifacts::debug::{DebugArtifact, DebugVars, StackFrame}; @@ -50,11 +53,11 @@ pub struct DefaultDebugForeignCallExecutor { } impl DefaultDebugForeignCallExecutor { - pub fn make( + fn make( output: PrintOutput<'_>, ex: DefaultDebugForeignCallExecutor, ) -> impl DebugForeignCallExecutor + '_ { - Layer::new(ex, DefaultForeignCallExecutor::new(output, None, None, None)) + DefaultForeignCallExecutor::new(output, None, None, None).add_layer(ex) } #[allow(clippy::new_ret_no_self, dead_code)] From 2516d16608a56c9ba5a225d49da51db11cffcce1 Mon Sep 17 00:00:00 2001 From: Tom French <15848336+TomAFrench@users.noreply.github.com> Date: Thu, 19 Dec 2024 10:22:28 +0000 Subject: [PATCH 13/21] Update compiler/wasm/Cargo.toml --- compiler/wasm/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/wasm/Cargo.toml b/compiler/wasm/Cargo.toml index b7bf7ce3c06..115ccf6ff41 100644 --- a/compiler/wasm/Cargo.toml +++ b/compiler/wasm/Cargo.toml @@ -33,7 +33,7 @@ gloo-utils.workspace = true tracing-subscriber.workspace = true tracing-web.workspace = true -# Disable the execution feature so we don't get the HTTP dependency which doesn't compile to Wasm. +# Disable the rpc feature so we don't get the HTTP dependency which doesn't compile to Wasm. # Cannot use `workspace = true` because it would unify all packages and compile with the default # features on, ignoring the setting here, but with `path` it works. nargo = { path = "../../tooling/nargo", default-features = false } From 1d9bfdd1a663546bc126ecd92604e37bd29decba Mon Sep 17 00:00:00 2001 From: Akosh Farkash Date: Thu, 19 Dec 2024 13:50:48 +0000 Subject: [PATCH 14/21] Make the rpc feature opt-in --- compiler/wasm/Cargo.toml | 2 +- tooling/nargo/Cargo.toml | 6 +- tooling/nargo/src/foreign_calls/default.rs | 101 +++++++++++++++++---- tooling/nargo/src/foreign_calls/mod.rs | 1 - tooling/nargo_cli/Cargo.toml | 8 +- 5 files changed, 93 insertions(+), 25 deletions(-) diff --git a/compiler/wasm/Cargo.toml b/compiler/wasm/Cargo.toml index b7bf7ce3c06..ae87ca9c55f 100644 --- a/compiler/wasm/Cargo.toml +++ b/compiler/wasm/Cargo.toml @@ -36,7 +36,7 @@ tracing-web.workspace = true # Disable the execution feature so we don't get the HTTP dependency which doesn't compile to Wasm. # Cannot use `workspace = true` because it would unify all packages and compile with the default # features on, ignoring the setting here, but with `path` it works. -nargo = { path = "../../tooling/nargo", default-features = false } +nargo.workspace = true # This is an unused dependency, we are adding it # so that we can enable the js feature in getrandom. diff --git a/tooling/nargo/Cargo.toml b/tooling/nargo/Cargo.toml index 9aa5f3ba530..ef5500131f3 100644 --- a/tooling/nargo/Cargo.toml +++ b/tooling/nargo/Cargo.toml @@ -22,12 +22,12 @@ noirc_frontend.workspace = true noirc_printable_type.workspace = true iter-extended.workspace = true rayon.workspace = true +serde = { workspace = true } thiserror.workspace = true tracing.workspace = true walkdir = "2.5.0" # Some dependencies are optional so we can compile to Wasm. -serde = { workspace = true, optional = true } jsonrpsee = { workspace = true, optional = true } tokio = { workspace = true, optional = true } rand = { workspace = true, optional = true } @@ -40,7 +40,7 @@ proptest = { workspace = true } jsonrpsee = { workspace = true, features = ["server"] } [features] -default = ["rpc"] +default = [] # Execution currently uses HTTP based Oracle resolvers; does not compile to Wasm. -rpc = ["jsonrpsee/http-client", "jsonrpsee/macros", "tokio/rt", "serde", "rand"] +rpc = ["jsonrpsee/http-client", "jsonrpsee/macros", "tokio/rt", "rand"] diff --git a/tooling/nargo/src/foreign_calls/default.rs b/tooling/nargo/src/foreign_calls/default.rs index 1929161bf11..2428457fdca 100644 --- a/tooling/nargo/src/foreign_calls/default.rs +++ b/tooling/nargo/src/foreign_calls/default.rs @@ -1,7 +1,4 @@ -use std::path::PathBuf; - use acvm::AcirField; -use rand::Rng; use serde::{Deserialize, Serialize}; use crate::PrintOutput; @@ -10,18 +7,90 @@ use super::{ layers::{self, Layer, Layering}, mocker::MockForeignCallExecutor, print::PrintForeignCallExecutor, - rpc::RPCForeignCallExecutor, ForeignCallExecutor, }; +#[cfg(feature = "rpc")] +use super::rpc::RPCForeignCallExecutor; + +/// A configuration where we can enable fields based on feature flags, +/// which is easier than providing different overrides for `new`. +#[derive(Default)] +pub struct DefaultForeignCallConfig<'a> { + pub output: PrintOutput<'a>, + #[cfg(feature = "rpc")] + pub resolver_url: Option, + #[cfg(feature = "rpc")] + pub root_path: Option, + #[cfg(feature = "rpc")] + pub package_name: Option, +} + +impl<'a> DefaultForeignCallConfig<'a> { + pub fn build(self) -> DefaultForeignCallLayers<'a, layers::Empty, F> + where + F: AcirField + Serialize + for<'de> Deserialize<'de> + 'a, + { + self.build_with_base(layers::Empty) + } + + pub fn build_with_base(self, base: B) -> DefaultForeignCallLayers<'a, B, F> + where + F: AcirField + Serialize + for<'de> Deserialize<'de> + 'a, + B: ForeignCallExecutor + 'a, + { + let executor = { + #[cfg(feature = "rpc")] + { + use rand::Rng; + + base.add_layer(self.resolver_url.map(|resolver_url| { + let id = rand::thread_rng().gen(); + RPCForeignCallExecutor::new( + &resolver_url, + id, + self.root_path, + self.package_name, + ) + })) + } + #[cfg(not(feature = "rpc"))] + { + base + } + }; + + executor + .add_layer(MockForeignCallExecutor::default()) + .add_layer(PrintForeignCallExecutor::new(self.output)) + } +} + +/// Facilitate static typing of layers on a base layer, so inner layers can be accessed. +#[cfg(feature = "rpc")] +pub type DefaultForeignCallLayers<'a, B, F> = Layer< + PrintForeignCallExecutor<'a>, + Layer, Layer, B>>, +>; +#[cfg(not(feature = "rpc"))] +pub type DefaultForeignCallLayers<'a, B, F> = + Layer, Layer, B>>; + +/// Convenience constructor for code that used to create the executor this way. +#[cfg(feature = "rpc")] pub struct DefaultForeignCallExecutor; +/// Convenience constructors for the RPC case. Non-RPC versions are not provided +/// because once a crate opts into this within the workspace, everyone gets it +/// even if they don't want to. For the non-RPC case we can nudge people to +/// use `DefaultForeignCallConfig` which is easier to keep flexible. +#[cfg(feature = "rpc")] impl DefaultForeignCallExecutor { #[allow(clippy::new_ret_no_self)] pub fn new<'a, F>( output: PrintOutput<'a>, resolver_url: Option<&str>, - root_path: Option, + root_path: Option, package_name: Option, ) -> impl ForeignCallExecutor + 'a where @@ -34,25 +103,19 @@ impl DefaultForeignCallExecutor { base: B, output: PrintOutput<'a>, resolver_url: Option<&str>, - root_path: Option, + root_path: Option, package_name: Option, ) -> DefaultForeignCallLayers<'a, B, F> where F: AcirField + Serialize + for<'de> Deserialize<'de> + 'a, B: ForeignCallExecutor + 'a, { - // Adding them in the opposite order, so print is the outermost layer. - base.add_layer(resolver_url.map(|resolver_url| { - let id = rand::thread_rng().gen(); - RPCForeignCallExecutor::new(resolver_url, id, root_path, package_name) - })) - .add_layer(MockForeignCallExecutor::default()) - .add_layer(PrintForeignCallExecutor::new(output)) + DefaultForeignCallConfig { + output, + resolver_url: resolver_url.map(|s| s.to_string()), + root_path, + package_name, + } + .build_with_base(base) } } - -/// Facilitate static typing of layers on a base layer, so inner layers can be accessed. -pub type DefaultForeignCallLayers<'a, B, F> = Layer< - PrintForeignCallExecutor<'a>, - Layer, Layer, B>>, ->; diff --git a/tooling/nargo/src/foreign_calls/mod.rs b/tooling/nargo/src/foreign_calls/mod.rs index a47a2ba8db8..448b5520d3a 100644 --- a/tooling/nargo/src/foreign_calls/mod.rs +++ b/tooling/nargo/src/foreign_calls/mod.rs @@ -5,7 +5,6 @@ pub mod layers; pub mod mocker; pub mod print; -#[cfg(feature = "rpc")] pub mod default; #[cfg(feature = "rpc")] pub mod rpc; diff --git a/tooling/nargo_cli/Cargo.toml b/tooling/nargo_cli/Cargo.toml index 5603b7f4fca..1d1d1643fd1 100644 --- a/tooling/nargo_cli/Cargo.toml +++ b/tooling/nargo_cli/Cargo.toml @@ -27,7 +27,13 @@ clap.workspace = true fm.workspace = true fxhash.workspace = true iter-extended.workspace = true -nargo.workspace = true +# This is the only crate that really needs the RPC feature, +# but enabling it here implicitly enables it for the whole +# workspace. A crate could opt out using `path` dependency, +# but it's only `noir_wasm` which couldn't compile with it, +# and that is a different target, and for that the feature +# aren't unified with this one. +nargo = { workspace = true, features = ["rpc"] } nargo_fmt.workspace = true nargo_toml.workspace = true noir_lsp.workspace = true From c8e31c72572588a48cb6c713793e0ce62439fea3 Mon Sep 17 00:00:00 2001 From: Akosh Farkash Date: Thu, 19 Dec 2024 14:20:38 +0000 Subject: [PATCH 15/21] Use the DefaultForeignCallBuilder where its mostly None we're passing --- tooling/acvm_cli/src/cli/execute_cmd.rs | 5 +-- tooling/debugger/src/foreign_calls.rs | 7 ++-- tooling/lsp/src/requests/test_run.rs | 14 ++++---- tooling/nargo/src/foreign_calls/default.rs | 36 ++++++++----------- tooling/nargo/src/foreign_calls/mod.rs | 1 + tooling/nargo_cli/benches/criterion.rs | 3 +- tooling/nargo_cli/src/cli/info_cmd.rs | 5 ++- tooling/nargo_cli/src/cli/test_cmd.rs | 14 ++++---- tooling/nargo_cli/tests/stdlib-props.rs | 7 ++-- tooling/nargo_cli/tests/stdlib-tests.rs | 10 ++---- .../src/cli/execution_flamegraph_cmd.rs | 4 +-- 11 files changed, 44 insertions(+), 62 deletions(-) diff --git a/tooling/acvm_cli/src/cli/execute_cmd.rs b/tooling/acvm_cli/src/cli/execute_cmd.rs index d4473eb3eef..c3c83a8f000 100644 --- a/tooling/acvm_cli/src/cli/execute_cmd.rs +++ b/tooling/acvm_cli/src/cli/execute_cmd.rs @@ -9,7 +9,7 @@ use nargo::PrintOutput; use crate::cli::fs::inputs::{read_bytecode_from_file, read_inputs_from_file}; use crate::errors::CliError; -use nargo::{foreign_calls::DefaultForeignCallExecutor, ops::execute_program}; +use nargo::{foreign_calls::DefaultForeignCallBuilder, ops::execute_program}; use super::fs::witness::{create_output_witness_string, save_witness_to_dir}; @@ -74,7 +74,8 @@ pub(crate) fn execute_program_from_witness( &program, inputs_map, &Bn254BlackBoxSolver, - &mut DefaultForeignCallExecutor::new(PrintOutput::Stdout, None, None, None), + &mut DefaultForeignCallBuilder { output: PrintOutput::Stdout, ..Default::default() } + .build(), ) .map_err(CliError::CircuitExecutionError) } diff --git a/tooling/debugger/src/foreign_calls.rs b/tooling/debugger/src/foreign_calls.rs index 1cd133e238d..352fc468491 100644 --- a/tooling/debugger/src/foreign_calls.rs +++ b/tooling/debugger/src/foreign_calls.rs @@ -4,10 +4,7 @@ use acvm::{ AcirField, FieldElement, }; use nargo::{ - foreign_calls::{ - layers::{Layer, Layering}, - DefaultForeignCallExecutor, ForeignCallExecutor, - }, + foreign_calls::{layers::Layer, DefaultForeignCallBuilder, ForeignCallExecutor}, PrintOutput, }; use noirc_artifacts::debug::{DebugArtifact, DebugVars, StackFrame}; @@ -57,7 +54,7 @@ impl DefaultDebugForeignCallExecutor { output: PrintOutput<'_>, ex: DefaultDebugForeignCallExecutor, ) -> impl DebugForeignCallExecutor + '_ { - DefaultForeignCallExecutor::new(output, None, None, None).add_layer(ex) + DefaultForeignCallBuilder::default().with_output(output).build().add_layer(ex) } #[allow(clippy::new_ret_no_self, dead_code)] diff --git a/tooling/lsp/src/requests/test_run.rs b/tooling/lsp/src/requests/test_run.rs index 56fcb0325c3..1071866dfad 100644 --- a/tooling/lsp/src/requests/test_run.rs +++ b/tooling/lsp/src/requests/test_run.rs @@ -3,7 +3,7 @@ use std::future::{self, Future}; use crate::insert_all_files_for_workspace_into_file_manager; use async_lsp::{ErrorCode, ResponseError}; use nargo::{ - foreign_calls::DefaultForeignCallExecutor, + foreign_calls::DefaultForeignCallBuilder, ops::{run_test, TestStatus}, PrintOutput, }; @@ -91,13 +91,13 @@ fn on_test_run_request_inner( PrintOutput::Stdout, &CompileOptions::default(), |output, base| { - DefaultForeignCallExecutor::with_base( - base, + DefaultForeignCallBuilder { output, - None, - Some(workspace.root_dir.clone()), - Some(package.name.to_string()), - ) + resolver_url: None, // NB without this the root and package don't do anything. + root_path: Some(workspace.root_dir.clone()), + package_name: Some(package.name.to_string()), + } + .build_with_base(base) }, ); let result = match test_result { diff --git a/tooling/nargo/src/foreign_calls/default.rs b/tooling/nargo/src/foreign_calls/default.rs index 2428457fdca..ce4af3aa744 100644 --- a/tooling/nargo/src/foreign_calls/default.rs +++ b/tooling/nargo/src/foreign_calls/default.rs @@ -13,10 +13,10 @@ use super::{ #[cfg(feature = "rpc")] use super::rpc::RPCForeignCallExecutor; -/// A configuration where we can enable fields based on feature flags, -/// which is easier than providing different overrides for `new`. +/// A builder for [DefaultForeignCallLayers] where we can enable fields based on feature flags, +/// which is easier than providing different overrides for a `new` method. #[derive(Default)] -pub struct DefaultForeignCallConfig<'a> { +pub struct DefaultForeignCallBuilder<'a> { pub output: PrintOutput<'a>, #[cfg(feature = "rpc")] pub resolver_url: Option, @@ -26,7 +26,14 @@ pub struct DefaultForeignCallConfig<'a> { pub package_name: Option, } -impl<'a> DefaultForeignCallConfig<'a> { +impl<'a> DefaultForeignCallBuilder<'a> { + /// Override the output. + pub fn with_output(mut self, output: PrintOutput<'a>) -> Self { + self.output = output; + self + } + + /// Compose the executor layers with [layers::Empty] as the default handler. pub fn build(self) -> DefaultForeignCallLayers<'a, layers::Empty, F> where F: AcirField + Serialize + for<'de> Deserialize<'de> + 'a, @@ -34,6 +41,7 @@ impl<'a> DefaultForeignCallConfig<'a> { self.build_with_base(layers::Empty) } + /// Compose the executor layers with `base` as the default handler. pub fn build_with_base(self, base: B) -> DefaultForeignCallLayers<'a, B, F> where F: AcirField + Serialize + for<'de> Deserialize<'de> + 'a, @@ -83,7 +91,7 @@ pub struct DefaultForeignCallExecutor; /// Convenience constructors for the RPC case. Non-RPC versions are not provided /// because once a crate opts into this within the workspace, everyone gets it /// even if they don't want to. For the non-RPC case we can nudge people to -/// use `DefaultForeignCallConfig` which is easier to keep flexible. +/// use `DefaultForeignCallBuilder` which is easier to keep flexible. #[cfg(feature = "rpc")] impl DefaultForeignCallExecutor { #[allow(clippy::new_ret_no_self)] @@ -96,26 +104,12 @@ impl DefaultForeignCallExecutor { where F: AcirField + Serialize + for<'de> Deserialize<'de> + 'a, { - Self::with_base(layers::Empty, output, resolver_url, root_path, package_name) - } - - pub fn with_base<'a, F, B>( - base: B, - output: PrintOutput<'a>, - resolver_url: Option<&str>, - root_path: Option, - package_name: Option, - ) -> DefaultForeignCallLayers<'a, B, F> - where - F: AcirField + Serialize + for<'de> Deserialize<'de> + 'a, - B: ForeignCallExecutor + 'a, - { - DefaultForeignCallConfig { + DefaultForeignCallBuilder { output, resolver_url: resolver_url.map(|s| s.to_string()), root_path, package_name, } - .build_with_base(base) + .build() } } diff --git a/tooling/nargo/src/foreign_calls/mod.rs b/tooling/nargo/src/foreign_calls/mod.rs index 448b5520d3a..4a5e840fa83 100644 --- a/tooling/nargo/src/foreign_calls/mod.rs +++ b/tooling/nargo/src/foreign_calls/mod.rs @@ -8,6 +8,7 @@ pub mod print; pub mod default; #[cfg(feature = "rpc")] pub mod rpc; +pub use default::DefaultForeignCallBuilder; #[cfg(feature = "rpc")] pub use default::DefaultForeignCallExecutor; diff --git a/tooling/nargo_cli/benches/criterion.rs b/tooling/nargo_cli/benches/criterion.rs index 9bc50f87d8e..3d81ade65bc 100644 --- a/tooling/nargo_cli/benches/criterion.rs +++ b/tooling/nargo_cli/benches/criterion.rs @@ -3,7 +3,6 @@ use acvm::{acir::native_types::WitnessMap, FieldElement}; use assert_cmd::prelude::{CommandCargoExt, OutputAssertExt}; use criterion::{criterion_group, criterion_main, Criterion}; -use nargo::PrintOutput; use noirc_abi::{ input_parser::{Format, InputValue}, Abi, InputMap, @@ -116,7 +115,7 @@ fn criterion_test_execution(c: &mut Criterion, test_program_dir: &Path, force_br let artifacts = RefCell::new(None); let mut foreign_call_executor = - nargo::foreign_calls::DefaultForeignCallExecutor::new(PrintOutput::None, None, None, None); + nargo::foreign_calls::DefaultForeignCallBuilder::default().build(); c.bench_function(&benchmark_name, |b| { b.iter_batched( diff --git a/tooling/nargo_cli/src/cli/info_cmd.rs b/tooling/nargo_cli/src/cli/info_cmd.rs index ee8ff32922e..6320cbbf350 100644 --- a/tooling/nargo_cli/src/cli/info_cmd.rs +++ b/tooling/nargo_cli/src/cli/info_cmd.rs @@ -3,8 +3,7 @@ use bn254_blackbox_solver::Bn254BlackBoxSolver; use clap::Args; use iter_extended::vecmap; use nargo::{ - constants::PROVER_INPUT_FILE, foreign_calls::DefaultForeignCallExecutor, package::Package, - PrintOutput, + constants::PROVER_INPUT_FILE, foreign_calls::DefaultForeignCallBuilder, package::Package, }; use nargo_toml::{get_package_manifest, resolve_workspace_from_toml}; use noirc_abi::input_parser::Format; @@ -255,7 +254,7 @@ fn profile_brillig_execution( &program_artifact.bytecode, initial_witness, &Bn254BlackBoxSolver, - &mut DefaultForeignCallExecutor::new(PrintOutput::None, None, None, None), + &mut DefaultForeignCallBuilder::default().build(), )?; let expression_width = get_target_width(package.expression_width, expression_width); diff --git a/tooling/nargo_cli/src/cli/test_cmd.rs b/tooling/nargo_cli/src/cli/test_cmd.rs index f4f50acd37c..43f1c306d88 100644 --- a/tooling/nargo_cli/src/cli/test_cmd.rs +++ b/tooling/nargo_cli/src/cli/test_cmd.rs @@ -14,7 +14,7 @@ use clap::Args; use fm::FileManager; use formatters::{Formatter, JsonFormatter, PrettyFormatter, TerseFormatter}; use nargo::{ - foreign_calls::DefaultForeignCallExecutor, insert_all_files_for_workspace_into_file_manager, + foreign_calls::DefaultForeignCallBuilder, insert_all_files_for_workspace_into_file_manager, ops::TestStatus, package::Package, parse_all, prepare_package, workspace::Workspace, PrintOutput, }; @@ -497,13 +497,13 @@ impl<'a> TestRunner<'a> { PrintOutput::String(&mut output_string), &self.args.compile_options, |output, base| { - DefaultForeignCallExecutor::with_base( - base, + DefaultForeignCallBuilder { output, - foreign_call_resolver_url, - root_path.clone(), - Some(package_name.clone()), - ) + resolver_url: foreign_call_resolver_url.map(|s| s.to_string()), + root_path: root_path.clone(), + package_name: Some(package_name.clone()), + } + .build_with_base(base) }, ); (test_status, output_string) diff --git a/tooling/nargo_cli/tests/stdlib-props.rs b/tooling/nargo_cli/tests/stdlib-props.rs index a19408bd5fd..fd0733ff962 100644 --- a/tooling/nargo_cli/tests/stdlib-props.rs +++ b/tooling/nargo_cli/tests/stdlib-props.rs @@ -2,9 +2,7 @@ use std::{cell::RefCell, collections::BTreeMap, path::Path}; use acvm::{acir::native_types::WitnessStack, AcirField, FieldElement}; use iter_extended::vecmap; -use nargo::{ - foreign_calls::DefaultForeignCallExecutor, ops::execute_program, parse_all, PrintOutput, -}; +use nargo::{foreign_calls::DefaultForeignCallBuilder, ops::execute_program, parse_all}; use noirc_abi::input_parser::InputValue; use noirc_driver::{ compile_main, file_manager_with_stdlib, prepare_crate, CompilationResult, CompileOptions, @@ -81,8 +79,7 @@ fn run_snippet_proptest( }; let blackbox_solver = bn254_blackbox_solver::Bn254BlackBoxSolver; - let foreign_call_executor = - RefCell::new(DefaultForeignCallExecutor::new(PrintOutput::None, None, None, None)); + let foreign_call_executor = RefCell::new(DefaultForeignCallBuilder::default().build()); // Generate multiple input/output proptest!(ProptestConfig::with_cases(100), |(io in strategy)| { diff --git a/tooling/nargo_cli/tests/stdlib-tests.rs b/tooling/nargo_cli/tests/stdlib-tests.rs index bd08b0fd156..6aae94f6645 100644 --- a/tooling/nargo_cli/tests/stdlib-tests.rs +++ b/tooling/nargo_cli/tests/stdlib-tests.rs @@ -2,7 +2,7 @@ #![allow(clippy::items_after_test_module)] use clap::Parser; use fm::FileManager; -use nargo::foreign_calls::DefaultForeignCallExecutor; +use nargo::foreign_calls::DefaultForeignCallBuilder; use nargo::PrintOutput; use noirc_driver::{check_crate, file_manager_with_stdlib, CompileOptions}; use noirc_frontend::hir::FunctionNameMatch; @@ -91,13 +91,7 @@ fn run_stdlib_tests(force_brillig: bool, inliner_aggressiveness: i64) { PrintOutput::Stdout, &CompileOptions { force_brillig, inliner_aggressiveness, ..Default::default() }, |output, base| { - DefaultForeignCallExecutor::with_base( - base, - output, - None, - Some(dummy_package.root_dir.clone()), - Some(dummy_package.name.to_string()), - ) + DefaultForeignCallBuilder { output, ..Default::default() }.build_with_base(base) }, ); (test_name, status) diff --git a/tooling/profiler/src/cli/execution_flamegraph_cmd.rs b/tooling/profiler/src/cli/execution_flamegraph_cmd.rs index 76b23ebf739..bab15529744 100644 --- a/tooling/profiler/src/cli/execution_flamegraph_cmd.rs +++ b/tooling/profiler/src/cli/execution_flamegraph_cmd.rs @@ -3,13 +3,13 @@ use std::path::{Path, PathBuf}; use acir::circuit::OpcodeLocation; use clap::Args; use color_eyre::eyre::{self, Context}; +use nargo::foreign_calls::DefaultForeignCallBuilder; use nargo::PrintOutput; use crate::flamegraph::{BrilligExecutionSample, FlamegraphGenerator, InfernoFlamegraphGenerator}; use crate::fs::{read_inputs_from_file, read_program_from_file}; use crate::opcode_formatter::format_brillig_opcode; use bn254_blackbox_solver::Bn254BlackBoxSolver; -use nargo::foreign_calls::DefaultForeignCallExecutor; use noirc_abi::input_parser::Format; use noirc_artifacts::debug::DebugArtifact; @@ -55,7 +55,7 @@ fn run_with_generator( &program.bytecode, initial_witness, &Bn254BlackBoxSolver, - &mut DefaultForeignCallExecutor::new(PrintOutput::Stdout, None, None, None), + &mut DefaultForeignCallBuilder::default().with_output(PrintOutput::Stdout).build(), )?; println!("Executed"); From b97e5ac929807d4fb99049312f4a34bbea77c3a1 Mon Sep 17 00:00:00 2001 From: Akosh Farkash Date: Thu, 19 Dec 2024 14:23:59 +0000 Subject: [PATCH 16/21] Update compiler/wasm/Cargo.toml --- compiler/wasm/Cargo.toml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/compiler/wasm/Cargo.toml b/compiler/wasm/Cargo.toml index aed63d46d95..5cde0dfbbcf 100644 --- a/compiler/wasm/Cargo.toml +++ b/compiler/wasm/Cargo.toml @@ -33,9 +33,8 @@ gloo-utils.workspace = true tracing-subscriber.workspace = true tracing-web.workspace = true -# Disable the rpc feature so we don't get the HTTP dependency which doesn't compile to Wasm. -# Cannot use `workspace = true` because it would unify all packages and compile with the default -# features on, ignoring the setting here, but with `path` it works. +# Cannot use the `rpc` feature because the HTTP dependency wouldn't compile to Wasm. +# We could use `path` if `rpc` was a default feature, but we made it opt-in so we don't get any problems when publishing the workspace. nargo.workspace = true # This is an unused dependency, we are adding it From fa863be2b5ed69a6e613f03ae5eeb04264d70819 Mon Sep 17 00:00:00 2001 From: Tom French Date: Thu, 2 Jan 2025 14:06:19 +0000 Subject: [PATCH 17/21] Merge branch 'master' into 6742-jsonrpsee * master: chore: move implementation of print foreign call into `nargo` (#6865) chore: document format strings (#6920) --- Cargo.lock | 5 +- compiler/noirc_printable_type/Cargo.toml | 4 - compiler/noirc_printable_type/src/lib.rs | 212 ++---------------- docs/docs/noir/concepts/data_types/strings.md | 35 +++ .../noir/concepts/data_types/strings.md | 35 +++ tooling/debugger/src/foreign_calls.rs | 5 +- tooling/nargo/Cargo.toml | 3 +- tooling/nargo/src/errors.rs | 3 +- tooling/nargo/src/foreign_calls/layers.rs | 3 +- tooling/nargo/src/foreign_calls/mocker.rs | 4 +- tooling/nargo/src/foreign_calls/mod.rs | 20 +- tooling/nargo/src/foreign_calls/print.rs | 83 ++++++- tooling/nargo/src/foreign_calls/rpc.rs | 3 +- tooling/nargo/src/ops/test.rs | 3 +- tooling/noirc_abi/src/lib.rs | 16 +- tooling/noirc_abi/src/printable_type.rs | 78 +++++++ tooling/noirc_artifacts/src/debug_vars.rs | 7 +- 17 files changed, 292 insertions(+), 227 deletions(-) create mode 100644 tooling/noirc_abi/src/printable_type.rs diff --git a/Cargo.lock b/Cargo.lock index cd5b1ea57cd..2d4aa00b864 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2820,6 +2820,7 @@ dependencies = [ "rand", "rayon", "serde", + "serde_json", "thiserror", "tokio", "tracing", @@ -3244,11 +3245,7 @@ name = "noirc_printable_type" version = "1.0.0-beta.1" dependencies = [ "acvm", - "iter-extended", - "jsonrpsee", "serde", - "serde_json", - "thiserror", ] [[package]] diff --git a/compiler/noirc_printable_type/Cargo.toml b/compiler/noirc_printable_type/Cargo.toml index bb965d12c4e..a1eae750b1f 100644 --- a/compiler/noirc_printable_type/Cargo.toml +++ b/compiler/noirc_printable_type/Cargo.toml @@ -13,10 +13,6 @@ workspace = true [dependencies] acvm.workspace = true -iter-extended.workspace = true serde.workspace = true -serde_json.workspace = true -thiserror.workspace = true -jsonrpsee.workspace = true [dev-dependencies] diff --git a/compiler/noirc_printable_type/src/lib.rs b/compiler/noirc_printable_type/src/lib.rs index f85dfcc8e1e..eb74d2470fb 100644 --- a/compiler/noirc_printable_type/src/lib.rs +++ b/compiler/noirc_printable_type/src/lib.rs @@ -1,10 +1,13 @@ +#![forbid(unsafe_code)] +#![warn(unused_crate_dependencies, unused_extern_crates)] +#![warn(unreachable_pub)] +#![warn(clippy::semicolon_if_nothing_returned)] + use std::{collections::BTreeMap, str}; -use acvm::{acir::AcirField, brillig_vm::brillig::ForeignCallParam}; -use iter_extended::vecmap; +use acvm::AcirField; use serde::{Deserialize, Serialize}; -use thiserror::Error; #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[serde(tag = "kind", rename_all = "lowercase")] @@ -66,96 +69,23 @@ pub enum PrintableValueDisplay { Plain(PrintableValue, PrintableType), FmtString(String, Vec<(PrintableValue, PrintableType)>), } - -#[derive(Debug, Error)] -pub enum ForeignCallError { - #[error("No handler could be found for foreign call `{0}`")] - NoHandler(String), - - #[error("Foreign call inputs needed for execution are missing")] - MissingForeignCallInputs, - - #[error("Could not parse PrintableType argument. {0}")] - ParsingError(#[from] serde_json::Error), - - #[error("Failed calling external resolver. {0}")] - ExternalResolverError(#[from] jsonrpsee::core::client::Error), - - #[error("Assert message resolved after an unsatisfied constrain. {0}")] - ResolvedAssertMessage(String), -} - -impl TryFrom<&[ForeignCallParam]> for PrintableValueDisplay { - type Error = ForeignCallError; - - fn try_from(foreign_call_inputs: &[ForeignCallParam]) -> Result { - let (is_fmt_str, foreign_call_inputs) = - foreign_call_inputs.split_last().ok_or(ForeignCallError::MissingForeignCallInputs)?; - - if is_fmt_str.unwrap_field().is_one() { - convert_fmt_string_inputs(foreign_call_inputs) - } else { - convert_string_inputs(foreign_call_inputs) +impl std::fmt::Display for PrintableValueDisplay { + fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::Plain(value, typ) => { + let output_string = to_string(value, typ).ok_or(std::fmt::Error)?; + write!(fmt, "{output_string}") + } + Self::FmtString(template, values) => { + let mut values_iter = values.iter(); + write_template_replacing_interpolations(template, fmt, || { + values_iter.next().and_then(|(value, typ)| to_string(value, typ)) + }) + } } } } -fn convert_string_inputs( - foreign_call_inputs: &[ForeignCallParam], -) -> Result, ForeignCallError> { - // Fetch the PrintableType from the foreign call input - // The remaining input values should hold what is to be printed - let (printable_type_as_values, input_values) = - foreign_call_inputs.split_last().ok_or(ForeignCallError::MissingForeignCallInputs)?; - let printable_type = fetch_printable_type(printable_type_as_values)?; - - // We must use a flat map here as each value in a struct will be in a separate input value - let mut input_values_as_fields = input_values.iter().flat_map(|param| param.fields()); - - let value = decode_value(&mut input_values_as_fields, &printable_type); - - Ok(PrintableValueDisplay::Plain(value, printable_type)) -} - -fn convert_fmt_string_inputs( - foreign_call_inputs: &[ForeignCallParam], -) -> Result, ForeignCallError> { - let (message, input_and_printable_types) = - foreign_call_inputs.split_first().ok_or(ForeignCallError::MissingForeignCallInputs)?; - - let message_as_fields = message.fields(); - let message_as_string = decode_string_value(&message_as_fields); - - let (num_values, input_and_printable_types) = input_and_printable_types - .split_first() - .ok_or(ForeignCallError::MissingForeignCallInputs)?; - - let mut output = Vec::new(); - let num_values = num_values.unwrap_field().to_u128() as usize; - - let types_start_at = input_and_printable_types.len() - num_values; - let mut input_iter = - input_and_printable_types[0..types_start_at].iter().flat_map(|param| param.fields()); - for printable_type in input_and_printable_types.iter().skip(types_start_at) { - let printable_type = fetch_printable_type(printable_type)?; - let value = decode_value(&mut input_iter, &printable_type); - - output.push((value, printable_type)); - } - - Ok(PrintableValueDisplay::FmtString(message_as_string, output)) -} - -fn fetch_printable_type( - printable_type: &ForeignCallParam, -) -> Result { - let printable_type_as_fields = printable_type.fields(); - let printable_type_as_string = decode_string_value(&printable_type_as_fields); - let printable_type: PrintableType = serde_json::from_str(&printable_type_as_string)?; - - Ok(printable_type) -} - fn to_string(value: &PrintableValue, typ: &PrintableType) -> Option { let mut output = String::new(); match (value, typ) { @@ -193,7 +123,7 @@ fn to_string(value: &PrintableValue, typ: &PrintableType) -> Op (PrintableValue::Vec { array_elements, is_slice }, PrintableType::Array { typ, .. }) | (PrintableValue::Vec { array_elements, is_slice }, PrintableType::Slice { typ }) => { if *is_slice { - output.push('&') + output.push('&'); } output.push('['); let mut values = array_elements.iter().peekable(); @@ -253,23 +183,6 @@ fn to_string(value: &PrintableValue, typ: &PrintableType) -> Op Some(output) } -impl std::fmt::Display for PrintableValueDisplay { - fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - Self::Plain(value, typ) => { - let output_string = to_string(value, typ).ok_or(std::fmt::Error)?; - write!(fmt, "{output_string}") - } - Self::FmtString(template, values) => { - let mut values_iter = values.iter(); - write_template_replacing_interpolations(template, fmt, || { - values_iter.next().and_then(|(value, typ)| to_string(value, typ)) - }) - } - } - } -} - fn write_template_replacing_interpolations( template: &str, fmt: &mut std::fmt::Formatter<'_>, @@ -346,94 +259,11 @@ fn format_field_string(field: F) -> String { "0x".to_owned() + &trimmed_field } -/// Assumes that `field_iterator` contains enough field elements in order to decode the [PrintableType] -pub fn decode_value( - field_iterator: &mut impl Iterator, - typ: &PrintableType, -) -> PrintableValue { - match typ { - PrintableType::Field - | PrintableType::SignedInteger { .. } - | PrintableType::UnsignedInteger { .. } - | PrintableType::Boolean => { - let field_element = field_iterator.next().unwrap(); - - PrintableValue::Field(field_element) - } - PrintableType::Array { length, typ } => { - let length = *length as usize; - let mut array_elements = Vec::with_capacity(length); - for _ in 0..length { - array_elements.push(decode_value(field_iterator, typ)); - } - - PrintableValue::Vec { array_elements, is_slice: false } - } - PrintableType::Slice { typ } => { - let length = field_iterator - .next() - .expect("not enough data to decode variable array length") - .to_u128() as usize; - let mut array_elements = Vec::with_capacity(length); - for _ in 0..length { - array_elements.push(decode_value(field_iterator, typ)); - } - - PrintableValue::Vec { array_elements, is_slice: true } - } - PrintableType::Tuple { types } => PrintableValue::Vec { - array_elements: vecmap(types, |typ| decode_value(field_iterator, typ)), - is_slice: false, - }, - PrintableType::String { length } => { - let field_elements: Vec = field_iterator.take(*length as usize).collect(); - - PrintableValue::String(decode_string_value(&field_elements)) - } - PrintableType::Struct { fields, .. } => { - let mut struct_map = BTreeMap::new(); - - for (field_key, param_type) in fields { - let field_value = decode_value(field_iterator, param_type); - - struct_map.insert(field_key.to_owned(), field_value); - } - - PrintableValue::Struct(struct_map) - } - PrintableType::Function { env, .. } => { - let field_element = field_iterator.next().unwrap(); - let func_ref = PrintableValue::Field(field_element); - // we want to consume the fields from the environment, but for now they are not actually printed - decode_value(field_iterator, env); - func_ref - } - PrintableType::MutableReference { typ } => { - // we decode the reference, but it's not really used for printing - decode_value(field_iterator, typ) - } - PrintableType::Unit => PrintableValue::Field(F::zero()), - } -} - -pub fn decode_string_value(field_elements: &[F]) -> String { - // TODO: Replace with `into` when Char is supported - let string_as_slice = vecmap(field_elements, |e| { - let mut field_as_bytes = e.to_be_bytes(); - let char_byte = field_as_bytes.pop().unwrap(); // A character in a string is represented by a u8, thus we just want the last byte of the element - assert!(field_as_bytes.into_iter().all(|b| b == 0)); // Assert that the rest of the field element's bytes are empty - char_byte - }); - - let final_string = str::from_utf8(&string_as_slice).unwrap(); - final_string.to_owned() -} - #[cfg(test)] mod tests { use acvm::FieldElement; - use crate::{PrintableType, PrintableValue, PrintableValueDisplay}; + use super::{PrintableType, PrintableValue, PrintableValueDisplay}; #[test] fn printable_value_display_to_string_without_interpolations() { diff --git a/docs/docs/noir/concepts/data_types/strings.md b/docs/docs/noir/concepts/data_types/strings.md index 1fdee42425e..b2257e8bdbb 100644 --- a/docs/docs/noir/concepts/data_types/strings.md +++ b/docs/docs/noir/concepts/data_types/strings.md @@ -77,3 +77,38 @@ let s = r#"Simon says "hello world""#; // Any number of hashes may be used (>= 1) as long as the string also terminates with the same number of hashes let s = r#####"One "#, Two "##, Three "###, Four "####, Five will end the string."#####; ``` + +## Format strings + +A format string begins with the letter `f` and allows inserting the value of local and global variables in it. + +Example: + +```rust +let four = 2 + 2; +let s = f"Two plus two is: {four}"; +println(s); +``` + +The output of the above program is: + +```text +Two plus two is: 4 +``` + +To insert the value of a local or global variable, put it inside `{...}` in the string. + +If you need to write the `{` or `}` characters, use `{{` and `}}` respectively: + +```rust +let four = 2 + 2; + +// Prints "This is not expanded: {four}" +println(f"This is not expanded: {{four}}"); +``` + +More complex expressions are not allowed inside `{...}`: + +```rust +let s = f"Two plus two is: {2 + 2}" // Error: invalid format string +``` \ No newline at end of file diff --git a/docs/versioned_docs/version-v1.0.0-beta.1/noir/concepts/data_types/strings.md b/docs/versioned_docs/version-v1.0.0-beta.1/noir/concepts/data_types/strings.md index 1fdee42425e..b2257e8bdbb 100644 --- a/docs/versioned_docs/version-v1.0.0-beta.1/noir/concepts/data_types/strings.md +++ b/docs/versioned_docs/version-v1.0.0-beta.1/noir/concepts/data_types/strings.md @@ -77,3 +77,38 @@ let s = r#"Simon says "hello world""#; // Any number of hashes may be used (>= 1) as long as the string also terminates with the same number of hashes let s = r#####"One "#, Two "##, Three "###, Four "####, Five will end the string."#####; ``` + +## Format strings + +A format string begins with the letter `f` and allows inserting the value of local and global variables in it. + +Example: + +```rust +let four = 2 + 2; +let s = f"Two plus two is: {four}"; +println(s); +``` + +The output of the above program is: + +```text +Two plus two is: 4 +``` + +To insert the value of a local or global variable, put it inside `{...}` in the string. + +If you need to write the `{` or `}` characters, use `{{` and `}}` respectively: + +```rust +let four = 2 + 2; + +// Prints "This is not expanded: {four}" +println(f"This is not expanded: {{four}}"); +``` + +More complex expressions are not allowed inside `{...}`: + +```rust +let s = f"Two plus two is: {2 + 2}" // Error: invalid format string +``` \ No newline at end of file diff --git a/tooling/debugger/src/foreign_calls.rs b/tooling/debugger/src/foreign_calls.rs index 352fc468491..b92e22844ea 100644 --- a/tooling/debugger/src/foreign_calls.rs +++ b/tooling/debugger/src/foreign_calls.rs @@ -4,12 +4,13 @@ use acvm::{ AcirField, FieldElement, }; use nargo::{ - foreign_calls::{layers::Layer, DefaultForeignCallBuilder, ForeignCallExecutor}, + foreign_calls::{ + layers::Layer, DefaultForeignCallBuilder, ForeignCallError, ForeignCallExecutor, + }, PrintOutput, }; use noirc_artifacts::debug::{DebugArtifact, DebugVars, StackFrame}; use noirc_errors::debug_info::{DebugFnId, DebugVarId}; -use noirc_printable_type::ForeignCallError; pub(crate) enum DebugForeignCall { VarAssign, diff --git a/tooling/nargo/Cargo.toml b/tooling/nargo/Cargo.toml index ef5500131f3..4af20359739 100644 --- a/tooling/nargo/Cargo.toml +++ b/tooling/nargo/Cargo.toml @@ -22,9 +22,10 @@ noirc_frontend.workspace = true noirc_printable_type.workspace = true iter-extended.workspace = true rayon.workspace = true -serde = { workspace = true } thiserror.workspace = true tracing.workspace = true +serde.workspace = true +serde_json.workspace = true walkdir = "2.5.0" # Some dependencies are optional so we can compile to Wasm. diff --git a/tooling/nargo/src/errors.rs b/tooling/nargo/src/errors.rs index 5256f28e36c..00c411bf7e4 100644 --- a/tooling/nargo/src/errors.rs +++ b/tooling/nargo/src/errors.rs @@ -16,9 +16,10 @@ use noirc_errors::{ pub use noirc_errors::Location; use noirc_driver::CrateName; -use noirc_printable_type::ForeignCallError; use thiserror::Error; +use crate::foreign_calls::ForeignCallError; + /// Errors covering situations where a package cannot be compiled. #[derive(Debug, Error)] pub enum CompileError { diff --git a/tooling/nargo/src/foreign_calls/layers.rs b/tooling/nargo/src/foreign_calls/layers.rs index 25df4e904aa..19f14c6f4a8 100644 --- a/tooling/nargo/src/foreign_calls/layers.rs +++ b/tooling/nargo/src/foreign_calls/layers.rs @@ -1,7 +1,6 @@ use acvm::{acir::brillig::ForeignCallResult, pwg::ForeignCallWaitInfo, AcirField}; -use noirc_printable_type::ForeignCallError; -use super::ForeignCallExecutor; +use super::{ForeignCallError, ForeignCallExecutor}; /// Returns an empty result when called. /// diff --git a/tooling/nargo/src/foreign_calls/mocker.rs b/tooling/nargo/src/foreign_calls/mocker.rs index 42d788fcfc6..b97d5749307 100644 --- a/tooling/nargo/src/foreign_calls/mocker.rs +++ b/tooling/nargo/src/foreign_calls/mocker.rs @@ -5,9 +5,9 @@ use acvm::{ pwg::ForeignCallWaitInfo, AcirField, }; -use noirc_printable_type::{decode_string_value, ForeignCallError}; +use noirc_abi::decode_string_value; -use super::{ForeignCall, ForeignCallExecutor}; +use super::{ForeignCall, ForeignCallError, ForeignCallExecutor}; /// This struct represents an oracle mock. It can be used for testing programs that use oracles. #[derive(Debug, PartialEq, Eq, Clone)] diff --git a/tooling/nargo/src/foreign_calls/mod.rs b/tooling/nargo/src/foreign_calls/mod.rs index 4a5e840fa83..06fe42bfec9 100644 --- a/tooling/nargo/src/foreign_calls/mod.rs +++ b/tooling/nargo/src/foreign_calls/mod.rs @@ -1,5 +1,5 @@ use acvm::{acir::brillig::ForeignCallResult, pwg::ForeignCallWaitInfo}; -use noirc_printable_type::ForeignCallError; +use thiserror::Error; pub mod layers; pub mod mocker; @@ -63,3 +63,21 @@ impl ForeignCall { } } } + +#[derive(Debug, Error)] +pub enum ForeignCallError { + #[error("No handler could be found for foreign call `{0}`")] + NoHandler(String), + + #[error("Foreign call inputs needed for execution are missing")] + MissingForeignCallInputs, + + #[error("Could not parse PrintableType argument. {0}")] + ParsingError(#[from] serde_json::Error), + + #[error("Failed calling external resolver. {0}")] + ExternalResolverError(#[from] jsonrpsee::core::client::Error), + + #[error("Assert message resolved after an unsatisfied constrain. {0}")] + ResolvedAssertMessage(String), +} diff --git a/tooling/nargo/src/foreign_calls/print.rs b/tooling/nargo/src/foreign_calls/print.rs index 5dc006ca775..fb5621da942 100644 --- a/tooling/nargo/src/foreign_calls/print.rs +++ b/tooling/nargo/src/foreign_calls/print.rs @@ -1,7 +1,12 @@ -use acvm::{acir::brillig::ForeignCallResult, pwg::ForeignCallWaitInfo, AcirField}; -use noirc_printable_type::{ForeignCallError, PrintableValueDisplay}; +use acvm::{ + acir::brillig::{ForeignCallParam, ForeignCallResult}, + pwg::ForeignCallWaitInfo, + AcirField, +}; +use noirc_abi::{decode_printable_value, decode_string_value}; +use noirc_printable_type::{PrintableType, PrintableValueDisplay}; -use super::{ForeignCall, ForeignCallExecutor}; +use super::{ForeignCall, ForeignCallError, ForeignCallExecutor}; #[derive(Debug, Default)] pub enum PrintOutput<'a> { @@ -38,7 +43,8 @@ impl ForeignCallExecutor for PrintForeignCallExecutor<'_> { .ok_or(ForeignCallError::MissingForeignCallInputs)? .1; - let display_values: PrintableValueDisplay = foreign_call_inputs.try_into()?; + let display_values: PrintableValueDisplay = + try_from_params(foreign_call_inputs)?; let display_string = format!("{display_values}{}", if skip_newline { "" } else { "\n" }); @@ -56,3 +62,72 @@ impl ForeignCallExecutor for PrintForeignCallExecutor<'_> { } } } + +fn try_from_params( + foreign_call_inputs: &[ForeignCallParam], +) -> Result, ForeignCallError> { + let (is_fmt_str, foreign_call_inputs) = + foreign_call_inputs.split_last().ok_or(ForeignCallError::MissingForeignCallInputs)?; + + if is_fmt_str.unwrap_field().is_one() { + convert_fmt_string_inputs(foreign_call_inputs) + } else { + convert_string_inputs(foreign_call_inputs) + } +} + +fn convert_string_inputs( + foreign_call_inputs: &[ForeignCallParam], +) -> Result, ForeignCallError> { + // Fetch the PrintableType from the foreign call input + // The remaining input values should hold what is to be printed + let (printable_type_as_values, input_values) = + foreign_call_inputs.split_last().ok_or(ForeignCallError::MissingForeignCallInputs)?; + let printable_type = fetch_printable_type(printable_type_as_values)?; + + // We must use a flat map here as each value in a struct will be in a separate input value + let mut input_values_as_fields = input_values.iter().flat_map(|param| param.fields()); + + let value = decode_printable_value(&mut input_values_as_fields, &printable_type); + + Ok(PrintableValueDisplay::Plain(value, printable_type)) +} + +fn convert_fmt_string_inputs( + foreign_call_inputs: &[ForeignCallParam], +) -> Result, ForeignCallError> { + let (message, input_and_printable_types) = + foreign_call_inputs.split_first().ok_or(ForeignCallError::MissingForeignCallInputs)?; + + let message_as_fields = message.fields(); + let message_as_string = decode_string_value(&message_as_fields); + + let (num_values, input_and_printable_types) = input_and_printable_types + .split_first() + .ok_or(ForeignCallError::MissingForeignCallInputs)?; + + let mut output = Vec::new(); + let num_values = num_values.unwrap_field().to_u128() as usize; + + let types_start_at = input_and_printable_types.len() - num_values; + let mut input_iter = + input_and_printable_types[0..types_start_at].iter().flat_map(|param| param.fields()); + for printable_type in input_and_printable_types.iter().skip(types_start_at) { + let printable_type = fetch_printable_type(printable_type)?; + let value = decode_printable_value(&mut input_iter, &printable_type); + + output.push((value, printable_type)); + } + + Ok(PrintableValueDisplay::FmtString(message_as_string, output)) +} + +fn fetch_printable_type( + printable_type: &ForeignCallParam, +) -> Result { + let printable_type_as_fields = printable_type.fields(); + let printable_type_as_string = decode_string_value(&printable_type_as_fields); + let printable_type: PrintableType = serde_json::from_str(&printable_type_as_string)?; + + Ok(printable_type) +} diff --git a/tooling/nargo/src/foreign_calls/rpc.rs b/tooling/nargo/src/foreign_calls/rpc.rs index aa11c24bc9f..89a748b6c45 100644 --- a/tooling/nargo/src/foreign_calls/rpc.rs +++ b/tooling/nargo/src/foreign_calls/rpc.rs @@ -6,10 +6,9 @@ use jsonrpsee::{ http_client::{HttpClient, HttpClientBuilder}, rpc_params, }; -use noirc_printable_type::ForeignCallError; use serde::{Deserialize, Serialize}; -use super::ForeignCallExecutor; +use super::{ForeignCallError, ForeignCallExecutor}; #[derive(Debug)] pub struct RPCForeignCallExecutor { diff --git a/tooling/nargo/src/ops/test.rs b/tooling/nargo/src/ops/test.rs index 660770e6ae1..366e899ff9e 100644 --- a/tooling/nargo/src/ops/test.rs +++ b/tooling/nargo/src/ops/test.rs @@ -10,11 +10,10 @@ use noirc_abi::Abi; use noirc_driver::{compile_no_check, CompileError, CompileOptions, DEFAULT_EXPRESSION_WIDTH}; use noirc_errors::{debug_info::DebugInfo, FileDiagnostic}; use noirc_frontend::hir::{def_map::TestFunction, Context}; -use noirc_printable_type::ForeignCallError; use crate::{ errors::try_to_diagnose_runtime_error, - foreign_calls::{layers, print::PrintOutput, ForeignCallExecutor}, + foreign_calls::{layers, print::PrintOutput, ForeignCallError, ForeignCallExecutor}, NargoError, }; diff --git a/tooling/noirc_abi/src/lib.rs b/tooling/noirc_abi/src/lib.rs index bd5674d64f1..5f5f3748bc4 100644 --- a/tooling/noirc_abi/src/lib.rs +++ b/tooling/noirc_abi/src/lib.rs @@ -13,10 +13,7 @@ use acvm::{ use errors::AbiError; use input_parser::InputValue; use iter_extended::{try_btree_map, try_vecmap, vecmap}; -use noirc_printable_type::{ - decode_value as printable_type_decode_value, PrintableType, PrintableValue, - PrintableValueDisplay, -}; +use noirc_printable_type::{PrintableType, PrintableValue, PrintableValueDisplay}; use serde::{Deserialize, Serialize}; use std::borrow::Borrow; use std::{collections::BTreeMap, str}; @@ -30,8 +27,11 @@ mod arbitrary; pub mod errors; pub mod input_parser; +mod printable_type; mod serialization; +pub use printable_type::decode_value as decode_printable_value; + /// A map from the fields in an TOML/JSON file which correspond to some ABI to their values pub type InputMap = BTreeMap; @@ -417,7 +417,7 @@ pub fn decode_value( Ok(value) } -fn decode_string_value(field_elements: &[FieldElement]) -> String { +pub fn decode_string_value(field_elements: &[F]) -> String { let string_as_slice = vecmap(field_elements, |e| { let mut field_as_bytes = e.to_be_bytes(); let char_byte = field_as_bytes.pop().unwrap(); // A character in a string is represented by a u8, thus we just want the last byte of the element @@ -476,21 +476,21 @@ pub fn display_abi_error( AbiErrorType::FmtString { length, item_types } => { let mut fields_iter = fields.iter().copied(); let PrintableValue::String(string) = - printable_type_decode_value(&mut fields_iter, &PrintableType::String { length }) + decode_printable_value(&mut fields_iter, &PrintableType::String { length }) else { unreachable!("Got non-string from string decoding"); }; let _length_of_items = fields_iter.next(); let items = item_types.into_iter().map(|abi_type| { let printable_typ = (&abi_type).into(); - let decoded = printable_type_decode_value(&mut fields_iter, &printable_typ); + let decoded = decode_printable_value(&mut fields_iter, &printable_typ); (decoded, printable_typ) }); PrintableValueDisplay::FmtString(string, items.collect()) } AbiErrorType::Custom(abi_typ) => { let printable_type = (&abi_typ).into(); - let decoded = printable_type_decode_value(&mut fields.iter().copied(), &printable_type); + let decoded = decode_printable_value(&mut fields.iter().copied(), &printable_type); PrintableValueDisplay::Plain(decoded, printable_type) } AbiErrorType::String { string } => { diff --git a/tooling/noirc_abi/src/printable_type.rs b/tooling/noirc_abi/src/printable_type.rs new file mode 100644 index 00000000000..a81eb0ce8f6 --- /dev/null +++ b/tooling/noirc_abi/src/printable_type.rs @@ -0,0 +1,78 @@ +use std::collections::BTreeMap; + +use acvm::acir::AcirField; +use iter_extended::vecmap; + +use noirc_printable_type::{PrintableType, PrintableValue}; + +use crate::decode_string_value; + +/// Assumes that `field_iterator` contains enough field elements in order to decode the [PrintableType] +pub fn decode_value( + field_iterator: &mut impl Iterator, + typ: &PrintableType, +) -> PrintableValue { + match typ { + PrintableType::Field + | PrintableType::SignedInteger { .. } + | PrintableType::UnsignedInteger { .. } + | PrintableType::Boolean => { + let field_element = field_iterator.next().unwrap(); + + PrintableValue::Field(field_element) + } + PrintableType::Array { length, typ } => { + let length = *length as usize; + let mut array_elements = Vec::with_capacity(length); + for _ in 0..length { + array_elements.push(decode_value(field_iterator, typ)); + } + + PrintableValue::Vec { array_elements, is_slice: false } + } + PrintableType::Slice { typ } => { + let length = field_iterator + .next() + .expect("not enough data to decode variable array length") + .to_u128() as usize; + let mut array_elements = Vec::with_capacity(length); + for _ in 0..length { + array_elements.push(decode_value(field_iterator, typ)); + } + + PrintableValue::Vec { array_elements, is_slice: true } + } + PrintableType::Tuple { types } => PrintableValue::Vec { + array_elements: vecmap(types, |typ| decode_value(field_iterator, typ)), + is_slice: false, + }, + PrintableType::String { length } => { + let field_elements: Vec = field_iterator.take(*length as usize).collect(); + + PrintableValue::String(decode_string_value(&field_elements)) + } + PrintableType::Struct { fields, .. } => { + let mut struct_map = BTreeMap::new(); + + for (field_key, param_type) in fields { + let field_value = decode_value(field_iterator, param_type); + + struct_map.insert(field_key.to_owned(), field_value); + } + + PrintableValue::Struct(struct_map) + } + PrintableType::Function { env, .. } => { + let field_element = field_iterator.next().unwrap(); + let func_ref = PrintableValue::Field(field_element); + // we want to consume the fields from the environment, but for now they are not actually printed + decode_value(field_iterator, env); + func_ref + } + PrintableType::MutableReference { typ } => { + // we decode the reference, but it's not really used for printing + decode_value(field_iterator, typ) + } + PrintableType::Unit => PrintableValue::Field(F::zero()), + } +} diff --git a/tooling/noirc_artifacts/src/debug_vars.rs b/tooling/noirc_artifacts/src/debug_vars.rs index aa9328432b8..1e144e3ecc5 100644 --- a/tooling/noirc_artifacts/src/debug_vars.rs +++ b/tooling/noirc_artifacts/src/debug_vars.rs @@ -1,8 +1,9 @@ use acvm::AcirField; +use noirc_abi::decode_printable_value; use noirc_errors::debug_info::{ DebugFnId, DebugFunction, DebugInfo, DebugTypeId, DebugVarId, DebugVariable, }; -use noirc_printable_type::{decode_value, PrintableType, PrintableValue}; +use noirc_printable_type::{PrintableType, PrintableValue}; use std::collections::HashMap; #[derive(Debug, Default, Clone)] @@ -72,7 +73,7 @@ impl DebugVars { .last_mut() .expect("unexpected empty stack frames") .1 - .insert(var_id, decode_value(&mut values.iter().copied(), ptype)); + .insert(var_id, decode_printable_value(&mut values.iter().copied(), ptype)); } pub fn assign_field(&mut self, var_id: DebugVarId, indexes: Vec, values: &[F]) { @@ -143,7 +144,7 @@ impl DebugVars { } }; } - *cursor = decode_value(&mut values.iter().copied(), cursor_type); + *cursor = decode_printable_value(&mut values.iter().copied(), cursor_type); } pub fn assign_deref(&mut self, _var_id: DebugVarId, _values: &[F]) { From e5185b4642a76066340e23001ec3769db700293e Mon Sep 17 00:00:00 2001 From: Tom French Date: Thu, 2 Jan 2025 14:27:07 +0000 Subject: [PATCH 18/21] . --- tooling/nargo/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tooling/nargo/Cargo.toml b/tooling/nargo/Cargo.toml index 4af20359739..9fb46b78bc9 100644 --- a/tooling/nargo/Cargo.toml +++ b/tooling/nargo/Cargo.toml @@ -21,6 +21,7 @@ noirc_errors.workspace = true noirc_frontend.workspace = true noirc_printable_type.workspace = true iter-extended.workspace = true +jsonrpsee.workspace = true rayon.workspace = true thiserror.workspace = true tracing.workspace = true @@ -29,7 +30,6 @@ serde_json.workspace = true walkdir = "2.5.0" # Some dependencies are optional so we can compile to Wasm. -jsonrpsee = { workspace = true, optional = true } tokio = { workspace = true, optional = true } rand = { workspace = true, optional = true } From 9ab1f0b54ad92a64bc70668a25ffd41fe5bef9f0 Mon Sep 17 00:00:00 2001 From: Tom French <15848336+TomAFrench@users.noreply.github.com> Date: Thu, 2 Jan 2025 15:32:19 +0000 Subject: [PATCH 19/21] Update tooling/nargo/src/foreign_calls/mocker.rs --- tooling/nargo/src/foreign_calls/mocker.rs | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/tooling/nargo/src/foreign_calls/mocker.rs b/tooling/nargo/src/foreign_calls/mocker.rs index b97d5749307..b289e907cd7 100644 --- a/tooling/nargo/src/foreign_calls/mocker.rs +++ b/tooling/nargo/src/foreign_calls/mocker.rs @@ -189,18 +189,16 @@ impl ForeignCallExecutor for DisabledMockForeignCallExecutor { foreign_call: &ForeignCallWaitInfo, ) -> Result, ForeignCallError> { let foreign_call_name = foreign_call.function.as_str(); - if let Some(call) = ForeignCall::lookup(foreign_call_name) { - match call { - ForeignCall::CreateMock - | ForeignCall::SetMockParams - | ForeignCall::GetMockLastParams - | ForeignCall::SetMockReturns - | ForeignCall::SetMockTimes - | ForeignCall::ClearMock => { - panic!("unexpected mock call: {}", foreign_call.function) - } - _ => {} - } + if let Some( + ForeignCall::CreateMock + | ForeignCall::SetMockParams + | ForeignCall::GetMockLastParams + | ForeignCall::SetMockReturns + | ForeignCall::SetMockTimes + | ForeignCall::ClearMock, + ) = ForeignCall::lookup(foreign_call_name) + { + panic!("unexpected mock call: {}", foreign_call.function) } Err(ForeignCallError::NoHandler(foreign_call.function.clone())) } From 06a667686cd3723d8ad68e79e0229d16b79a9509 Mon Sep 17 00:00:00 2001 From: Tom French Date: Thu, 2 Jan 2025 15:38:18 +0000 Subject: [PATCH 20/21] chore: review changes --- tooling/nargo/src/ops/test.rs | 28 ++++++++++++---------------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/tooling/nargo/src/ops/test.rs b/tooling/nargo/src/ops/test.rs index 366e899ff9e..420a7c87704 100644 --- a/tooling/nargo/src/ops/test.rs +++ b/tooling/nargo/src/ops/test.rs @@ -33,14 +33,13 @@ impl TestStatus { } } -#[allow(clippy::too_many_arguments)] pub fn run_test<'a, B, F, E>( blackbox_solver: &B, context: &mut Context, test_function: &TestFunction, output: PrintOutput<'a>, config: &CompileOptions, - foreign_call_executor: F, + build_foreign_call_executor: F, ) -> TestStatus where B: BlackBoxFunctionSolver, @@ -63,8 +62,9 @@ where if test_function_has_no_arguments { // Run the backend to ensure the PWG evaluates functions like std::hash::pedersen, // otherwise constraints involving these expressions will not error. - let mut foreign_call_executor = - TestForeignCallExecutor::new(output, &foreign_call_executor); + // Use a base layer that doesn't handle anything, which we handle in the `execute` below. + let inner_executor = build_foreign_call_executor(output, layers::Unhandled); + let mut foreign_call_executor = TestForeignCallExecutor::new(inner_executor); let circuit_execution = execute_program( &compiled_program.program, @@ -122,14 +122,17 @@ where |program: &Program, initial_witness: WitnessMap| -> Result, String> { + // Use a base layer that doesn't handle anything, which we handle in the `execute` below. + let inner_executor = + build_foreign_call_executor(PrintOutput::None, layers::Unhandled); + let mut foreign_call_executor = + TestForeignCallExecutor::new(inner_executor); + let circuit_execution = execute_program( program, initial_witness, blackbox_solver, - &mut TestForeignCallExecutor::new( - PrintOutput::None, - &foreign_call_executor, - ), + &mut foreign_call_executor, ); let status = test_status_program_compile_pass( @@ -271,14 +274,7 @@ struct TestForeignCallExecutor { } impl TestForeignCallExecutor { - #[allow(clippy::new_ret_no_self)] - fn new<'a, F>(output: PrintOutput<'a>, foreign_call_executor: &F) -> Self - where - F: Fn(PrintOutput<'a>, layers::Unhandled) -> E + 'a, - { - // Use a base layer that doesn't handle anything, which we handle in the `execute` below. - let executor = foreign_call_executor(output, layers::Unhandled); - + fn new(executor: E) -> Self { Self { executor, encountered_unknown_foreign_call: false } } } From 65d3614974e907f43bb6b9b9ec8f311a5956fcfe Mon Sep 17 00:00:00 2001 From: Tom French Date: Thu, 2 Jan 2025 15:45:04 +0000 Subject: [PATCH 21/21] . --- tooling/nargo/src/ops/test.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tooling/nargo/src/ops/test.rs b/tooling/nargo/src/ops/test.rs index 420a7c87704..bfd5cd3713f 100644 --- a/tooling/nargo/src/ops/test.rs +++ b/tooling/nargo/src/ops/test.rs @@ -293,6 +293,8 @@ where match self.executor.execute(foreign_call) { Err(ForeignCallError::NoHandler(_)) => { self.encountered_unknown_foreign_call = true; + // If the inner executor cannot handle this foreign call, then it's very likely that this is a custom + // foreign call. We then return an empty response in case the foreign call doesn't need return values. layers::Empty.execute(foreign_call) } other => other,