Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat!: Switch to using jsonrpsee for foreign calls; refactor run_test; foreign call layering #6849

Merged
merged 30 commits into from
Jan 2, 2025
Merged
Show file tree
Hide file tree
Changes from 20 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
3b5f7e0
Use jsonrpsee on the client side
aakoshh Dec 17, 2024
159bcbc
Rewrite the test to use jsonrpsee
aakoshh Dec 17, 2024
118e1e3
Remove jsonrpc from deny
aakoshh Dec 17, 2024
8b742ff
Fix clippy
aakoshh Dec 17, 2024
84dba55
Add clarification for the 'ring' license
aakoshh Dec 17, 2024
5232698
Added feature flags to nargo to be able to disable execution for Wasm
aakoshh Dec 18, 2024
fff53f8
Just use unwrap in tests
aakoshh Dec 18, 2024
9b113a7
Merge remote-tracking branch 'origin/master' into 6742-jsonrpsee
aakoshh Dec 18, 2024
e2549df
Update tooling/nargo/Cargo.toml
aakoshh Dec 18, 2024
8280761
Merge branch 'master' into 6742-jsonrpsee
aakoshh Dec 19, 2024
6ce3263
feat!: Composable foreign call handlers (#6857)
aakoshh Dec 19, 2024
54fc751
feat!: `nargo::ops::test::run_test` generic in `ForeignCallExecutor` …
aakoshh Dec 19, 2024
ee79016
Layer doesn't need F
aakoshh Dec 19, 2024
d0d5c1a
Use add_layer in debug
aakoshh Dec 19, 2024
2516d16
Update compiler/wasm/Cargo.toml
TomAFrench Dec 19, 2024
1d9bfdd
Make the rpc feature opt-in
aakoshh Dec 19, 2024
20fa935
Merge branch '6742-jsonrpsee' of github.com:noir-lang/noir into 6742-…
aakoshh Dec 19, 2024
74ef178
Merge branch 'master' into 6742-jsonrpsee
aakoshh Dec 19, 2024
c8e31c7
Use the DefaultForeignCallBuilder where its mostly None we're passing
aakoshh Dec 19, 2024
005b30f
Merge branch '6742-jsonrpsee' of github.com:noir-lang/noir into 6742-…
aakoshh Dec 19, 2024
b97e5ac
Update compiler/wasm/Cargo.toml
aakoshh Dec 19, 2024
12c0d8f
Merge branch 'master' into 6742-jsonrpsee
aakoshh Dec 20, 2024
ee41126
Merge branch 'master' into 6742-jsonrpsee
TomAFrench Dec 23, 2024
63b48b2
Merge branch 'master' into 6742-jsonrpsee
TomAFrench Jan 2, 2025
fa863be
Merge branch 'master' into 6742-jsonrpsee
TomAFrench Jan 2, 2025
9bc1aab
Merge branch 'master' into 6742-jsonrpsee
TomAFrench Jan 2, 2025
e5185b4
.
TomAFrench Jan 2, 2025
9ab1f0b
Update tooling/nargo/src/foreign_calls/mocker.rs
TomAFrench Jan 2, 2025
06a6676
chore: review changes
TomAFrench Jan 2, 2025
65d3614
.
TomAFrench Jan 2, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
992 changes: 543 additions & 449 deletions Cargo.lock

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +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 = ["client-core"] }
flate2 = "1.0.24"
color-eyre = "0.6.2"
rand = "0.8.5"
Expand All @@ -159,7 +159,7 @@ sha2 = { version = "0.10.6", features = ["compress"] }
sha3 = "0.10.6"
strum = "0.24"
strum_macros = "0.24"

tokio = "1.42"
im = { version = "15.1", features = ["serde"] }
tracing = "0.1.40"
tracing-web = "0.1.3"
Expand Down
2 changes: 1 addition & 1 deletion compiler/noirc_printable_type/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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]
4 changes: 2 additions & 2 deletions compiler/noirc_printable_type/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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),
}

Expand Down
7 changes: 6 additions & 1 deletion compiler/wasm/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -33,6 +33,11 @@ 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.
nargo.workspace = true
aakoshh marked this conversation as resolved.
Show resolved Hide resolved

# This is an unused dependency, we are adding it
# so that we can enable the js feature in getrandom.
getrandom = { workspace = true, features = ["js"] }
Expand Down
2 changes: 2 additions & 0 deletions cspell.json
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@
"jmpifs",
"jmps",
"jsdoc",
"jsonrpsee",
"Jubjub",
"keccak",
"keccakf",
Expand Down Expand Up @@ -166,6 +167,7 @@
"nomicfoundation",
"noncanonical",
"nouner",
"oneshot",
"overflowing",
"pedersen",
"peekable",
Expand Down
7 changes: 6 additions & 1 deletion deny.toml
Original file line number Diff line number Diff line change
Expand Up @@ -66,14 +66,19 @@ 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" },
{ 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
Expand Down
5 changes: 3 additions & 2 deletions tooling/acvm_cli/src/cli/execute_cmd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};

Expand Down Expand Up @@ -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)
}
52 changes: 37 additions & 15 deletions tooling/debugger/src/foreign_calls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use acvm::{
AcirField, FieldElement,
};
use nargo::{
foreign_calls::{DefaultForeignCallExecutor, ForeignCallExecutor},
foreign_calls::{layers::Layer, DefaultForeignCallBuilder, ForeignCallExecutor},
PrintOutput,
};
use noirc_artifacts::debug::{DebugArtifact, DebugVars, StackFrame};
Expand Down Expand Up @@ -44,23 +44,31 @@ pub trait DebugForeignCallExecutor: ForeignCallExecutor<FieldElement> {
fn current_stack_frame(&self) -> Option<StackFrame<FieldElement>>;
}

