From 5c649eca4d49ee12acd44de742326d6b97a1c9f5 Mon Sep 17 00:00:00 2001 From: Esau Date: Mon, 22 Jan 2024 19:09:06 +0100 Subject: [PATCH 1/7] Initial Fix test --- .../acir-simulator/src/acvm/oracle/oracle.ts | 2 + .../src/acvm/oracle/typed_oracle.ts | 1 + .../src/client/client_execution_context.ts | 4 +- .../src/client/pick_notes.test.ts | 102 +++++++++++-- .../acir-simulator/src/client/pick_notes.ts | 19 ++- .../src/client/view_data_oracle.ts | 4 +- .../archiver/src/archiver/eth_log_handlers.ts | 2 +- .../aztec-nr/aztec/src/note/note_getter.nr | 35 ++++- .../aztec/src/note/note_getter_options.nr | 27 +++- .../aztec/src/note/note_viewer_options.nr | 10 +- .../aztec-nr/aztec/src/oracle/notes.nr | 5 + yarn-project/aztec.js/src/index.ts | 1 + .../circuit-types/src/notes/note_filter.ts | 12 ++ .../end-to-end/src/e2e_note_getter.test.ts | 114 ++++++++++++++ yarn-project/foundation/src/fields/fields.ts | 4 + .../docs_example_contract/src/main.nr | 32 +++- .../docs_example_contract/src/options.nr | 8 +- .../docs_example_contract/src/types.nr | 1 + .../src/types/transparent_note.nr | 139 ++++++++++++++++++ .../contracts/escrow_contract/src/main.nr | 2 +- .../inclusion_proofs_contract/src/main.nr | 8 +- .../token_blacklist_contract/src/main.nr | 2 +- .../contracts/token_contract/src/main.nr | 2 +- 23 files changed, 495 insertions(+), 41 deletions(-) create mode 100644 yarn-project/end-to-end/src/e2e_note_getter.test.ts create mode 100644 yarn-project/noir-contracts/contracts/docs_example_contract/src/types/transparent_note.nr diff --git a/yarn-project/acir-simulator/src/acvm/oracle/oracle.ts b/yarn-project/acir-simulator/src/acvm/oracle/oracle.ts index 10a78d70875..994c6cab8ab 100644 --- a/yarn-project/acir-simulator/src/acvm/oracle/oracle.ts +++ b/yarn-project/acir-simulator/src/acvm/oracle/oracle.ts @@ -167,6 +167,7 @@ export class Oracle { [numSelects]: ACVMField[], selectBy: ACVMField[], selectValues: ACVMField[], + selectComparators: ACVMField[], sortBy: ACVMField[], sortOrder: ACVMField[], [limit]: ACVMField[], @@ -178,6 +179,7 @@ export class Oracle { +numSelects, selectBy.map(s => +s), selectValues.map(fromACVMField), + selectComparators.map(s => +s), sortBy.map(s => +s), sortOrder.map(s => +s), +limit, diff --git a/yarn-project/acir-simulator/src/acvm/oracle/typed_oracle.ts b/yarn-project/acir-simulator/src/acvm/oracle/typed_oracle.ts index 621a62db10f..1b49bc6f3ee 100644 --- a/yarn-project/acir-simulator/src/acvm/oracle/typed_oracle.ts +++ b/yarn-project/acir-simulator/src/acvm/oracle/typed_oracle.ts @@ -147,6 +147,7 @@ export abstract class TypedOracle { _numSelects: number, _selectBy: number[], _selectValues: Fr[], + _selectComparators: number[], _sortBy: number[], _sortOrder: number[], _limit: number, diff --git a/yarn-project/acir-simulator/src/client/client_execution_context.ts b/yarn-project/acir-simulator/src/client/client_execution_context.ts index 062cfdf4def..6e50e00be21 100644 --- a/yarn-project/acir-simulator/src/client/client_execution_context.ts +++ b/yarn-project/acir-simulator/src/client/client_execution_context.ts @@ -185,6 +185,7 @@ export class ClientExecutionContext extends ViewDataOracle { * @param numSelects - The number of valid selects in selectBy and selectValues. * @param selectBy - An array of indices of the fields to selects. * @param selectValues - The values to match. + * @param selectComparators - The comparators to match by. * @param sortBy - An array of indices of the fields to sort. * @param sortOrder - The order of the corresponding index in sortBy. (1: DESC, 2: ASC, 0: Do nothing) * @param limit - The number of notes to retrieve per query. @@ -196,6 +197,7 @@ export class ClientExecutionContext extends ViewDataOracle { numSelects: number, selectBy: number[], selectValues: Fr[], + selectComparators: number[], sortBy: number[], sortOrder: number[], limit: number, @@ -209,7 +211,7 @@ export class ClientExecutionContext extends ViewDataOracle { const dbNotesFiltered = dbNotes.filter(n => !pendingNullifiers.has((n.siloedNullifier as Fr).value)); const notes = pickNotes([...dbNotesFiltered, ...pendingNotes], { - selects: selectBy.slice(0, numSelects).map((index, i) => ({ index, value: selectValues[i] })), + selects: selectBy.slice(0, numSelects).map((index, i) => ({ index, value: selectValues[i], comparator: selectComparators[i] })), sorts: sortBy.map((index, i) => ({ index, order: sortOrder[i] })), limit, offset, diff --git a/yarn-project/acir-simulator/src/client/pick_notes.test.ts b/yarn-project/acir-simulator/src/client/pick_notes.test.ts index bf2ad610718..08080aeaa72 100644 --- a/yarn-project/acir-simulator/src/client/pick_notes.test.ts +++ b/yarn-project/acir-simulator/src/client/pick_notes.test.ts @@ -1,4 +1,4 @@ -import { Note } from '@aztec/circuit-types'; +import { Note, Comparator } from '@aztec/circuit-types'; import { Fr } from '@aztec/foundation/fields'; import { SortOrder, pickNotes } from './pick_notes.js'; @@ -141,7 +141,7 @@ describe('getNotes', () => { ]; { - const options = { selects: [{ index: 0, value: new Fr(2n) }] }; + const options = { selects: [{ index: 0, value: new Fr(2n), comparator: Comparator.EQ }] }; const result = pickNotes(notes, options); expectNotes(result, [ [2n, 1n, 3n], @@ -153,8 +153,8 @@ describe('getNotes', () => { { const options = { selects: [ - { index: 0, value: new Fr(2n) }, - { index: 2, value: new Fr(3n) }, + { index: 0, value: new Fr(2n), comparator: Comparator.EQ }, + { index: 2, value: new Fr(3n), comparator: Comparator.EQ }, ], }; const result = pickNotes(notes, options); @@ -167,8 +167,8 @@ describe('getNotes', () => { { const options = { selects: [ - { index: 1, value: new Fr(2n) }, - { index: 2, value: new Fr(3n) }, + { index: 1, value: new Fr(2n), comparator: Comparator.EQ }, + { index: 2, value: new Fr(3n), comparator: Comparator.EQ }, ], }; const result = pickNotes(notes, options); @@ -176,7 +176,7 @@ describe('getNotes', () => { } { - const options = { selects: [{ index: 1, value: new Fr(5n) }] }; + const options = { selects: [{ index: 1, value: new Fr(5n), comparator: Comparator.EQ }] }; const result = pickNotes(notes, options); expectNotes(result, []); } @@ -184,8 +184,8 @@ describe('getNotes', () => { { const options = { selects: [ - { index: 0, value: new Fr(2n) }, - { index: 1, value: new Fr(5n) }, + { index: 0, value: new Fr(2n), comparator: Comparator.EQ }, + { index: 1, value: new Fr(5n), comparator: Comparator.EQ }, ], }; const result = pickNotes(notes, options); @@ -203,7 +203,7 @@ describe('getNotes', () => { createNote([6n, 5n, 8n]), ]; - const options = { selects: [{ index: 2, value: new Fr(8n) }], sorts: [{ index: 1, order: SortOrder.ASC }] }; + const options = { selects: [{ index: 2, value: new Fr(8n), comparator: Comparator.EQ }], sorts: [{ index: 1, order: SortOrder.ASC }] }; const result = pickNotes(notes, options); expectNotes(result, [ [0n, 0n, 8n], @@ -212,4 +212,86 @@ describe('getNotes', () => { [7n, 6n, 8n], ]); }); + + it('should get sorted matching notes with GTE and LTE', () => { + const notes = [ + createNote([2n, 1n, 3n]), + createNote([4n, 5n, 8n]), + createNote([7n, 6n, 8n]), + createNote([6n, 5n, 2n]), + createNote([0n, 0n, 8n]), + createNote([6n, 5n, 8n]), + ]; + + const options = { + selects: [{ + index: 2, + value: new Fr(7n), + comparator: Comparator.GTE, + }, { + index: 2, + value: new Fr(8n), + comparator: Comparator.LTE, + }], + sorts: [{ + index: 1, order: SortOrder.ASC + }], + }; + const result = pickNotes(notes, options); + expectNotes(result, [ + [0n, 0n, 8n], + [4n, 5n, 8n], + [6n, 5n, 8n], + [7n, 6n, 8n], + ]); + }); + + it('should get sorted matching notes with GTE and LTE', () => { + const notes = [ + createNote([2n, 1n, 1n]), + createNote([4n, 5n, 2n]), + createNote([7n, 6n, 3n]), + createNote([6n, 5n, 4n]), + createNote([0n, 0n, 5n]), + createNote([6n, 5n, 6n]), + ]; + + const options1 = { + selects: [{ + index: 2, + value: new Fr(3n), + comparator: Comparator.GT, + }], + sorts: [{ + index: 1, order: SortOrder.ASC + }], + }; + + const result1 = pickNotes(notes, options1); + + expectNotes(result1, [ + [0n, 0n, 5n], + [6n, 5n, 4n], + [6n, 5n, 6n], + ]); + + const options2 = { + selects: [{ + index: 2, + value: new Fr(4n), + comparator: Comparator.LT, + }], + sorts: [{ + index: 1, order: SortOrder.ASC + }], + }; + + const result2 = pickNotes(notes, options2); + + expectNotes(result2, [ + [2n, 1n, 1n], + [4n, 5n, 2n], + [7n, 6n, 3n], + ]); + }); }); diff --git a/yarn-project/acir-simulator/src/client/pick_notes.ts b/yarn-project/acir-simulator/src/client/pick_notes.ts index a964cf35177..e2dce9c4ad9 100644 --- a/yarn-project/acir-simulator/src/client/pick_notes.ts +++ b/yarn-project/acir-simulator/src/client/pick_notes.ts @@ -1,4 +1,4 @@ -import { Note } from '@aztec/circuit-types'; +import { Comparator, Note } from '@aztec/circuit-types'; import { Fr } from '@aztec/foundation/fields'; /** @@ -13,6 +13,10 @@ export interface Select { * Required value of the field. */ value: Fr; + /** + * The comparator to use + */ + comparator: Comparator; } /** @@ -75,7 +79,18 @@ interface ContainsNote { } const selectNotes = (noteDatas: T[], selects: Select[]): T[] => - noteDatas.filter(noteData => selects.every(({ index, value }) => noteData.note.items[index]?.equals(value))); + noteDatas.filter(noteData => selects.every(({ index, value, comparator }) => { + const comparatorSelector = { + [Comparator.EQ]: () => noteData.note.items[index].equals(value), + [Comparator.NEQ]: () => !noteData.note.items[index].equals(value), + [Comparator.LT]: () => noteData.note.items[index].lt(value), + [Comparator.LTE]: () => noteData.note.items[index].lt(value) || noteData.note.items[index].equals(value), + [Comparator.GT]: () => !noteData.note.items[index].lt(value) && !noteData.note.items[index].equals(value), + [Comparator.GTE]: () => !noteData.note.items[index].lt(value), + } + + return comparatorSelector[comparator](); + })); const sortNotes = (a: Fr[], b: Fr[], sorts: Sort[], level = 0): number => { if (sorts[level] === undefined) { diff --git a/yarn-project/acir-simulator/src/client/view_data_oracle.ts b/yarn-project/acir-simulator/src/client/view_data_oracle.ts index 3b6128e3221..c444e5d26a3 100644 --- a/yarn-project/acir-simulator/src/client/view_data_oracle.ts +++ b/yarn-project/acir-simulator/src/client/view_data_oracle.ts @@ -198,6 +198,7 @@ export class ViewDataOracle extends TypedOracle { * @param numSelects - The number of valid selects in selectBy and selectValues. * @param selectBy - An array of indices of the fields to selects. * @param selectValues - The values to match. + * @param selectComparators - The comparators to use to match values. * @param sortBy - An array of indices of the fields to sort. * @param sortOrder - The order of the corresponding index in sortBy. (1: DESC, 2: ASC, 0: Do nothing) * @param limit - The number of notes to retrieve per query. @@ -209,6 +210,7 @@ export class ViewDataOracle extends TypedOracle { numSelects: number, selectBy: number[], selectValues: Fr[], + selectComparators: number[], sortBy: number[], sortOrder: number[], limit: number, @@ -216,7 +218,7 @@ export class ViewDataOracle extends TypedOracle { ): Promise { const dbNotes = await this.db.getNotes(this.contractAddress, storageSlot); return pickNotes(dbNotes, { - selects: selectBy.slice(0, numSelects).map((index, i) => ({ index, value: selectValues[i] })), + selects: selectBy.slice(0, numSelects).map((index, i) => ({ index, value: selectValues[i], comparator: selectComparators[i] })), sorts: sortBy.map((index, i) => ({ index, order: sortOrder[i] })), limit, offset, diff --git a/yarn-project/archiver/src/archiver/eth_log_handlers.ts b/yarn-project/archiver/src/archiver/eth_log_handlers.ts index 0d28ca2b4b2..b57a8775c57 100644 --- a/yarn-project/archiver/src/archiver/eth_log_handlers.ts +++ b/yarn-project/archiver/src/archiver/eth_log_handlers.ts @@ -107,7 +107,7 @@ async function getBlockFromCallData( if (functionName !== 'process') { throw new Error(`Unexpected method called ${functionName}`); } - const [headerHex, archiveRootHex, , bodyHex] = args! as [Hex, Hex, Hex, Hex, Hex]; + const [headerHex, archiveRootHex, , bodyHex, ] = args! as [Hex, Hex, Hex, Hex, Hex]; const blockBuffer = Buffer.concat([ Buffer.from(hexToBytes(headerHex)), Buffer.from(hexToBytes(archiveRootHex)), // L2Block.archive.root diff --git a/yarn-project/aztec-nr/aztec/src/note/note_getter.nr b/yarn-project/aztec-nr/aztec/src/note/note_getter.nr index 15b98f89f30..0a5420ff7ba 100644 --- a/yarn-project/aztec-nr/aztec/src/note/note_getter.nr +++ b/yarn-project/aztec-nr/aztec/src/note/note_getter.nr @@ -8,7 +8,7 @@ use dep::protocol_types::constants::{ }; use crate::context::PrivateContext; use crate::note::{ - note_getter_options::{NoteGetterOptions, Select, Sort, SortOrder}, + note_getter_options::{NoteGetterOptions, Select, Sort, SortOrder, Comparator}, note_interface::NoteInterface, note_viewer_options::NoteViewerOptions, utils::compute_note_hash_for_read_or_nullify, @@ -32,7 +32,24 @@ fn check_note_header( fn check_note_fields(fields: [Field; N], selects: BoundedVec, N>) { for i in 0..selects.len { let select = selects.get_unchecked(i).unwrap_unchecked(); - assert(fields[select.field_index] == select.value, "Mismatch return note field."); + + // Values are computed ahead of time because circuits evaluate all branches + let isEqual = fields[select.field_index] == select.value; + let isLt = fields[select.field_index].lt(select.value); + + if (select.comparator == Comparator.EQ) { + assert(isEqual, "Mismatch return note field."); + } else if (select.comparator == Comparator.NEQ) { + assert(!isEqual, "Mismatch return note field."); + } else if (select.comparator == Comparator.LT) { + assert(isLt, "Mismatch return note field."); + } else if (select.comparator == Comparator.LTE) { + assert(isLt | isEqual, "Mismatch return note field."); + } else if (select.comparator == Comparator.GT) { + assert(!isLt & !isEqual, "Mismatch return note field."); + } else if (select.comparator == Comparator.GTE) { + assert(!isLt, "Mismatch return note field."); + } } } @@ -115,6 +132,7 @@ unconstrained fn get_note_internal(storage_slot: Field, note_interface: [], [], [], + [], 1, // limit 0, // offset placeholder_note, @@ -127,7 +145,7 @@ unconstrained fn get_notes_internal( note_interface: NoteInterface, options: NoteGetterOptions ) -> [Option; MAX_READ_REQUESTS_PER_CALL] { - let (num_selects, select_by, select_values, sort_by, sort_order) = flatten_options(options.selects, options.sorts); + let (num_selects, select_by, select_values, select_comparators, sort_by, sort_order) = flatten_options(options.selects, options.sorts); let placeholder_opt_notes = [Option::none(); MAX_READ_REQUESTS_PER_CALL]; let placeholder_fields = [0; GET_NOTES_ORACLE_RETURN_LENGTH]; let opt_notes = oracle::notes::get_notes( @@ -136,6 +154,7 @@ unconstrained fn get_notes_internal( num_selects, select_by, select_values, + select_comparators, sort_by, sort_order, options.limit, @@ -154,7 +173,7 @@ unconstrained pub fn view_notes( note_interface: NoteInterface, options: NoteViewerOptions ) -> [Option; MAX_NOTES_PER_PAGE] { - let (num_selects, select_by, select_values, sort_by, sort_order) = flatten_options(options.selects, options.sorts); + let (num_selects, select_by, select_values, select_comparators, sort_by, sort_order) = flatten_options(options.selects, options.sorts); let placeholder_opt_notes = [Option::none(); MAX_NOTES_PER_PAGE]; let placeholder_fields = [0; VIEW_NOTE_ORACLE_RETURN_LENGTH]; oracle::notes::get_notes( @@ -163,6 +182,7 @@ unconstrained pub fn view_notes( num_selects, select_by, select_values, + select_comparators, sort_by, sort_order, options.limit, @@ -175,15 +195,18 @@ unconstrained pub fn view_notes( unconstrained fn flatten_options( selects: BoundedVec, N>, sorts: BoundedVec, N> -) -> (u8, [u8; N], [Field; N], [u8; N], [u2; N]) { +) -> (u8, [u8; N], [Field; N], [u3; N], [u8; N], [u2; N]) { let mut num_selects = 0; let mut select_by = [0; N]; let mut select_values = [0; N]; + let mut select_comparators = [0; N]; + for i in 0..selects.len { let select = selects.get(i); if select.is_some() { select_by[num_selects] = select.unwrap_unchecked().field_index; select_values[num_selects] = select.unwrap_unchecked().value; + select_comparators[num_selects] = select.unwrap_unchecked().comparator; num_selects += 1; }; } @@ -198,5 +221,5 @@ unconstrained fn flatten_options( }; } - (num_selects, select_by, select_values, sort_by, sort_order) + (num_selects, select_by, select_values, select_comparators, sort_by, sort_order) } diff --git a/yarn-project/aztec-nr/aztec/src/note/note_getter_options.nr b/yarn-project/aztec-nr/aztec/src/note/note_getter_options.nr index 8ceca5eb03e..97949b5e920 100644 --- a/yarn-project/aztec-nr/aztec/src/note/note_getter_options.nr +++ b/yarn-project/aztec-nr/aztec/src/note/note_getter_options.nr @@ -2,14 +2,33 @@ use dep::std::option::Option; use crate::types::vec::BoundedVec; use dep::protocol_types::constants::MAX_READ_REQUESTS_PER_CALL; +struct ComparatorEnum { + EQ: u3, + NEQ: u3, + LT: u3, + LTE: u3, + GT: u3, + GTE: u3, +} + +global Comparator = ComparatorEnum { + EQ: 1, + NEQ: 2, + LT: 3, + LTE: 4, + GT: 5, + GTE: 6, +}; + struct Select { field_index: u8, value: Field, + comparator: u3, } impl Select { - pub fn new(field_index: u8, value: Field) -> Self { - Select { field_index, value } + pub fn new(field_index: u8, value: Field, comparator: u3) -> Self { + Select { field_index, value, comparator } } } @@ -87,8 +106,8 @@ impl NoteGetterOptions { // This method adds a `Select` criterion to the options. // It takes a field_index indicating which field to select and a value representing the specific value to match in that field. - pub fn select(&mut self, field_index: u8, value: Field) -> Self { - self.selects.push(Option::some(Select::new(field_index, value))); + pub fn select(&mut self, field_index: u8, value: Field, comparator: Option) -> Self { + self.selects.push(Option::some(Select::new(field_index, value, comparator.unwrap_or(Comparator.EQ)))); *self } diff --git a/yarn-project/aztec-nr/aztec/src/note/note_viewer_options.nr b/yarn-project/aztec-nr/aztec/src/note/note_viewer_options.nr index 15d445d2c02..424567058e8 100644 --- a/yarn-project/aztec-nr/aztec/src/note/note_viewer_options.nr +++ b/yarn-project/aztec-nr/aztec/src/note/note_viewer_options.nr @@ -1,6 +1,6 @@ use dep::std::option::Option; use dep::protocol_types::constants::MAX_NOTES_PER_PAGE; -use crate::note::note_getter_options::{Select, Sort}; +use crate::note::note_getter_options::{Select, Sort, Comparator}; use crate::types::vec::BoundedVec; // docs:start:NoteViewerOptions @@ -21,9 +21,11 @@ impl NoteViewerOptions { offset: 0, } } - - pub fn select(&mut self, field_index: u8, value: Field) -> Self { - self.selects.push(Option::some(Select::new(field_index, value))); + + // This method adds a `Select` criterion to the options. + // It takes a field_index indicating which field to select and a value representing the specific value to match in that field. + pub fn select(&mut self, field_index: u8, value: Field, comparator: Option) -> Self { + self.selects.push(Option::some(Select::new(field_index, value, comparator.unwrap_or(Comparator.EQ)))); *self } diff --git a/yarn-project/aztec-nr/aztec/src/oracle/notes.nr b/yarn-project/aztec-nr/aztec/src/oracle/notes.nr index 88664e64dc8..4176e647578 100644 --- a/yarn-project/aztec-nr/aztec/src/oracle/notes.nr +++ b/yarn-project/aztec-nr/aztec/src/oracle/notes.nr @@ -27,6 +27,7 @@ fn get_notes_oracle( _num_selects: u8, _select_by: [u8; N], _select_values: [Field; N], + _select_comparators: [u3; N], _sort_by: [u8; N], _sort_order: [u2; N], _limit: u32, @@ -40,6 +41,7 @@ unconstrained fn get_notes_oracle_wrapper( num_selects: u8, select_by: [u8; N], select_values: [Field; N], + select_comparators: [u3; N], sort_by: [u8; N], sort_order: [u2; N], limit: u32, @@ -52,6 +54,7 @@ unconstrained fn get_notes_oracle_wrapper( num_selects, select_by, select_values, + select_comparators, sort_by, sort_order, limit, @@ -67,6 +70,7 @@ unconstrained pub fn get_notes( num_selects: u8, select_by: [u8; M], select_values: [Field; M], + select_comparators: [u3; M], sort_by: [u8; M], sort_order: [u2; M], limit: u32, @@ -79,6 +83,7 @@ unconstrained pub fn get_notes( num_selects, select_by, select_values, + select_comparators, sort_by, sort_order, limit, diff --git a/yarn-project/aztec.js/src/index.ts b/yarn-project/aztec.js/src/index.ts index ff2378a23bf..bc5558c8d9f 100644 --- a/yarn-project/aztec.js/src/index.ts +++ b/yarn-project/aztec.js/src/index.ts @@ -106,6 +106,7 @@ export { emptyFunctionCall, merkleTreeIds, mockTx, + Comparator, } from '@aztec/circuit-types'; export { NodeInfo } from '@aztec/types/interfaces'; diff --git a/yarn-project/circuit-types/src/notes/note_filter.ts b/yarn-project/circuit-types/src/notes/note_filter.ts index 515dabb7c35..362526d13ff 100644 --- a/yarn-project/circuit-types/src/notes/note_filter.ts +++ b/yarn-project/circuit-types/src/notes/note_filter.ts @@ -16,3 +16,15 @@ export type NoteFilter = { /** The owner of the note (whose public key was used to encrypt the note). */ owner?: AztecAddress; }; + +/** + * The comparator to use to compare. + */ +export enum Comparator { + EQ = 1, + NEQ = 2, + LT = 3, + LTE = 4, + GT = 5, + GTE = 6, +} diff --git a/yarn-project/end-to-end/src/e2e_note_getter.test.ts b/yarn-project/end-to-end/src/e2e_note_getter.test.ts new file mode 100644 index 00000000000..079fccb4ded --- /dev/null +++ b/yarn-project/end-to-end/src/e2e_note_getter.test.ts @@ -0,0 +1,114 @@ +import { Fr, Wallet, Comparator } from '@aztec/aztec.js'; +import { DocsExampleContract } from '@aztec/noir-contracts'; + +import { setup } from './fixtures/utils.js'; + +interface CardNotePartial { + randomness: bigint + points: bigint +} +interface NoirOption { + _is_some: boolean; + _value: T; +} + +function unwrapOptions(options: NoirOption[]): T[] { + return options.filter((option: any) => option._is_some).map((option: any) => option._value); +} + +describe('e2e_singleton', () => { + let wallet: Wallet; + + let teardown: () => Promise; + let contract: DocsExampleContract; + + beforeAll(async () => { + ({ teardown, wallet } = await setup()); + contract = await DocsExampleContract.deploy(wallet).send().deployed(); + // sets card value to 1 and leader to sender. + await contract.methods.initialize_private(Fr.random(), 1).send().wait(); + }, 25_000); + + afterAll(() => teardown()); + + // Singleton tests: + it('a test that inserts note and checks if ', async () => { + const numbers = [...Array(10).keys()]; + await Promise.all(numbers.map((number) => contract.methods.insert_note(number).send().wait())); + await contract.methods.insert_note(5).send().wait(); + + const [ + returnEq, + returnNeq, + returnLt, + returnGt, + returnLte, + returnGte, + ] = await Promise.all([ + contract.methods.read_note(5, Comparator.EQ).view(), + contract.methods.read_note(5, Comparator.NEQ).view(), + contract.methods.read_note(5, Comparator.LT).view(), + contract.methods.read_note(5, Comparator.GT).view(), + contract.methods.read_note(5, Comparator.LTE).view(), + contract.methods.read_note(5, Comparator.GTE).view(), + ]) + + expect(unwrapOptions(returnEq).map(({points, randomness}: any) => ({points, randomness}))) + .toStrictEqual([ + { points: 5n, randomness: 1n }, + { points: 5n, randomness: 1n }, + ]); + + expect(unwrapOptions(returnNeq).map(({points, randomness}: any) => ({points, randomness})).sort((a: any, b: any) => a.points > b.points ? 1 : -1)) + .toStrictEqual([ + { points: 0n, randomness: 1n }, + { points: 1n, randomness: 1n }, + { points: 7n, randomness: 1n }, + { points: 9n, randomness: 1n }, + { points: 2n, randomness: 1n }, + { points: 6n, randomness: 1n }, + { points: 8n, randomness: 1n }, + { points: 4n, randomness: 1n }, + { points: 3n, randomness: 1n }, + ].sort((a: any, b: any) => a.points > b.points ? 1 : -1)); + + expect(unwrapOptions(returnLt).map(({points, randomness}: any) => ({points, randomness})).sort((a: any, b: any) => a.points > b.points ? 1 : -1)) + .toStrictEqual([ + { points: 0n, randomness: 1n }, + { points: 1n, randomness: 1n }, + { points: 2n, randomness: 1n }, + { points: 4n, randomness: 1n }, + { points: 3n, randomness: 1n }, + ].sort((a: any, b: any) => a.points > b.points ? 1 : -1)); + + expect(unwrapOptions(returnGt).map(({points, randomness}: any) => ({points, randomness})).sort((a: any, b: any) => a.points > b.points ? 1 : -1)) + .toStrictEqual([ + { points: 7n, randomness: 1n }, + { points: 9n, randomness: 1n }, + { points: 6n, randomness: 1n }, + { points: 8n, randomness: 1n }, + ].sort((a: any, b: any) => a.points > b.points ? 1 : -1)); + + expect(unwrapOptions(returnLte).map(({points, randomness}: any) => ({points, randomness})).sort((a: any, b: any) => a.points > b.points ? 1 : -1)) + .toStrictEqual([ + { points: 5n, randomness: 1n }, + { points: 5n, randomness: 1n }, + { points: 0n, randomness: 1n }, + { points: 1n, randomness: 1n }, + { points: 2n, randomness: 1n }, + { points: 4n, randomness: 1n }, + { points: 3n, randomness: 1n }, + ].sort((a: any, b: any) => a.points > b.points ? 1 : -1)); + + expect(unwrapOptions(returnGte).map(({points, randomness}: any) => ({points, randomness})).sort((a: any, b: any) => a.points > b.points ? 1 : -1)) + .toStrictEqual([ + { points: 5n, randomness: 1n }, + { points: 5n, randomness: 1n }, + { points: 7n, randomness: 1n }, + { points: 9n, randomness: 1n }, + { points: 6n, randomness: 1n }, + { points: 8n, randomness: 1n }, + ].sort((a: any, b: any) => a.points > b.points ? 1 : -1)); + + }, 300_000); +}); diff --git a/yarn-project/foundation/src/fields/fields.ts b/yarn-project/foundation/src/fields/fields.ts index bbf2f3b9a20..0e622cd4fde 100644 --- a/yarn-project/foundation/src/fields/fields.ts +++ b/yarn-project/foundation/src/fields/fields.ts @@ -104,6 +104,10 @@ abstract class BaseField { return this.toBuffer().equals(rhs.toBuffer()); } + lt(rhs: BaseField): boolean { + return this.toBigInt() < rhs.toBigInt(); + } + isZero(): boolean { return this.toBuffer().equals(ZERO_BUFFER); } diff --git a/yarn-project/noir-contracts/contracts/docs_example_contract/src/main.nr b/yarn-project/noir-contracts/contracts/docs_example_contract/src/main.nr index 6662f6de2f0..4f5f38a2c27 100644 --- a/yarn-project/noir-contracts/contracts/docs_example_contract/src/main.nr +++ b/yarn-project/noir-contracts/contracts/docs_example_contract/src/main.nr @@ -18,16 +18,22 @@ contract DocsExample { address::AztecAddress, }; use dep::aztec::{ + oracle::{ + debug_log::debug_log_format, + }, note::{ note_header::NoteHeader, + note_getter_options::{NoteGetterOptions, Comparator}, + note_viewer_options::{NoteViewerOptions}, utils as note_utils, }, context::{PrivateContext, PublicContext, Context}, - state_vars::{map::Map, public_state::PublicState,singleton::Singleton}, + state_vars::{map::Map, public_state::PublicState,singleton::Singleton, set::Set}, }; // how to import methods from other files/folders within your workspace use crate::options::create_account_card_getter_options; use crate::types::{ + transparent_note::{TransparentNote, TransparentNoteMethods, TRANSPARENT_NOTE_LEN}, card_note::{CardNote, CardNoteMethods, CARD_NOTE_LEN}, leader::{Leader, LeaderSerializationMethods, LEADER_SERIALIZED_LEN}, }; @@ -42,6 +48,7 @@ contract DocsExample { // docs:start:storage-map-singleton-declaration profiles: Map>, // docs:end:storage-map-singleton-declaration + test: Set, } impl Storage { @@ -65,6 +72,7 @@ contract DocsExample { }, ), // docs:end:state_vars-MapSingleton + test: Set::new(context, 4, CardNoteMethods), } } } @@ -80,6 +88,28 @@ contract DocsExample { storage.legendary_card.initialize(&mut legendary_card, Option::none(), true); } + #[aztec(private)] + fn insert_note(amount: u8) { + let mut note = CardNote::new(amount, 1, context.msg_sender()); + storage.test.insert(&mut note, true); + } + + unconstrained fn read_note(amount: Field, comparator: u3) -> pub [Option; 10] { + let options = NoteViewerOptions::new().select(0, amount, Option::some(comparator)); + let notes = storage.test.view_notes(options); + + for i in 0..notes.len() { + if notes[i].is_some() { + debug_log_format( + "NOTES THAT MATCH: {0}", + [notes[i].unwrap_unchecked().points as Field] + ); + } + } + + notes + } + #[aztec(private)] fn update_legendary_card(randomness: Field, points: u8) { // Ensure `points` > current value diff --git a/yarn-project/noir-contracts/contracts/docs_example_contract/src/options.nr b/yarn-project/noir-contracts/contracts/docs_example_contract/src/options.nr index 9742345f8ca..9f1173f7588 100644 --- a/yarn-project/noir-contracts/contracts/docs_example_contract/src/options.nr +++ b/yarn-project/noir-contracts/contracts/docs_example_contract/src/options.nr @@ -13,7 +13,7 @@ pub fn create_account_card_getter_options( account: AztecAddress, offset: u32 ) -> NoteGetterOptions { - NoteGetterOptions::new().select(2, account.to_field()).sort(0, SortOrder.DESC).set_offset(offset) + NoteGetterOptions::new().select(2, account.to_field(), Option::none()).sort(0, SortOrder.DESC).set_offset(offset) } // docs:end:state_vars-NoteGetterOptionsSelectSortOffset @@ -23,7 +23,7 @@ pub fn create_exact_card_getter_options( secret: Field, account: AztecAddress ) -> NoteGetterOptions { - NoteGetterOptions::new().select(0, points as Field).select(1, secret).select(2, account.to_field()) + NoteGetterOptions::new().select(0, points as Field, Option::none()).select(1, secret, Option::none()).select(2, account.to_field(), Option::none()) } // docs:end:state_vars-NoteGetterOptionsMultiSelects @@ -46,12 +46,12 @@ pub fn filter_min_points( // docs:start:state_vars-NoteGetterOptionsFilter pub fn create_account_cards_with_min_points_getter_options(account: AztecAddress, min_points: u8) -> NoteGetterOptions { - NoteGetterOptions::with_filter(filter_min_points, min_points).select(2, account.to_field()).sort(0, SortOrder.ASC) + NoteGetterOptions::with_filter(filter_min_points, min_points).select(2, account.to_field(), Option::none()).sort(0, SortOrder.ASC) } // docs:end:state_vars-NoteGetterOptionsFilter // docs:start:state_vars-NoteGetterOptionsPickOne pub fn create_largest_account_card_getter_options(account: AztecAddress) -> NoteGetterOptions { - NoteGetterOptions::new().select(2, account.to_field()).sort(0, SortOrder.DESC).set_limit(1) + NoteGetterOptions::new().select(2, account.to_field(), Option::none()).sort(0, SortOrder.DESC).set_limit(1) } // docs:end:state_vars-NoteGetterOptionsPickOne diff --git a/yarn-project/noir-contracts/contracts/docs_example_contract/src/types.nr b/yarn-project/noir-contracts/contracts/docs_example_contract/src/types.nr index 630d5c9b87e..965909d4800 100644 --- a/yarn-project/noir-contracts/contracts/docs_example_contract/src/types.nr +++ b/yarn-project/noir-contracts/contracts/docs_example_contract/src/types.nr @@ -1,2 +1,3 @@ mod card_note; mod leader; +mod transparent_note; diff --git a/yarn-project/noir-contracts/contracts/docs_example_contract/src/types/transparent_note.nr b/yarn-project/noir-contracts/contracts/docs_example_contract/src/types/transparent_note.nr new file mode 100644 index 00000000000..deb2bcdf6f1 --- /dev/null +++ b/yarn-project/noir-contracts/contracts/docs_example_contract/src/types/transparent_note.nr @@ -0,0 +1,139 @@ +// docs:start:token_types_all +use dep::aztec::{ + note::{ + note_header::NoteHeader, + note_interface::NoteInterface, + utils::compute_siloed_note_hash, + }, + hash::{compute_secret_hash, pedersen_hash}, + context::PrivateContext, +}; + +global TRANSPARENT_NOTE_LEN: Field = 2; + +// Transparent note represents a note that is created in the clear (public execution), +// but can only be spent by those that know the preimage of the "secret_hash" +struct TransparentNote { + amount: Field, + secret_hash: Field, + // the secret is just here for ease of use and won't be (de)serialized + secret: Field, + // header is just here to satisfy the NoteInterface + header: NoteHeader, +} + +impl TransparentNote { + + // CONSTRUCTORS + + pub fn new(amount: Field, secret_hash: Field) -> Self { + TransparentNote { + amount: amount, + secret_hash: secret_hash, + secret: 0, + header: NoteHeader::empty(), + } + } + + // new oracle call primitive + // get me the secret corresponding to this hash + pub fn new_from_secret(amount: Field, secret: Field) -> Self { + TransparentNote { + amount: amount, + secret_hash: compute_secret_hash(secret), + secret: secret, + header: NoteHeader::empty(), + } + } + + + // STANDARD NOTE_INTERFACE FUNCTIONS + + pub fn serialize(self) -> [Field; TRANSPARENT_NOTE_LEN] { + [self.amount, self.secret_hash] + } + + pub fn deserialize(serialized_note: [Field; TRANSPARENT_NOTE_LEN]) -> Self { + TransparentNote { + amount: serialized_note[0], + secret_hash: serialized_note[1], + secret: 0, + header: NoteHeader::empty(), + } + } + + pub fn compute_note_hash(self) -> Field { + // TODO(#1205) Should use a non-zero generator index. + pedersen_hash([ + self.amount, + self.secret_hash, + ],0) + } + + pub fn compute_nullifier(self, _context: &mut PrivateContext) -> Field { + self.compute_nullifier_without_context() + } + + pub fn compute_nullifier_without_context(self) -> Field { + // TODO(#1386): should use `compute_note_hash_for_read_or_nullify` once public functions inject nonce! + let siloed_note_hash = compute_siloed_note_hash(TransparentNoteMethods, self); + // TODO(#1205) Should use a non-zero generator index. + pedersen_hash([self.secret, siloed_note_hash],0) + } + + pub fn set_header(&mut self, header: NoteHeader) { + self.header = header; + } + + + // CUSTOM FUNCTIONS FOR THIS NOTE TYPE + + pub fn knows_secret(self, secret: Field) { + let hash = compute_secret_hash(secret); + assert(self.secret_hash == hash); + } +} + +fn deserialize(serialized_note: [Field; TRANSPARENT_NOTE_LEN]) -> TransparentNote { + TransparentNote::deserialize(serialized_note) +} + +fn serialize(note: TransparentNote) -> [Field; TRANSPARENT_NOTE_LEN] { + note.serialize() +} + +fn compute_note_hash(note: TransparentNote) -> Field { + note.compute_note_hash() +} + +fn compute_nullifier(note: TransparentNote, context: &mut PrivateContext) -> Field { + note.compute_nullifier(context) +} + +fn compute_nullifier_without_context(note: TransparentNote) -> Field { + note.compute_nullifier_without_context() +} + +fn get_header(note: TransparentNote) -> NoteHeader { + note.header +} + +fn set_header(note: &mut TransparentNote, header: NoteHeader) { + note.set_header(header) +} + +fn broadcast(context: &mut PrivateContext, slot: Field, note: TransparentNote) { + assert(false, "TransparentNote does not support broadcast"); +} + +global TransparentNoteMethods = NoteInterface { + deserialize, + serialize, + compute_note_hash, + compute_nullifier, + compute_nullifier_without_context, + get_header, + set_header, + broadcast, +}; +// docs:end:token_types_all \ No newline at end of file diff --git a/yarn-project/noir-contracts/contracts/escrow_contract/src/main.nr b/yarn-project/noir-contracts/contracts/escrow_contract/src/main.nr index cf7500c7fa6..09b92c5131f 100644 --- a/yarn-project/noir-contracts/contracts/escrow_contract/src/main.nr +++ b/yarn-project/noir-contracts/contracts/escrow_contract/src/main.nr @@ -57,7 +57,7 @@ contract Escrow { let sender = context.msg_sender(); // We don't remove note from the owners set. If a note exists, the owner and recipient are legit. - let options = NoteGetterOptions::new().select(0, sender.to_field()).select(1, this.to_field()).set_limit(1); + let options = NoteGetterOptions::new().select(0, sender.to_field(), Option::none()).select(1, this.to_field(), Option::none()).set_limit(1); let notes = storage.owners.get_notes(options); assert(notes[0].is_some(), "Sender is not an owner."); diff --git a/yarn-project/noir-contracts/contracts/inclusion_proofs_contract/src/main.nr b/yarn-project/noir-contracts/contracts/inclusion_proofs_contract/src/main.nr index 411fcaf5c35..12cd74544a5 100644 --- a/yarn-project/noir-contracts/contracts/inclusion_proofs_contract/src/main.nr +++ b/yarn-project/noir-contracts/contracts/inclusion_proofs_contract/src/main.nr @@ -104,7 +104,7 @@ contract InclusionProofs { ) { // 1) Get the note from PXE. let private_values = storage.private_values.at(owner); - let options = NoteGetterOptions::new().select(1, owner.to_field()).set_limit(1); + let options = NoteGetterOptions::new().select(1, owner.to_field(), Option::none()).set_limit(1); let notes = private_values.get_notes(options); let maybe_note = notes[0]; @@ -134,7 +134,7 @@ contract InclusionProofs { ) { // 2) Get the note from PXE let private_values = storage.private_values.at(owner); - let options = NoteGetterOptions::new().select(1, owner.to_field()).set_limit(1); + let options = NoteGetterOptions::new().select(1, owner.to_field(), Option::none()).set_limit(1); let notes = private_values.get_notes(options); let maybe_note = notes[0]; @@ -159,7 +159,7 @@ contract InclusionProofs { ) { // 1) Get the note from PXE. let private_values = storage.private_values.at(owner); - let options = NoteGetterOptions::new().select(1, owner.to_field()).set_limit(1); + let options = NoteGetterOptions::new().select(1, owner.to_field(), Option::none()).set_limit(1); let notes = private_values.get_notes(options); let note = notes[0].unwrap(); @@ -170,7 +170,7 @@ contract InclusionProofs { #[aztec(private)] fn nullify_note(owner: AztecAddress) { let private_values = storage.private_values.at(owner); - let options = NoteGetterOptions::new().select(1, owner.to_field()).set_limit(1); + let options = NoteGetterOptions::new().select(1, owner.to_field(), Option::none()).set_limit(1); let notes = private_values.get_notes(options); let note = notes[0].unwrap(); diff --git a/yarn-project/noir-contracts/contracts/token_blacklist_contract/src/main.nr b/yarn-project/noir-contracts/contracts/token_blacklist_contract/src/main.nr index 0845c0ec0da..db026c03c5c 100644 --- a/yarn-project/noir-contracts/contracts/token_blacklist_contract/src/main.nr +++ b/yarn-project/noir-contracts/contracts/token_blacklist_contract/src/main.nr @@ -281,7 +281,7 @@ contract TokenBlacklist { let secret_hash = compute_secret_hash(secret); // Get 1 note (set_limit(1)) which has amount stored in field with index 0 (select(0, amount)) and secret_hash // stored in field with index 1 (select(1, secret_hash)). - let options = NoteGetterOptions::new().select(0, amount).select(1, secret_hash).set_limit(1); + let options = NoteGetterOptions::new().select(0, amount, Option::none()).select(1, secret_hash, Option::none()).set_limit(1); let notes = pending_shields.get_notes(options); let note = notes[0].unwrap_unchecked(); // Remove the note from the pending shields set diff --git a/yarn-project/noir-contracts/contracts/token_contract/src/main.nr b/yarn-project/noir-contracts/contracts/token_contract/src/main.nr index 6aa5c0f88d3..080f252969b 100644 --- a/yarn-project/noir-contracts/contracts/token_contract/src/main.nr +++ b/yarn-project/noir-contracts/contracts/token_contract/src/main.nr @@ -301,7 +301,7 @@ contract Token { let secret_hash = compute_secret_hash(secret); // Get 1 note (set_limit(1)) which has amount stored in field with index 0 (select(0, amount)) and secret_hash // stored in field with index 1 (select(1, secret_hash)). - let options = NoteGetterOptions::new().select(0, amount).select(1, secret_hash).set_limit(1); + let options = NoteGetterOptions::new().select(0, amount, Option::none()).select(1, secret_hash, Option::none()).set_limit(1); let notes = pending_shields.get_notes(options); let note = notes[0].unwrap_unchecked(); // Remove the note from the pending shields set From acde9c630acbef5a9683f456b4201f687a22e82a Mon Sep 17 00:00:00 2001 From: Esau Date: Thu, 25 Jan 2024 15:04:07 +0100 Subject: [PATCH 2/7] Fixing review comments p1 --- .../aztec/src/note/note_getter_options.nr | 4 +- .../aztec/src/note/note_viewer_options.nr | 4 +- .../docs_example_contract/src/main.nr | 1 - .../docs_example_contract/src/types.nr | 1 - .../src/types/transparent_note.nr | 139 ------------------ 5 files changed, 6 insertions(+), 143 deletions(-) delete mode 100644 yarn-project/noir-contracts/contracts/docs_example_contract/src/types/transparent_note.nr diff --git a/yarn-project/aztec-nr/aztec/src/note/note_getter_options.nr b/yarn-project/aztec-nr/aztec/src/note/note_getter_options.nr index 97949b5e920..78fbeffd553 100644 --- a/yarn-project/aztec-nr/aztec/src/note/note_getter_options.nr +++ b/yarn-project/aztec-nr/aztec/src/note/note_getter_options.nr @@ -105,7 +105,9 @@ impl NoteGetterOptions { } // This method adds a `Select` criterion to the options. - // It takes a field_index indicating which field to select and a value representing the specific value to match in that field. + // It takes a field_index indicating which field to select, + // a value representing the specific value to match in that field, and + // a comparator (For possible values of comparators, please see the Comparator enum above) pub fn select(&mut self, field_index: u8, value: Field, comparator: Option) -> Self { self.selects.push(Option::some(Select::new(field_index, value, comparator.unwrap_or(Comparator.EQ)))); *self diff --git a/yarn-project/aztec-nr/aztec/src/note/note_viewer_options.nr b/yarn-project/aztec-nr/aztec/src/note/note_viewer_options.nr index 424567058e8..34c7271bfeb 100644 --- a/yarn-project/aztec-nr/aztec/src/note/note_viewer_options.nr +++ b/yarn-project/aztec-nr/aztec/src/note/note_viewer_options.nr @@ -23,7 +23,9 @@ impl NoteViewerOptions { } // This method adds a `Select` criterion to the options. - // It takes a field_index indicating which field to select and a value representing the specific value to match in that field. + // It takes a field_index indicating which field to select, + // a value representing the specific value to match in that field, and + // a comparator (For possible values of comparators, please see the Comparator enum from note_getter_options) pub fn select(&mut self, field_index: u8, value: Field, comparator: Option) -> Self { self.selects.push(Option::some(Select::new(field_index, value, comparator.unwrap_or(Comparator.EQ)))); *self diff --git a/yarn-project/noir-contracts/contracts/docs_example_contract/src/main.nr b/yarn-project/noir-contracts/contracts/docs_example_contract/src/main.nr index 4f5f38a2c27..a5d224e2702 100644 --- a/yarn-project/noir-contracts/contracts/docs_example_contract/src/main.nr +++ b/yarn-project/noir-contracts/contracts/docs_example_contract/src/main.nr @@ -33,7 +33,6 @@ contract DocsExample { // how to import methods from other files/folders within your workspace use crate::options::create_account_card_getter_options; use crate::types::{ - transparent_note::{TransparentNote, TransparentNoteMethods, TRANSPARENT_NOTE_LEN}, card_note::{CardNote, CardNoteMethods, CARD_NOTE_LEN}, leader::{Leader, LeaderSerializationMethods, LEADER_SERIALIZED_LEN}, }; diff --git a/yarn-project/noir-contracts/contracts/docs_example_contract/src/types.nr b/yarn-project/noir-contracts/contracts/docs_example_contract/src/types.nr index 965909d4800..630d5c9b87e 100644 --- a/yarn-project/noir-contracts/contracts/docs_example_contract/src/types.nr +++ b/yarn-project/noir-contracts/contracts/docs_example_contract/src/types.nr @@ -1,3 +1,2 @@ mod card_note; mod leader; -mod transparent_note; diff --git a/yarn-project/noir-contracts/contracts/docs_example_contract/src/types/transparent_note.nr b/yarn-project/noir-contracts/contracts/docs_example_contract/src/types/transparent_note.nr deleted file mode 100644 index deb2bcdf6f1..00000000000 --- a/yarn-project/noir-contracts/contracts/docs_example_contract/src/types/transparent_note.nr +++ /dev/null @@ -1,139 +0,0 @@ -// docs:start:token_types_all -use dep::aztec::{ - note::{ - note_header::NoteHeader, - note_interface::NoteInterface, - utils::compute_siloed_note_hash, - }, - hash::{compute_secret_hash, pedersen_hash}, - context::PrivateContext, -}; - -global TRANSPARENT_NOTE_LEN: Field = 2; - -// Transparent note represents a note that is created in the clear (public execution), -// but can only be spent by those that know the preimage of the "secret_hash" -struct TransparentNote { - amount: Field, - secret_hash: Field, - // the secret is just here for ease of use and won't be (de)serialized - secret: Field, - // header is just here to satisfy the NoteInterface - header: NoteHeader, -} - -impl TransparentNote { - - // CONSTRUCTORS - - pub fn new(amount: Field, secret_hash: Field) -> Self { - TransparentNote { - amount: amount, - secret_hash: secret_hash, - secret: 0, - header: NoteHeader::empty(), - } - } - - // new oracle call primitive - // get me the secret corresponding to this hash - pub fn new_from_secret(amount: Field, secret: Field) -> Self { - TransparentNote { - amount: amount, - secret_hash: compute_secret_hash(secret), - secret: secret, - header: NoteHeader::empty(), - } - } - - - // STANDARD NOTE_INTERFACE FUNCTIONS - - pub fn serialize(self) -> [Field; TRANSPARENT_NOTE_LEN] { - [self.amount, self.secret_hash] - } - - pub fn deserialize(serialized_note: [Field; TRANSPARENT_NOTE_LEN]) -> Self { - TransparentNote { - amount: serialized_note[0], - secret_hash: serialized_note[1], - secret: 0, - header: NoteHeader::empty(), - } - } - - pub fn compute_note_hash(self) -> Field { - // TODO(#1205) Should use a non-zero generator index. - pedersen_hash([ - self.amount, - self.secret_hash, - ],0) - } - - pub fn compute_nullifier(self, _context: &mut PrivateContext) -> Field { - self.compute_nullifier_without_context() - } - - pub fn compute_nullifier_without_context(self) -> Field { - // TODO(#1386): should use `compute_note_hash_for_read_or_nullify` once public functions inject nonce! - let siloed_note_hash = compute_siloed_note_hash(TransparentNoteMethods, self); - // TODO(#1205) Should use a non-zero generator index. - pedersen_hash([self.secret, siloed_note_hash],0) - } - - pub fn set_header(&mut self, header: NoteHeader) { - self.header = header; - } - - - // CUSTOM FUNCTIONS FOR THIS NOTE TYPE - - pub fn knows_secret(self, secret: Field) { - let hash = compute_secret_hash(secret); - assert(self.secret_hash == hash); - } -} - -fn deserialize(serialized_note: [Field; TRANSPARENT_NOTE_LEN]) -> TransparentNote { - TransparentNote::deserialize(serialized_note) -} - -fn serialize(note: TransparentNote) -> [Field; TRANSPARENT_NOTE_LEN] { - note.serialize() -} - -fn compute_note_hash(note: TransparentNote) -> Field { - note.compute_note_hash() -} - -fn compute_nullifier(note: TransparentNote, context: &mut PrivateContext) -> Field { - note.compute_nullifier(context) -} - -fn compute_nullifier_without_context(note: TransparentNote) -> Field { - note.compute_nullifier_without_context() -} - -fn get_header(note: TransparentNote) -> NoteHeader { - note.header -} - -fn set_header(note: &mut TransparentNote, header: NoteHeader) { - note.set_header(header) -} - -fn broadcast(context: &mut PrivateContext, slot: Field, note: TransparentNote) { - assert(false, "TransparentNote does not support broadcast"); -} - -global TransparentNoteMethods = NoteInterface { - deserialize, - serialize, - compute_note_hash, - compute_nullifier, - compute_nullifier_without_context, - get_header, - set_header, - broadcast, -}; -// docs:end:token_types_all \ No newline at end of file From 4d197a657e72da2b5cbe0a4fdf6fc8f94ac8a10c Mon Sep 17 00:00:00 2001 From: Esau Date: Thu, 25 Jan 2024 15:20:26 +0100 Subject: [PATCH 3/7] revert From fd8cd35747de629a334cbcd71047b142226b68b4 Mon Sep 17 00:00:00 2001 From: Esau Date: Thu, 25 Jan 2024 15:25:28 +0100 Subject: [PATCH 4/7] real revert --- .../src/barretenberg/stdlib/primitives/bool/bool.test.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/stdlib/primitives/bool/bool.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/primitives/bool/bool.test.cpp index e356505b458..d9f87cd59ab 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/primitives/bool/bool.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/primitives/bool/bool.test.cpp @@ -148,7 +148,7 @@ TYPED_TEST(BoolTest, And) for (size_t i = 0; i < 32; ++i) { bool_ct a = witness_ct(&builder, (bool)(i % 1)); bool_ct b = witness_ct(&builder, (bool)(i % 2 == 1)); - a & b; + a& b; } bool result = builder.check_circuit(); @@ -163,17 +163,17 @@ TYPED_TEST(BoolTest, AndConstants) for (size_t i = 0; i < 32; ++i) { bool_ct a = witness_ct(&builder, (bool)(i % 2)); bool_ct b = witness_ct(&builder, (bool)(i % 3 == 1)); - a & b; + a& b; } for (size_t i = 0; i < 32; ++i) { if (i % 2 == 0) { bool_ct a = witness_ct(&builder, (bool)(i % 2)); bool_ct b(&builder, (bool)(i % 3 == 1)); - a & b; + a& b; } else { bool_ct a(&builder, (bool)(i % 2)); bool_ct b = witness_ct(&builder, (bool)(i % 3 == 1)); - a & b; + a& b; } } From 0ef95fa5c959c5a11866f3910748fc8f7574e620 Mon Sep 17 00:00:00 2001 From: Esau Date: Thu, 25 Jan 2024 15:47:47 +0100 Subject: [PATCH 5/7] yarn fmt --- .../src/client/client_execution_context.ts | 4 +- .../src/client/pick_notes.test.ts | 85 +++++++++------- .../acir-simulator/src/client/pick_notes.ts | 24 ++--- .../src/client/view_data_oracle.ts | 4 +- .../archiver/src/archiver/eth_log_handlers.ts | 2 +- .../end-to-end/src/e2e_note_getter.test.ts | 96 +++++++++++-------- yarn-project/foundation/.eslintrc.docs.cjs | 7 +- 7 files changed, 130 insertions(+), 92 deletions(-) diff --git a/yarn-project/acir-simulator/src/client/client_execution_context.ts b/yarn-project/acir-simulator/src/client/client_execution_context.ts index 6e50e00be21..78dcc68d139 100644 --- a/yarn-project/acir-simulator/src/client/client_execution_context.ts +++ b/yarn-project/acir-simulator/src/client/client_execution_context.ts @@ -211,7 +211,9 @@ export class ClientExecutionContext extends ViewDataOracle { const dbNotesFiltered = dbNotes.filter(n => !pendingNullifiers.has((n.siloedNullifier as Fr).value)); const notes = pickNotes([...dbNotesFiltered, ...pendingNotes], { - selects: selectBy.slice(0, numSelects).map((index, i) => ({ index, value: selectValues[i], comparator: selectComparators[i] })), + selects: selectBy + .slice(0, numSelects) + .map((index, i) => ({ index, value: selectValues[i], comparator: selectComparators[i] })), sorts: sortBy.map((index, i) => ({ index, order: sortOrder[i] })), limit, offset, diff --git a/yarn-project/acir-simulator/src/client/pick_notes.test.ts b/yarn-project/acir-simulator/src/client/pick_notes.test.ts index 08080aeaa72..ccd73a4a117 100644 --- a/yarn-project/acir-simulator/src/client/pick_notes.test.ts +++ b/yarn-project/acir-simulator/src/client/pick_notes.test.ts @@ -1,4 +1,4 @@ -import { Note, Comparator } from '@aztec/circuit-types'; +import { Comparator, Note } from '@aztec/circuit-types'; import { Fr } from '@aztec/foundation/fields'; import { SortOrder, pickNotes } from './pick_notes.js'; @@ -203,7 +203,10 @@ describe('getNotes', () => { createNote([6n, 5n, 8n]), ]; - const options = { selects: [{ index: 2, value: new Fr(8n), comparator: Comparator.EQ }], sorts: [{ index: 1, order: SortOrder.ASC }] }; + const options = { + selects: [{ index: 2, value: new Fr(8n), comparator: Comparator.EQ }], + sorts: [{ index: 1, order: SortOrder.ASC }], + }; const result = pickNotes(notes, options); expectNotes(result, [ [0n, 0n, 8n], @@ -223,19 +226,25 @@ describe('getNotes', () => { createNote([6n, 5n, 8n]), ]; - const options = { - selects: [{ - index: 2, - value: new Fr(7n), - comparator: Comparator.GTE, - }, { - index: 2, - value: new Fr(8n), - comparator: Comparator.LTE, - }], - sorts: [{ - index: 1, order: SortOrder.ASC - }], + const options = { + selects: [ + { + index: 2, + value: new Fr(7n), + comparator: Comparator.GTE, + }, + { + index: 2, + value: new Fr(8n), + comparator: Comparator.LTE, + }, + ], + sorts: [ + { + index: 1, + order: SortOrder.ASC, + }, + ], }; const result = pickNotes(notes, options); expectNotes(result, [ @@ -256,15 +265,20 @@ describe('getNotes', () => { createNote([6n, 5n, 6n]), ]; - const options1 = { - selects: [{ - index: 2, - value: new Fr(3n), - comparator: Comparator.GT, - }], - sorts: [{ - index: 1, order: SortOrder.ASC - }], + const options1 = { + selects: [ + { + index: 2, + value: new Fr(3n), + comparator: Comparator.GT, + }, + ], + sorts: [ + { + index: 1, + order: SortOrder.ASC, + }, + ], }; const result1 = pickNotes(notes, options1); @@ -275,15 +289,20 @@ describe('getNotes', () => { [6n, 5n, 6n], ]); - const options2 = { - selects: [{ - index: 2, - value: new Fr(4n), - comparator: Comparator.LT, - }], - sorts: [{ - index: 1, order: SortOrder.ASC - }], + const options2 = { + selects: [ + { + index: 2, + value: new Fr(4n), + comparator: Comparator.LT, + }, + ], + sorts: [ + { + index: 1, + order: SortOrder.ASC, + }, + ], }; const result2 = pickNotes(notes, options2); diff --git a/yarn-project/acir-simulator/src/client/pick_notes.ts b/yarn-project/acir-simulator/src/client/pick_notes.ts index e2dce9c4ad9..d054a226e39 100644 --- a/yarn-project/acir-simulator/src/client/pick_notes.ts +++ b/yarn-project/acir-simulator/src/client/pick_notes.ts @@ -79,18 +79,20 @@ interface ContainsNote { } const selectNotes = (noteDatas: T[], selects: Select[]): T[] => - noteDatas.filter(noteData => selects.every(({ index, value, comparator }) => { - const comparatorSelector = { - [Comparator.EQ]: () => noteData.note.items[index].equals(value), - [Comparator.NEQ]: () => !noteData.note.items[index].equals(value), - [Comparator.LT]: () => noteData.note.items[index].lt(value), - [Comparator.LTE]: () => noteData.note.items[index].lt(value) || noteData.note.items[index].equals(value), - [Comparator.GT]: () => !noteData.note.items[index].lt(value) && !noteData.note.items[index].equals(value), - [Comparator.GTE]: () => !noteData.note.items[index].lt(value), - } + noteDatas.filter(noteData => + selects.every(({ index, value, comparator }) => { + const comparatorSelector = { + [Comparator.EQ]: () => noteData.note.items[index].equals(value), + [Comparator.NEQ]: () => !noteData.note.items[index].equals(value), + [Comparator.LT]: () => noteData.note.items[index].lt(value), + [Comparator.LTE]: () => noteData.note.items[index].lt(value) || noteData.note.items[index].equals(value), + [Comparator.GT]: () => !noteData.note.items[index].lt(value) && !noteData.note.items[index].equals(value), + [Comparator.GTE]: () => !noteData.note.items[index].lt(value), + }; - return comparatorSelector[comparator](); - })); + return comparatorSelector[comparator](); + }), + ); const sortNotes = (a: Fr[], b: Fr[], sorts: Sort[], level = 0): number => { if (sorts[level] === undefined) { diff --git a/yarn-project/acir-simulator/src/client/view_data_oracle.ts b/yarn-project/acir-simulator/src/client/view_data_oracle.ts index 387fbc36b81..3d2e6d7d16e 100644 --- a/yarn-project/acir-simulator/src/client/view_data_oracle.ts +++ b/yarn-project/acir-simulator/src/client/view_data_oracle.ts @@ -218,7 +218,9 @@ export class ViewDataOracle extends TypedOracle { ): Promise { const dbNotes = await this.db.getNotes(this.contractAddress, storageSlot); return pickNotes(dbNotes, { - selects: selectBy.slice(0, numSelects).map((index, i) => ({ index, value: selectValues[i], comparator: selectComparators[i] })), + selects: selectBy + .slice(0, numSelects) + .map((index, i) => ({ index, value: selectValues[i], comparator: selectComparators[i] })), sorts: sortBy.map((index, i) => ({ index, order: sortOrder[i] })), limit, offset, diff --git a/yarn-project/archiver/src/archiver/eth_log_handlers.ts b/yarn-project/archiver/src/archiver/eth_log_handlers.ts index b57a8775c57..0d28ca2b4b2 100644 --- a/yarn-project/archiver/src/archiver/eth_log_handlers.ts +++ b/yarn-project/archiver/src/archiver/eth_log_handlers.ts @@ -107,7 +107,7 @@ async function getBlockFromCallData( if (functionName !== 'process') { throw new Error(`Unexpected method called ${functionName}`); } - const [headerHex, archiveRootHex, , bodyHex, ] = args! as [Hex, Hex, Hex, Hex, Hex]; + const [headerHex, archiveRootHex, , bodyHex] = args! as [Hex, Hex, Hex, Hex, Hex]; const blockBuffer = Buffer.concat([ Buffer.from(hexToBytes(headerHex)), Buffer.from(hexToBytes(archiveRootHex)), // L2Block.archive.root diff --git a/yarn-project/end-to-end/src/e2e_note_getter.test.ts b/yarn-project/end-to-end/src/e2e_note_getter.test.ts index 079fccb4ded..beda14e2ba5 100644 --- a/yarn-project/end-to-end/src/e2e_note_getter.test.ts +++ b/yarn-project/end-to-end/src/e2e_note_getter.test.ts @@ -1,11 +1,11 @@ -import { Fr, Wallet, Comparator } from '@aztec/aztec.js'; +import { Comparator, Fr, Wallet } from '@aztec/aztec.js'; import { DocsExampleContract } from '@aztec/noir-contracts'; import { setup } from './fixtures/utils.js'; interface CardNotePartial { - randomness: bigint - points: bigint + randomness: bigint; + points: bigint; } interface NoirOption { _is_some: boolean; @@ -34,33 +34,29 @@ describe('e2e_singleton', () => { // Singleton tests: it('a test that inserts note and checks if ', async () => { const numbers = [...Array(10).keys()]; - await Promise.all(numbers.map((number) => contract.methods.insert_note(number).send().wait())); + await Promise.all(numbers.map(number => contract.methods.insert_note(number).send().wait())); await contract.methods.insert_note(5).send().wait(); - const [ - returnEq, - returnNeq, - returnLt, - returnGt, - returnLte, - returnGte, - ] = await Promise.all([ + const [returnEq, returnNeq, returnLt, returnGt, returnLte, returnGte] = await Promise.all([ contract.methods.read_note(5, Comparator.EQ).view(), contract.methods.read_note(5, Comparator.NEQ).view(), contract.methods.read_note(5, Comparator.LT).view(), contract.methods.read_note(5, Comparator.GT).view(), contract.methods.read_note(5, Comparator.LTE).view(), contract.methods.read_note(5, Comparator.GTE).view(), - ]) - - expect(unwrapOptions(returnEq).map(({points, randomness}: any) => ({points, randomness}))) - .toStrictEqual([ - { points: 5n, randomness: 1n }, - { points: 5n, randomness: 1n }, - ]); - - expect(unwrapOptions(returnNeq).map(({points, randomness}: any) => ({points, randomness})).sort((a: any, b: any) => a.points > b.points ? 1 : -1)) - .toStrictEqual([ + ]); + + expect(unwrapOptions(returnEq).map(({ points, randomness }: any) => ({ points, randomness }))).toStrictEqual([ + { points: 5n, randomness: 1n }, + { points: 5n, randomness: 1n }, + ]); + + expect( + unwrapOptions(returnNeq) + .map(({ points, randomness }: any) => ({ points, randomness })) + .sort((a: any, b: any) => (a.points > b.points ? 1 : -1)), + ).toStrictEqual( + [ { points: 0n, randomness: 1n }, { points: 1n, randomness: 1n }, { points: 7n, randomness: 1n }, @@ -70,27 +66,42 @@ describe('e2e_singleton', () => { { points: 8n, randomness: 1n }, { points: 4n, randomness: 1n }, { points: 3n, randomness: 1n }, - ].sort((a: any, b: any) => a.points > b.points ? 1 : -1)); - - expect(unwrapOptions(returnLt).map(({points, randomness}: any) => ({points, randomness})).sort((a: any, b: any) => a.points > b.points ? 1 : -1)) - .toStrictEqual([ + ].sort((a: any, b: any) => (a.points > b.points ? 1 : -1)), + ); + + expect( + unwrapOptions(returnLt) + .map(({ points, randomness }: any) => ({ points, randomness })) + .sort((a: any, b: any) => (a.points > b.points ? 1 : -1)), + ).toStrictEqual( + [ { points: 0n, randomness: 1n }, { points: 1n, randomness: 1n }, { points: 2n, randomness: 1n }, { points: 4n, randomness: 1n }, { points: 3n, randomness: 1n }, - ].sort((a: any, b: any) => a.points > b.points ? 1 : -1)); - - expect(unwrapOptions(returnGt).map(({points, randomness}: any) => ({points, randomness})).sort((a: any, b: any) => a.points > b.points ? 1 : -1)) - .toStrictEqual([ + ].sort((a: any, b: any) => (a.points > b.points ? 1 : -1)), + ); + + expect( + unwrapOptions(returnGt) + .map(({ points, randomness }: any) => ({ points, randomness })) + .sort((a: any, b: any) => (a.points > b.points ? 1 : -1)), + ).toStrictEqual( + [ { points: 7n, randomness: 1n }, { points: 9n, randomness: 1n }, { points: 6n, randomness: 1n }, { points: 8n, randomness: 1n }, - ].sort((a: any, b: any) => a.points > b.points ? 1 : -1)); - - expect(unwrapOptions(returnLte).map(({points, randomness}: any) => ({points, randomness})).sort((a: any, b: any) => a.points > b.points ? 1 : -1)) - .toStrictEqual([ + ].sort((a: any, b: any) => (a.points > b.points ? 1 : -1)), + ); + + expect( + unwrapOptions(returnLte) + .map(({ points, randomness }: any) => ({ points, randomness })) + .sort((a: any, b: any) => (a.points > b.points ? 1 : -1)), + ).toStrictEqual( + [ { points: 5n, randomness: 1n }, { points: 5n, randomness: 1n }, { points: 0n, randomness: 1n }, @@ -98,17 +109,22 @@ describe('e2e_singleton', () => { { points: 2n, randomness: 1n }, { points: 4n, randomness: 1n }, { points: 3n, randomness: 1n }, - ].sort((a: any, b: any) => a.points > b.points ? 1 : -1)); - - expect(unwrapOptions(returnGte).map(({points, randomness}: any) => ({points, randomness})).sort((a: any, b: any) => a.points > b.points ? 1 : -1)) - .toStrictEqual([ + ].sort((a: any, b: any) => (a.points > b.points ? 1 : -1)), + ); + + expect( + unwrapOptions(returnGte) + .map(({ points, randomness }: any) => ({ points, randomness })) + .sort((a: any, b: any) => (a.points > b.points ? 1 : -1)), + ).toStrictEqual( + [ { points: 5n, randomness: 1n }, { points: 5n, randomness: 1n }, { points: 7n, randomness: 1n }, { points: 9n, randomness: 1n }, { points: 6n, randomness: 1n }, { points: 8n, randomness: 1n }, - ].sort((a: any, b: any) => a.points > b.points ? 1 : -1)); - + ].sort((a: any, b: any) => (a.points > b.points ? 1 : -1)), + ); }, 300_000); }); diff --git a/yarn-project/foundation/.eslintrc.docs.cjs b/yarn-project/foundation/.eslintrc.docs.cjs index cac8e4f9095..ef0ba45aede 100644 --- a/yarn-project/foundation/.eslintrc.docs.cjs +++ b/yarn-project/foundation/.eslintrc.docs.cjs @@ -40,10 +40,7 @@ const JSDOC_RULES_LEVEL = 'error'; module.exports = { ...base, plugins: [...base.plugins, 'jsdoc'], - overrides: [ - ...base.overrides, - { files: '*.test.ts', rules: { 'jsdoc/require-jsdoc': 'off' } }, - ], + overrides: [...base.overrides, { files: '*.test.ts', rules: { 'jsdoc/require-jsdoc': 'off' } }], rules: { ...base.rules, 'tsdoc/syntax': JSDOC_RULES_LEVEL, @@ -65,5 +62,5 @@ module.exports = { 'jsdoc/require-property-description': [JSDOC_RULES_LEVEL, { contexts }], 'jsdoc/require-property-name': [JSDOC_RULES_LEVEL, { contexts }], 'jsdoc/require-returns': 'off', - } + }, }; From 48543941ed4c12a4a75b7eff137d56db287187dd Mon Sep 17 00:00:00 2001 From: Esau Date: Thu, 25 Jan 2024 15:53:31 +0100 Subject: [PATCH 6/7] fix boxes --- boxes/token/src/contracts/src/main.nr | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/boxes/token/src/contracts/src/main.nr b/boxes/token/src/contracts/src/main.nr index da7b7cb74ca..673ee997663 100644 --- a/boxes/token/src/contracts/src/main.nr +++ b/boxes/token/src/contracts/src/main.nr @@ -34,7 +34,7 @@ contract Token { address::AztecAddress, } }; - + // docs:start:import_authwit use dep::authwit::{ auth::{ @@ -246,9 +246,9 @@ contract Token { fn redeem_shield(to: AztecAddress, amount: Field, secret: Field) { let pending_shields = storage.pending_shields; let secret_hash = compute_secret_hash(secret); - // Get 1 note (set_limit(1)) which has amount stored in field with index 0 (select(0, amount)) and secret_hash - // stored in field with index 1 (select(1, secret_hash)). - let options = NoteGetterOptions::new().select(0, amount).select(1, secret_hash).set_limit(1); + // Get 1 note (set_limit(1)) which has amount stored in field with index 0 (select(0, amount, Option::none())) and secret_hash + // stored in field with index 1 (select(1, secret_hash, Option::none())). + let options = NoteGetterOptions::new().select(0, amount, Option::none()).select(1, secret_hash, Option::none()).set_limit(1); let notes = pending_shields.get_notes(options); let note = notes[0].unwrap_unchecked(); // Remove the note from the pending shields set From a1ee98aacc52a204c65b47a2669175aca2ae697f Mon Sep 17 00:00:00 2001 From: Esau Date: Thu, 25 Jan 2024 16:08:41 +0100 Subject: [PATCH 7/7] yarn fmt --- yarn-project/end-to-end/src/e2e_note_getter.test.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/yarn-project/end-to-end/src/e2e_note_getter.test.ts b/yarn-project/end-to-end/src/e2e_note_getter.test.ts index beda14e2ba5..26e11b55aa9 100644 --- a/yarn-project/end-to-end/src/e2e_note_getter.test.ts +++ b/yarn-project/end-to-end/src/e2e_note_getter.test.ts @@ -3,10 +3,6 @@ import { DocsExampleContract } from '@aztec/noir-contracts'; import { setup } from './fixtures/utils.js'; -interface CardNotePartial { - randomness: bigint; - points: bigint; -} interface NoirOption { _is_some: boolean; _value: T;