Skip to content

Commit

Permalink
feat: Sync from noir (AztecProtocol/aztec-packages#5725)
Browse files Browse the repository at this point in the history
Automated pull of development from the
[noir](https://github.com/noir-lang/noir) programming language, a
dependency of Aztec.
BEGIN_COMMIT_OVERRIDE
feat: get last mock oracles params
(#4789)
feat: split `backend_barretenburg` into prover and verifier classes
(#4769)
chore: testing that nargo fmt is idempotent
(#4765)
feat: Sync from aztec-packages
(#4787)
fix: ArrayGet and Set are not pure
(#4783)
END_COMMIT_OVERRIDE

---------

Co-authored-by: Santiago Palladino <santiago@aztecprotocol.com>
  • Loading branch information
AztecBot and spalladino committed Apr 12, 2024
2 parents dad8e65 + e55ce6c commit 653feca
Show file tree
Hide file tree
Showing 15 changed files with 472 additions and 206 deletions.
2 changes: 1 addition & 1 deletion .aztec-sync-commit
Original file line number Diff line number Diff line change
@@ -1 +1 @@
145cbcda61fd73f4e135348b31c59c774cfae965
825c455a62faeae5d148ce4f914efacb8f4c50fd
7 changes: 7 additions & 0 deletions noir_stdlib/src/test.nr
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ unconstrained fn create_mock_oracle<N>(name: str<N>) -> Field {}
#[oracle(set_mock_params)]
unconstrained fn set_mock_params_oracle<P>(id: Field, params: P) {}

#[oracle(get_mock_last_params)]
unconstrained fn get_mock_last_params_oracle<P>(id: Field) -> P {}

#[oracle(set_mock_returns)]
unconstrained fn set_mock_returns_oracle<R>(id: Field, returns: R) {}

Expand All @@ -27,6 +30,10 @@ impl OracleMock {
self
}

unconstrained pub fn get_last_params<P>(self) -> P {
get_mock_last_params_oracle(self.id)
}

unconstrained pub fn returns<R>(self, returns: R) -> Self {
set_mock_returns_oracle(self.id, returns);
self
Expand Down
2 changes: 0 additions & 2 deletions test_programs/execution_success/mock_oracle/Prover.toml

This file was deleted.

27 changes: 0 additions & 27 deletions test_programs/execution_success/mock_oracle/src/main.nr

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@
name = "mock_oracle"
type = "bin"
authors = [""]
compiler_version = ">=0.23.0"

[dependencies]
[dependencies]
Empty file.
130 changes: 130 additions & 0 deletions test_programs/noir_test_success/mock_oracle/src/main.nr
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
use dep::std::test::OracleMock;

struct Point {
x: Field,
y: Field,
}

impl Eq for Point {
fn eq(self, other: Point) -> bool {
(self.x == other.x) & (self.y == other.y)
}
}

#[oracle(void_field)]
unconstrained fn void_field_oracle() -> Field {}

unconstrained fn void_field() -> Field {
void_field_oracle()
}

#[oracle(field_field)]
unconstrained fn field_field_oracle(_x: Field) -> Field {}

unconstrained fn field_field(x: Field) -> Field {
field_field_oracle(x)
}

#[oracle(struct_field)]
unconstrained fn struct_field_oracle(_point: Point, _array: [Field; 4]) -> Field {}

unconstrained fn struct_field(point: Point, array: [Field; 4]) -> Field {
struct_field_oracle(point, array)
}

#[test(should_fail)]
fn test_mock_no_returns() {
OracleMock::mock("void_field");
void_field(); // Some return value must be set
}

#[test]
fn test_mock() {
OracleMock::mock("void_field").returns(10);
assert_eq(void_field(), 10);
}

#[test]
fn test_multiple_mock() {
let first_mock = OracleMock::mock("void_field").returns(10);
OracleMock::mock("void_field").returns(42);

// The mocks are searched for in creation order, so the first one prevents the second from being called.
assert_eq(void_field(), 10);

first_mock.clear();
assert_eq(void_field(), 42);
}

#[test]
fn test_multiple_mock_times() {
OracleMock::mock("void_field").returns(10).times(2);
OracleMock::mock("void_field").returns(42);

assert_eq(void_field(), 10);
assert_eq(void_field(), 10);
assert_eq(void_field(), 42);
}

#[test]
fn test_mock_with_params() {
OracleMock::mock("field_field").with_params((5,)).returns(10);
assert_eq(field_field(5), 10);
}

#[test]
fn test_multiple_mock_with_params() {
OracleMock::mock("field_field").with_params((5,)).returns(10);
OracleMock::mock("field_field").with_params((7,)).returns(14);

assert_eq(field_field(5), 10);
assert_eq(field_field(7), 14);
}

#[test]
fn test_mock_last_params() {
let mock = OracleMock::mock("field_field").returns(10);
assert_eq(field_field(5), 10);

assert_eq(mock.get_last_params(), 5);
}

#[test]
fn test_mock_last_params_many_calls() {
let mock = OracleMock::mock("field_field").returns(10);
assert_eq(field_field(5), 10);
assert_eq(field_field(7), 10);

assert_eq(mock.get_last_params(), 7);
}

#[test]
fn test_mock_struct_field() {
// Combination of simpler test cases

let array = [1, 2, 3, 4];
let another_array = [4, 3, 2, 1];
let point = Point { x: 14, y: 27 };

OracleMock::mock("struct_field").returns(42).times(2);
let timeless_mock = OracleMock::mock("struct_field").returns(0);

assert_eq(42, struct_field(point, array));
assert_eq(42, struct_field(point, array));
// The times(2) mock is now cleared

assert_eq(0, struct_field(point, array));

let last_params: (Point, [Field; 4]) = timeless_mock.get_last_params();
assert_eq(last_params.0, point);
assert_eq(last_params.1, array);

// We clear the mock with no times() to allow other mocks to be callable
timeless_mock.clear();

OracleMock::mock("struct_field").with_params((point, array)).returns(10);
OracleMock::mock("struct_field").with_params((point, another_array)).returns(20);
assert_eq(10, struct_field(point, array));
assert_eq(20, struct_field(point, another_array));
}

38 changes: 33 additions & 5 deletions tooling/nargo/src/ops/foreign_calls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ pub enum ForeignCall {
AssertMessage,
CreateMock,
SetMockParams,
GetMockLastParams,
SetMockReturns,
SetMockTimes,
ClearMock,
Expand All @@ -93,6 +94,7 @@ impl ForeignCall {
ForeignCall::AssertMessage => "assert_message",
ForeignCall::CreateMock => "create_mock",
ForeignCall::SetMockParams => "set_mock_params",
ForeignCall::GetMockLastParams => "get_mock_last_params",
ForeignCall::SetMockReturns => "set_mock_returns",
ForeignCall::SetMockTimes => "set_mock_times",
ForeignCall::ClearMock => "clear_mock",
Expand All @@ -105,6 +107,7 @@ impl ForeignCall {
"assert_message" => Some(ForeignCall::AssertMessage),
"create_mock" => Some(ForeignCall::CreateMock),
"set_mock_params" => Some(ForeignCall::SetMockParams),
"get_mock_last_params" => Some(ForeignCall::GetMockLastParams),
"set_mock_returns" => Some(ForeignCall::SetMockReturns),
"set_mock_times" => Some(ForeignCall::SetMockTimes),
"clear_mock" => Some(ForeignCall::ClearMock),
Expand All @@ -122,6 +125,8 @@ struct MockedCall {
name: String,
/// Optionally match the parameters
params: Option<Vec<ForeignCallParam>>,
/// The parameters with which the mock was last called
last_called_params: Option<Vec<ForeignCallParam>>,
/// The result to return when this mock is called
result: ForeignCallResult,
/// How many times should this mock be called before it is removed
Expand All @@ -134,6 +139,7 @@ impl MockedCall {
id,
name,
params: None,
last_called_params: None,
result: ForeignCallResult { values: vec![] },
times_left: None,
}
Expand Down Expand Up @@ -185,7 +191,11 @@ impl DefaultForeignCallExecutor {
Ok((id, params))
}

fn find_mock_by_id(&mut self, id: usize) -> Option<&mut MockedCall> {
fn find_mock_by_id(&self, id: usize) -> Option<&MockedCall> {
self.mocked_responses.iter().find(|response| response.id == id)
}

fn find_mock_by_id_mut(&mut self, id: usize) -> Option<&mut MockedCall> {
self.mocked_responses.iter_mut().find(|response| response.id == id)
}

Expand Down Expand Up @@ -250,15 +260,27 @@ impl ForeignCallExecutor for DefaultForeignCallExecutor {
}
Some(ForeignCall::SetMockParams) => {
let (id, params) = Self::extract_mock_id(&foreign_call.inputs)?;
self.find_mock_by_id(id)
self.find_mock_by_id_mut(id)
.unwrap_or_else(|| panic!("Unknown mock id {}", id))
.params = Some(params.to_vec());

Ok(ForeignCallResult::default().into())
}
Some(ForeignCall::GetMockLastParams) => {
let (id, _) = Self::extract_mock_id(&foreign_call.inputs)?;
let mock =
self.find_mock_by_id(id).unwrap_or_else(|| panic!("Unknown mock id {}", id));

let last_called_params = mock
.last_called_params
.clone()
.unwrap_or_else(|| panic!("Mock {} was never called", mock.name));

Ok(last_called_params.into())
}
Some(ForeignCall::SetMockReturns) => {
let (id, params) = Self::extract_mock_id(&foreign_call.inputs)?;
self.find_mock_by_id(id)
self.find_mock_by_id_mut(id)
.unwrap_or_else(|| panic!("Unknown mock id {}", id))
.result = ForeignCallResult { values: params.to_vec() };

Expand All @@ -269,7 +291,7 @@ impl ForeignCallExecutor for DefaultForeignCallExecutor {
let times =
params[0].unwrap_field().try_to_u64().expect("Invalid bit size of times");

self.find_mock_by_id(id)
self.find_mock_by_id_mut(id)
.unwrap_or_else(|| panic!("Unknown mock id {}", id))
.times_left = Some(times);

Expand All @@ -292,6 +314,9 @@ impl ForeignCallExecutor for DefaultForeignCallExecutor {
.mocked_responses
.get_mut(response_position)
.expect("Invalid position of mocked response");

mock.last_called_params = Some(foreign_call.inputs.clone());

let result = mock.result.values.clone();

if let Some(times_left) = &mut mock.times_left {
Expand All @@ -316,7 +341,10 @@ impl ForeignCallExecutor for DefaultForeignCallExecutor {

Ok(parsed_response.into())
}
(None, None) => panic!("Unknown foreign call {}", foreign_call_name),
(None, None) => panic!(
"No mock for foreign call {}({:?})",
foreign_call_name, &foreign_call.inputs
),
}
}
}
Expand Down
51 changes: 39 additions & 12 deletions tooling/nargo_fmt/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,28 +49,55 @@ fn generate_formatter_tests(test_file: &mut File, test_data_dir: &Path) {
let output_source_path = outputs_dir.join(file_name).display().to_string();
let output_source = std::fs::read_to_string(output_source_path.clone()).unwrap();

let skip_idempotent_test =
// TODO(https://github.com/noir-lang/noir/issues/4766): spurious trailing space
test_name == "array" ||
// TODO(https://github.com/noir-lang/noir/issues/4767): pre-comment space
// TODO(https://github.com/noir-lang/noir/issues/4768): spurious newline
test_name == "tuple";

write!(
test_file,
r##"
#[test]
fn format_{test_name}() {{
let input = r#"{input_source}"#;
let expected_output = r#"{output_source}"#;
#[test]
fn format_{test_name}() {{
let input = r#"{input_source}"#;
let expected_output = r#"{output_source}"#;
let (parsed_module, _errors) = noirc_frontend::parse_program(input);
let (parsed_module, _errors) = noirc_frontend::parse_program(input);
let config = nargo_fmt::Config::of("{config}").unwrap();
let fmt_text = nargo_fmt::format(input, parsed_module, &config);
let config = nargo_fmt::Config::of("{config}").unwrap();
let fmt_text = nargo_fmt::format(input, parsed_module, &config);
if std::env::var("UPDATE_EXPECT").is_ok() {{
std::fs::write("{output_source_path}", fmt_text.clone()).unwrap();
}}
if std::env::var("UPDATE_EXPECT").is_ok() {{
std::fs::write("{output_source_path}", fmt_text.clone()).unwrap();
}}
similar_asserts::assert_eq!(fmt_text, expected_output);
}}
similar_asserts::assert_eq!(fmt_text, expected_output);
}}
"##
)
.expect("Could not write templated test file.");

if !skip_idempotent_test {
write!(
test_file,
r##"
#[test]
fn format_idempotent_{test_name}() {{
let expected_output = r#"{output_source}"#;
let (parsed_module, _errors) = noirc_frontend::parse_program(expected_output);
let config = nargo_fmt::Config::of("{config}").unwrap();
let fmt_text = nargo_fmt::format(expected_output, parsed_module, &config);
similar_asserts::assert_eq!(fmt_text, expected_output);
}}
"##
)
.expect("Could not write templated test file.");
}
}
}
Loading

0 comments on commit 653feca

Please sign in to comment.