pub struct DefaultDebugForeignCallExecutor<'a> {
executor: DefaultForeignCallExecutor<'a, FieldElement>,
#[derive(Default)]
pub struct DefaultDebugForeignCallExecutor {
pub debug_vars: DebugVars<FieldElement>,
}

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 {
fn make(
output: PrintOutput<'_>,
ex: DefaultDebugForeignCallExecutor,
) -> impl DebugForeignCallExecutor + '_ {
DefaultForeignCallBuilder::default().with_output(output).build().add_layer(ex)
}

#[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) {
Expand All @@ -73,7 +81,7 @@ impl<'a> DefaultDebugForeignCallExecutor<'a> {
}
}

impl DebugForeignCallExecutor for DefaultDebugForeignCallExecutor<'_> {
impl DebugForeignCallExecutor for DefaultDebugForeignCallExecutor {
fn get_variables(&self) -> Vec<StackFrame<FieldElement>> {
self.debug_vars.get_variables()
}
Expand All @@ -91,7 +99,7 @@ fn debug_fn_id(value: &FieldElement) -> DebugFnId {
DebugFnId(value.to_u128() as u32)
}

impl ForeignCallExecutor<FieldElement> for DefaultDebugForeignCallExecutor<'_> {
impl ForeignCallExecutor<FieldElement> for DefaultDebugForeignCallExecutor {
fn execute(
&mut self,
foreign_call: &ForeignCallWaitInfo<FieldElement>,
Expand Down Expand Up @@ -166,7 +174,21 @@ impl ForeignCallExecutor<FieldElement> 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<H, I> DebugForeignCallExecutor for Layer<H, I>
where
H: DebugForeignCallExecutor,
I: ForeignCallExecutor<FieldElement>,
{
fn get_variables(&self) -> Vec<StackFrame<FieldElement>> {
self.handler().get_variables()
}

fn current_stack_frame(&self) -> Option<StackFrame<FieldElement>> {
self.handler().current_stack_frame()
}
}
13 changes: 10 additions & 3 deletions tooling/lsp/src/requests/test_run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::DefaultForeignCallBuilder,
ops::{run_test, TestStatus},
PrintOutput,
};
Expand Down Expand Up @@ -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| {
DefaultForeignCallBuilder {
output,
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 {
TestStatus::Pass => NargoTestRunResult {
Expand Down
26 changes: 16 additions & 10 deletions tooling/nargo/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,20 +21,26 @@ noirc_errors.workspace = true
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
rayon.workspace = true
jsonrpc.workspace = true
rand.workspace = true
serde.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 }

[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
noir_fuzzer.workspace = true
proptest.workspace = true
noir_fuzzer = { workspace = true }
proptest = { workspace = true }

[dev-dependencies]
jsonrpc-http-server = "18.0"
jsonrpc-core-client = "18.0"
jsonrpc-derive = "18.0"
jsonrpc-core = "18.0"
jsonrpsee = { workspace = true, features = ["server"] }

[features]
default = []

# Execution currently uses HTTP based Oracle resolvers; does not compile to Wasm.
rpc = ["jsonrpsee/http-client", "jsonrpsee/macros", "tokio/rt", "rand"]
115 changes: 115 additions & 0 deletions tooling/nargo/src/foreign_calls/default.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
use acvm::AcirField;
use serde::{Deserialize, Serialize};

use crate::PrintOutput;

use super::{
layers::{self, Layer, Layering},
mocker::MockForeignCallExecutor,
print::PrintForeignCallExecutor,
ForeignCallExecutor,
};

#[cfg(feature = "rpc")]
use super::rpc::RPCForeignCallExecutor;

/// 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 DefaultForeignCallBuilder<'a> {
pub output: PrintOutput<'a>,
#[cfg(feature = "rpc")]
pub resolver_url: Option<String>,
#[cfg(feature = "rpc")]
pub root_path: Option<std::path::PathBuf>,
#[cfg(feature = "rpc")]
pub package_name: Option<String>,
}

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<F>(self) -> DefaultForeignCallLayers<'a, layers::Empty, F>
where
F: AcirField + Serialize + for<'de> Deserialize<'de> + 'a,
{
self.build_with_base(layers::Empty)
}

/// Compose the executor layers with `base` as the default handler.
pub fn build_with_base<B, F>(self, base: B) -> DefaultForeignCallLayers<'a, B, F>
where
F: AcirField + Serialize + for<'de> Deserialize<'de> + 'a,
B: ForeignCallExecutor<F> + '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<MockForeignCallExecutor<F>, Layer<Option<RPCForeignCallExecutor>, B>>,
>;
#[cfg(not(feature = "rpc"))]
pub type DefaultForeignCallLayers<'a, B, F> =
Layer<PrintForeignCallExecutor<'a>, Layer<MockForeignCallExecutor<F>, 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 `DefaultForeignCallBuilder` 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<std::path::PathBuf>,
package_name: Option<String>,
) -> impl ForeignCallExecutor<F> + 'a
where
F: AcirField + Serialize + for<'de> Deserialize<'de> + 'a,
{
DefaultForeignCallBuilder {
output,
resolver_url: resolver_url.map(|s| s.to_string()),
root_path,
package_name,
}
.build()
}
}
Loading
Loading