From d90acf483a7673b6c4d73d1b2d103c5d7b74ce83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Venturo?= Date: Fri, 19 Jan 2024 13:54:40 +0000 Subject: [PATCH 01/17] Add status to NoteFilter, basic KV db support --- .../circuit-types/src/notes/note_filter.ts | 2 ++ .../pxe/src/database/kv_pxe_database.ts | 34 ++++++++++++------- .../src/database/pxe_database_test_suite.ts | 25 ++++++++++++-- 3 files changed, 47 insertions(+), 14 deletions(-) diff --git a/yarn-project/circuit-types/src/notes/note_filter.ts b/yarn-project/circuit-types/src/notes/note_filter.ts index 515dabb7c35..c682ca92b52 100644 --- a/yarn-project/circuit-types/src/notes/note_filter.ts +++ b/yarn-project/circuit-types/src/notes/note_filter.ts @@ -15,4 +15,6 @@ export type NoteFilter = { storageSlot?: Fr; /** The owner of the note (whose public key was used to encrypt the note). */ owner?: AztecAddress; + /** The status of the note. Defaults to 'active'. */ + status?: 'active' | 'deleted'; }; diff --git a/yarn-project/pxe/src/database/kv_pxe_database.ts b/yarn-project/pxe/src/database/kv_pxe_database.ts index a6216e9be06..e1b83358068 100644 --- a/yarn-project/pxe/src/database/kv_pxe_database.ts +++ b/yarn-project/pxe/src/database/kv_pxe_database.ts @@ -170,18 +170,28 @@ export class KVPxeDatabase implements PxeDatabase { ? (await this.getCompleteAddress(filter.owner))?.publicKey : undefined; - const initialNoteIds = publicKey - ? this.#notesByOwner.getValues(publicKey.toString()) - : filter.txHash - ? this.#notesByTxHash.getValues(filter.txHash.toString()) - : filter.contractAddress - ? this.#notesByContract.getValues(filter.contractAddress.toString()) - : filter.storageSlot - ? this.#notesByStorageSlot.getValues(filter.storageSlot.toString()) - : undefined; - - if (!initialNoteIds) { - return Array.from(this.#getAllNonNullifiedNotes()); + let initialNoteIds: IterableIterator | undefined; + + if ((filter.status ?? 'active') == 'active') { + // The #notesByX stores only track active notes. + initialNoteIds = publicKey + ? this.#notesByOwner.getValues(publicKey.toString()) + : filter.txHash + ? this.#notesByTxHash.getValues(filter.txHash.toString()) + : filter.contractAddress + ? this.#notesByContract.getValues(filter.contractAddress.toString()) + : filter.storageSlot + ? this.#notesByStorageSlot.getValues(filter.storageSlot.toString()) + : undefined; + + if (!initialNoteIds) { + return Array.from(this.#getAllNonNullifiedNotes()); + } + } else { + // TODO: this will cause a scan of all nullified notes in order to apply the filters manually. We could improve + // performance at the cost of storage by duplicating the #notesBy stores so that we also track nullified notes + // that way. + initialNoteIds = this.#nullifiedNotes.keys(); } const result: NoteDao[] = []; diff --git a/yarn-project/pxe/src/database/pxe_database_test_suite.ts b/yarn-project/pxe/src/database/pxe_database_test_suite.ts index 5464ef98dde..57622468219 100644 --- a/yarn-project/pxe/src/database/pxe_database_test_suite.ts +++ b/yarn-project/pxe/src/database/pxe_database_test_suite.ts @@ -91,12 +91,16 @@ export function describePxeDatabase(getDatabase: () => PxeDatabase) { [() => ({ owner: owners[0].address }), () => notes.filter(note => note.publicKey.equals(owners[0].publicKey))], [ - () => ({ contractAddress: contractAddresses[0], storageSlot: storageSlots[0] }), + () => ({ contractAddress: contractAddresses[0], storageSlot: storageSlots[0], status: 'active' }), () => notes.filter( note => note.contractAddress.equals(contractAddresses[0]) && note.storageSlot.equals(storageSlots[0]), ), ], + [ + () => ({ contractAddress: contractAddresses[0], storageSlot: storageSlots[0], status: 'deleted' }), + () => [], + ], [() => ({ contractAddress: contractAddresses[0], storageSlot: storageSlots[1] }), () => []], ]; @@ -132,7 +136,7 @@ export function describePxeDatabase(getDatabase: () => PxeDatabase) { await expect(database.getNotes(getFilter())).resolves.toEqual(getExpected()); }); - it('removes nullified notes', async () => { + it('skips nullified notes by default', async () => { const notesToNullify = notes.filter(note => note.publicKey.equals(owners[0].publicKey)); const nullifiers = notesToNullify.map(note => note.siloedNullifier); @@ -148,6 +152,23 @@ export function describePxeDatabase(getDatabase: () => PxeDatabase) { ).resolves.toEqual([]); await expect(database.getNotes({})).resolves.toEqual(notes.filter(note => !notesToNullify.includes(note))); }); + + it('retrieves nullified notes', async () => { + const notesToNullify = notes.filter(note => note.publicKey.equals(owners[0].publicKey)); + const nullifiers = notesToNullify.map(note => note.siloedNullifier); + + await database.addNotes(notes); + + await expect(database.removeNullifiedNotes(nullifiers, notesToNullify[0].publicKey)).resolves.toEqual( + notesToNullify, + ); + await expect( + database.getNotes({ + owner: owners[0].address, + status: 'deleted' + }), + ).resolves.toEqual(notesToNullify); + }); }); describe('block header', () => { From 185f525c1cf3f07f121981ba3cf9dff9fdce2f1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Venturo?= Date: Fri, 19 Jan 2024 19:13:36 +0000 Subject: [PATCH 02/17] Add filtering test cases --- .../circuit-types/src/notes/note_filter.ts | 2 +- .../src/database/pxe_database_test_suite.ts | 47 +++++++++++-------- 2 files changed, 28 insertions(+), 21 deletions(-) diff --git a/yarn-project/circuit-types/src/notes/note_filter.ts b/yarn-project/circuit-types/src/notes/note_filter.ts index c682ca92b52..47aa9d807c0 100644 --- a/yarn-project/circuit-types/src/notes/note_filter.ts +++ b/yarn-project/circuit-types/src/notes/note_filter.ts @@ -16,5 +16,5 @@ export type NoteFilter = { /** The owner of the note (whose public key was used to encrypt the note). */ owner?: AztecAddress; /** The status of the note. Defaults to 'active'. */ - status?: 'active' | 'deleted'; + status?: 'active' | 'nullified'; }; diff --git a/yarn-project/pxe/src/database/pxe_database_test_suite.ts b/yarn-project/pxe/src/database/pxe_database_test_suite.ts index 57622468219..351531c84a1 100644 --- a/yarn-project/pxe/src/database/pxe_database_test_suite.ts +++ b/yarn-project/pxe/src/database/pxe_database_test_suite.ts @@ -91,16 +91,12 @@ export function describePxeDatabase(getDatabase: () => PxeDatabase) { [() => ({ owner: owners[0].address }), () => notes.filter(note => note.publicKey.equals(owners[0].publicKey))], [ - () => ({ contractAddress: contractAddresses[0], storageSlot: storageSlots[0], status: 'active' }), + () => ({ contractAddress: contractAddresses[0], storageSlot: storageSlots[0] }), () => notes.filter( note => note.contractAddress.equals(contractAddresses[0]) && note.storageSlot.equals(storageSlots[0]), ), ], - [ - () => ({ contractAddress: contractAddresses[0], storageSlot: storageSlots[0], status: 'deleted' }), - () => [], - ], [() => ({ contractAddress: contractAddresses[0], storageSlot: storageSlots[1] }), () => []], ]; @@ -136,36 +132,47 @@ export function describePxeDatabase(getDatabase: () => PxeDatabase) { await expect(database.getNotes(getFilter())).resolves.toEqual(getExpected()); }); - it('skips nullified notes by default', async () => { - const notesToNullify = notes.filter(note => note.publicKey.equals(owners[0].publicKey)); - const nullifiers = notesToNullify.map(note => note.siloedNullifier); + it.each(filteringTests)('retrieves nullified notes', async (getFilter, getExpected) => { + await database.addNotes(notes); + + // Nullify all notes and use the same filter as other test cases + for (const owner of owners) { + const notesToNullify = notes.filter(note => note.publicKey.equals(owner.publicKey)); + const nullifiers = notesToNullify.map(note => note.siloedNullifier); + await expect(database.removeNullifiedNotes(nullifiers, owner.publicKey)).resolves.toEqual(notesToNullify); + } + + await expect(database.getNotes({ ...getFilter(), status: 'nullified' })).resolves.toEqual(getExpected()); + }); + it('skips nullified notes by default or when requesting active', async () => { await database.addNotes(notes); + const notesToNullify = notes.filter(note => note.publicKey.equals(owners[0].publicKey)); + const nullifiers = notesToNullify.map(note => note.siloedNullifier); await expect(database.removeNullifiedNotes(nullifiers, notesToNullify[0].publicKey)).resolves.toEqual( notesToNullify, ); - await expect( - database.getNotes({ - owner: owners[0].address, - }), - ).resolves.toEqual([]); - await expect(database.getNotes({})).resolves.toEqual(notes.filter(note => !notesToNullify.includes(note))); - }); - it('retrieves nullified notes', async () => { - const notesToNullify = notes.filter(note => note.publicKey.equals(owners[0].publicKey)); - const nullifiers = notesToNullify.map(note => note.siloedNullifier); + const actualNotesWithDefault = await database.getNotes({}); + const actualNotesWithActive = await database.getNotes({ status: 'active' }); + expect(actualNotesWithDefault).toEqual(actualNotesWithActive); + expect(actualNotesWithActive).toEqual(notes.filter(note => !notesToNullify.includes(note))); + }); + + it('skips active notes when requesting nullified', async () => { await database.addNotes(notes); + const notesToNullify = notes.filter(note => note.publicKey.equals(owners[0].publicKey)); + const nullifiers = notesToNullify.map(note => note.siloedNullifier); await expect(database.removeNullifiedNotes(nullifiers, notesToNullify[0].publicKey)).resolves.toEqual( notesToNullify, ); + await expect( database.getNotes({ - owner: owners[0].address, - status: 'deleted' + status: 'nullified', }), ).resolves.toEqual(notesToNullify); }); From 12e71d2cc8f33e8bacd5d8d636d75b3130cc64d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Venturo?= Date: Wed, 24 Jan 2024 23:01:21 +0000 Subject: [PATCH 03/17] Add filter option, create tests --- .../acir-simulator/src/acvm/oracle/oracle.ts | 2 + .../src/acvm/oracle/typed_oracle.ts | 1 + .../src/client/client_execution_context.ts | 4 +- .../acir-simulator/src/client/db_oracle.ts | 3 +- .../src/client/view_data_oracle.ts | 4 +- .../aztec-nr/aztec/src/note/note_getter.nr | 3 + .../aztec/src/note/note_getter_options.nr | 7 +- .../aztec/src/note/note_viewer_options.nr | 2 + .../aztec-nr/aztec/src/oracle/notes.nr | 5 + .../circuit-types/src/notes/note_filter.ts | 2 +- .../end-to-end/src/e2e_get_notes.test.ts | 86 ++++++++++++++++ .../contracts/test_contract/Nargo.toml | 1 + .../contracts/test_contract/src/main.nr | 97 ++++++++++++++++++- .../pxe/src/database/kv_pxe_database.ts | 38 +++++--- .../src/database/pxe_database_test_suite.ts | 18 ++-- .../pxe/src/simulator_oracle/index.ts | 8 +- 16 files changed, 248 insertions(+), 33 deletions(-) create mode 100644 yarn-project/end-to-end/src/e2e_get_notes.test.ts diff --git a/yarn-project/acir-simulator/src/acvm/oracle/oracle.ts b/yarn-project/acir-simulator/src/acvm/oracle/oracle.ts index 49449ffcbcb..e4d23cdfc89 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 { sortOrder: ACVMField[], [limit]: ACVMField[], [offset]: ACVMField[], + [includeNullified]: ACVMField[], [returnSize]: ACVMField[], ): Promise { const noteDatas = await this.typedOracle.getNotes( @@ -178,6 +179,7 @@ export class Oracle { sortOrder.map(s => +s), +limit, +offset, + !!+includeNullified, ); const noteLength = noteDatas?.[0]?.note.items.length ?? 0; 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 995a285b7b1..d8d1d5b5255 100644 --- a/yarn-project/acir-simulator/src/acvm/oracle/typed_oracle.ts +++ b/yarn-project/acir-simulator/src/acvm/oracle/typed_oracle.ts @@ -137,6 +137,7 @@ export abstract class TypedOracle { _sortOrder: number[], _limit: number, _offset: number, + _nullified: boolean ): Promise { throw new Error('Not available.'); } 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..26b356c1449 100644 --- a/yarn-project/acir-simulator/src/client/client_execution_context.ts +++ b/yarn-project/acir-simulator/src/client/client_execution_context.ts @@ -189,6 +189,7 @@ export class ClientExecutionContext extends ViewDataOracle { * @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. * @param offset - The starting index for pagination. + * @param includeNullified - Whether to include nullified notes. * @returns Array of note data. */ public async getNotes( @@ -200,12 +201,13 @@ export class ClientExecutionContext extends ViewDataOracle { sortOrder: number[], limit: number, offset: number, + includeNullified: boolean, ): Promise { // Nullified pending notes are already removed from the list. const pendingNotes = this.noteCache.getNotes(this.contractAddress, storageSlot); const pendingNullifiers = this.noteCache.getNullifiers(this.contractAddress); - const dbNotes = await this.db.getNotes(this.contractAddress, storageSlot); + const dbNotes = await this.db.getNotes(this.contractAddress, storageSlot, includeNullified); const dbNotesFiltered = dbNotes.filter(n => !pendingNullifiers.has((n.siloedNullifier as Fr).value)); const notes = pickNotes([...dbNotesFiltered, ...pendingNotes], { diff --git a/yarn-project/acir-simulator/src/client/db_oracle.ts b/yarn-project/acir-simulator/src/client/db_oracle.ts index eb4f59fae84..622ca48a8a9 100644 --- a/yarn-project/acir-simulator/src/client/db_oracle.ts +++ b/yarn-project/acir-simulator/src/client/db_oracle.ts @@ -61,9 +61,10 @@ export interface DBOracle extends CommitmentsDB { * * @param contractAddress - The AztecAddress instance representing the contract address. * @param storageSlot - The Fr instance representing the storage slot of the notes. + * @param includeNullified - Whether to include nullified notes. Defaults to false. * @returns A Promise that resolves to an array of note data. */ - getNotes(contractAddress: AztecAddress, storageSlot: Fr): Promise; + getNotes(contractAddress: AztecAddress, storageSlot: Fr, includeNullified?: boolean): Promise; /** * Retrieve the artifact information of a specific function within a contract. 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 b029833f2ea..9c690864424 100644 --- a/yarn-project/acir-simulator/src/client/view_data_oracle.ts +++ b/yarn-project/acir-simulator/src/client/view_data_oracle.ts @@ -202,6 +202,7 @@ export class ViewDataOracle extends TypedOracle { * @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. * @param offset - The starting index for pagination. + * @param includeNullified - Whether to include nullified notes. * @returns Array of note data. */ public async getNotes( @@ -213,8 +214,9 @@ export class ViewDataOracle extends TypedOracle { sortOrder: number[], limit: number, offset: number, + includeNullified: boolean, ): Promise { - const dbNotes = await this.db.getNotes(this.contractAddress, storageSlot); + const dbNotes = await this.db.getNotes(this.contractAddress, storageSlot, includeNullified); return pickNotes(dbNotes, { selects: selectBy.slice(0, numSelects).map((index, i) => ({ index, value: selectValues[i] })), sorts: sortBy.map((index, i) => ({ index, order: sortOrder[i] })), 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..2adb390dc7a 100644 --- a/yarn-project/aztec-nr/aztec/src/note/note_getter.nr +++ b/yarn-project/aztec-nr/aztec/src/note/note_getter.nr @@ -117,6 +117,7 @@ unconstrained fn get_note_internal(storage_slot: Field, note_interface: [], 1, // limit 0, // offset + false, // includeNullified - TODO: add a way for to retrieve nullified notes? placeholder_note, placeholder_fields )[0].unwrap() // Notice: we don't allow dummies to be returned from get_note (singular). @@ -140,6 +141,7 @@ unconstrained fn get_notes_internal( sort_order, options.limit, options.offset, + options.includeNullified, placeholder_opt_notes, placeholder_fields ); @@ -167,6 +169,7 @@ unconstrained pub fn view_notes( sort_order, options.limit, options.offset, + options.includeNullified, placeholder_opt_notes, placeholder_fields ) 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..5be1e483771 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 @@ -49,6 +49,7 @@ struct NoteGetterOptions { offset: u32, filter: fn ([Option; MAX_READ_REQUESTS_PER_CALL], FILTER_ARGS) -> [Option; MAX_READ_REQUESTS_PER_CALL], filter_args: FILTER_ARGS, + includeNullified: bool, } // docs:end:NoteGetterOptions @@ -66,6 +67,7 @@ impl NoteGetterOptions { offset: 0, filter: return_all_notes, filter_args: 0, + includeNullified: false, } } @@ -82,6 +84,7 @@ impl NoteGetterOptions { offset: 0, filter, filter_args, + includeNullified: false, } } @@ -99,14 +102,14 @@ impl NoteGetterOptions { *self } - // This method lets you set a limit for the maximum number of notes to be retrieved in a single query result. + // This method lets you set a limit for the maximum number of notes to be retrieved in a single query result. pub fn set_limit(&mut self, limit: u32) -> Self { assert(limit <= MAX_READ_REQUESTS_PER_CALL as u32); self.limit = limit; *self } - // This method sets the offset value, which determines where to start retrieving notes in the query results. + // This method sets the offset value, which determines where to start retrieving notes in the query results. pub fn set_offset(&mut self, offset: u32) -> Self { self.offset = offset; *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..671fa262e22 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 @@ -9,6 +9,7 @@ struct NoteViewerOptions { sorts: BoundedVec, N>, limit: u32, offset: u32, + includeNullified: bool, } // docs:end:NoteViewerOptions @@ -19,6 +20,7 @@ impl NoteViewerOptions { sorts: BoundedVec::new(Option::none()), limit: MAX_NOTES_PER_PAGE as u32, offset: 0, + includeNullified: false, } } diff --git a/yarn-project/aztec-nr/aztec/src/oracle/notes.nr b/yarn-project/aztec-nr/aztec/src/oracle/notes.nr index 88664e64dc8..667a317bf3e 100644 --- a/yarn-project/aztec-nr/aztec/src/oracle/notes.nr +++ b/yarn-project/aztec-nr/aztec/src/oracle/notes.nr @@ -31,6 +31,7 @@ fn get_notes_oracle( _sort_order: [u2; N], _limit: u32, _offset: u32, + _includeNullified: bool, _return_size: u32, _placeholder_fields: [Field; S] ) -> [Field; S] {} @@ -44,6 +45,7 @@ unconstrained fn get_notes_oracle_wrapper( sort_order: [u2; N], limit: u32, offset: u32, + includeNullified: bool, mut placeholder_fields: [Field; S] ) -> [Field; S] { let return_size = placeholder_fields.len() as u32; @@ -56,6 +58,7 @@ unconstrained fn get_notes_oracle_wrapper( sort_order, limit, offset, + includeNullified, return_size, placeholder_fields ) @@ -71,6 +74,7 @@ unconstrained pub fn get_notes( sort_order: [u2; M], limit: u32, offset: u32, + includeNullified: bool, mut placeholder_opt_notes: [Option; S], // TODO: Remove it and use `limit` to initialize the note array. placeholder_fields: [Field; NS] // TODO: Remove it and use `limit` to initialize the note array. ) -> [Option; S] { @@ -83,6 +87,7 @@ unconstrained pub fn get_notes( sort_order, limit, offset, + includeNullified, placeholder_fields ); let num_notes = fields[0] as u32; diff --git a/yarn-project/circuit-types/src/notes/note_filter.ts b/yarn-project/circuit-types/src/notes/note_filter.ts index 47aa9d807c0..265e5650795 100644 --- a/yarn-project/circuit-types/src/notes/note_filter.ts +++ b/yarn-project/circuit-types/src/notes/note_filter.ts @@ -16,5 +16,5 @@ export type NoteFilter = { /** The owner of the note (whose public key was used to encrypt the note). */ owner?: AztecAddress; /** The status of the note. Defaults to 'active'. */ - status?: 'active' | 'nullified'; + status?: 'active' | 'active_or_nullified'; // TODO: add 'nullified' }; diff --git a/yarn-project/end-to-end/src/e2e_get_notes.test.ts b/yarn-project/end-to-end/src/e2e_get_notes.test.ts new file mode 100644 index 00000000000..984532c0fa7 --- /dev/null +++ b/yarn-project/end-to-end/src/e2e_get_notes.test.ts @@ -0,0 +1,86 @@ +import { AztecAddress, Wallet, toBigInt } from '@aztec/aztec.js'; +import { TestContract } from '@aztec/noir-contracts'; + +import { setup } from './fixtures/utils.js'; + +describe('e2e_get_notes', () => { + // export DEBUG=aztec:e2e_get_notes + let wallet: Wallet; + let teardown: () => Promise; + + let contract: TestContract; + let owner: AztecAddress; + + beforeAll(async () => { + ({ teardown, wallet } = await setup()); + + contract = await TestContract.deploy(wallet).send().deployed(); + owner = wallet.getCompleteAddress().address; + }, 100_000); + + afterAll(() => teardown()); + + const VALUE = 5; + + // To prevent tests from interacting with one another, we'll have each use a different storage slot. + let storageSlot: number = 2; + + beforeEach(() => { + storageSlot += 1; + }); + + async function assertNoteIsReturned(storageSlot: number, expectedValue: number, includeNullified: boolean) { + const viewNotesResult = await contract.methods.call_view_notes(storageSlot, includeNullified).view(); + + // call_get_notes exposes the return value via an event since we cannot use view() with it. + const tx = contract.methods.call_get_notes(storageSlot, includeNullified).send(); + await tx.wait(); + + const logs = (await tx.getUnencryptedLogs()).logs; + expect(logs.length).toBe(1); + + const getNotesResult = toBigInt(logs[0].log.data); + + expect(viewNotesResult).toEqual(getNotesResult); + expect(viewNotesResult).toEqual(BigInt(expectedValue)); + } + + async function assertNoReturnValue(storageSlot: number, includeNullified: boolean) { + await expect(contract.methods.call_view_notes(storageSlot, includeNullified).view()).rejects.toThrow('is_some'); + await expect(contract.methods.call_get_notes(storageSlot, includeNullified).send().wait()).rejects.toThrow( + 'is_some', + ); + } + + describe('active note only', () => { + const includeNullified = false; + + it('returns active notes', async () => { + await contract.methods.call_create_note(VALUE, owner, storageSlot).send().wait(); + await assertNoteIsReturned(storageSlot, VALUE, includeNullified); + }); + + it('does not return nullified notes', async () => { + await contract.methods.call_create_note(VALUE, owner, storageSlot).send().wait(); + await contract.methods.call_destroy_note(storageSlot).send().wait(); + + await assertNoReturnValue(storageSlot, includeNullified); + }); + }); + + describe('active and nullified notes', () => { + const includeNullified = true; + + it('returns active notes', async () => { + await contract.methods.call_create_note(VALUE, owner, storageSlot).send().wait(); + await assertNoteIsReturned(storageSlot, VALUE, includeNullified); + }); + + it('returns nullified notes', async () => { + await contract.methods.call_create_note(VALUE, owner, storageSlot).send().wait(); + await contract.methods.call_destroy_note(storageSlot).send().wait(); + + await assertNoteIsReturned(storageSlot, VALUE, includeNullified); + }, 30_000); + }); +}); diff --git a/yarn-project/noir-contracts/contracts/test_contract/Nargo.toml b/yarn-project/noir-contracts/contracts/test_contract/Nargo.toml index 80a59556c0a..7ab24aa181e 100644 --- a/yarn-project/noir-contracts/contracts/test_contract/Nargo.toml +++ b/yarn-project/noir-contracts/contracts/test_contract/Nargo.toml @@ -7,4 +7,5 @@ type = "contract" [dependencies] aztec = { path = "../../../aztec-nr/aztec" } field_note = { path = "../../../aztec-nr/field-note" } +value_note = { path = "../../../aztec-nr/value-note" } token_portal_content_hash_lib = { path = "../token_portal_content_hash_lib" } diff --git a/yarn-project/noir-contracts/contracts/test_contract/src/main.nr b/yarn-project/noir-contracts/contracts/test_contract/src/main.nr index aac608c1bd8..40dc64fd811 100644 --- a/yarn-project/noir-contracts/contracts/test_contract/src/main.nr +++ b/yarn-project/noir-contracts/contracts/test_contract/src/main.nr @@ -23,6 +23,10 @@ contract Test { note::{ note_header::NoteHeader, utils as note_utils, + lifecycle::{create_note, destroy_note}, + note_getter::{get_notes, view_notes}, + note_getter_options::NoteGetterOptions, + note_viewer_options::NoteViewerOptions, }, oracle::{ get_public_key::get_public_key as get_public_key_oracle, @@ -35,6 +39,7 @@ contract Test { }; use dep::token_portal_content_hash_lib::{get_mint_private_content_hash, get_mint_public_content_hash}; use dep::field_note::field_note::{FieldNote, FieldNoteMethods, FIELD_NOTE_LEN}; + use dep::value_note::value_note::{ValueNote, ValueNoteMethods, VALUE_NOTE_LEN}; #[event] struct ExampleEvent { @@ -83,6 +88,85 @@ contract Test { context.this_address() } + #[aztec(private)] + fn call_create_note( + value: Field, + owner: AztecAddress, + storage_slot: Field + ) { + assert(storage_slot != 1, "storage slot 1 is reserved for example_constant"); + + let mut note = ValueNote::new(value, owner); + create_note( + &mut context, + storage_slot, + &mut note, + ValueNoteMethods, + true, + ); + } + + #[aztec(private)] + fn call_get_notes( + storage_slot: Field, + includeNullified: bool, + ) { + assert(storage_slot != 1, "storage slot 1 is reserved for example_constant"); + + let mut options = NoteGetterOptions::new(); + options.includeNullified = includeNullified; + let opt_notes = get_notes( + &mut context, + storage_slot, + ValueNoteMethods, + options, + ); + + // We can't get the return value of a private function from the outside world in an end to end test, so we + // expose it via an unecrypted log instead. + let value = opt_notes[0].unwrap().value; + emit_unencrypted_log_from_private(&mut context, value); + } + + unconstrained + fn call_view_notes( + storage_slot: Field, + includeNullified: bool, + ) -> pub Field { + assert(storage_slot != 1, "storage slot 1 is reserved for example_constant"); + + let mut options = NoteViewerOptions::new(); + options.includeNullified = includeNullified; + let opt_notes = view_notes( + storage_slot, + ValueNoteMethods, + options, + ); + + opt_notes[0].unwrap().value + } + + #[aztec(private)] + fn call_destroy_note(storage_slot: Field) { + assert(storage_slot != 1, "storage slot 1 is reserved for example_constant"); + + let options = NoteGetterOptions::new(); + let opt_notes = get_notes( + &mut context, + storage_slot, + ValueNoteMethods, + options, + ); + + let note = opt_notes[0].unwrap(); + + destroy_note( + &mut context, + note, + ValueNoteMethods, + ); + } + // Test codegen for Aztec.nr interfaces // See yarn-project/acir-simulator/src/client/private_execution.test.ts 'nested calls through autogenerated interface' // Note; this function is deliberately NOT annotated with #[aztec(private)] due to its use in tests @@ -238,10 +322,15 @@ contract Test { contract_address: AztecAddress, nonce: Field, storage_slot: Field, - serialized_note: [Field; FIELD_NOTE_LEN] + serialized_note: [Field; VALUE_NOTE_LEN] // must fit either a FieldNote or a ValueNote ) -> pub [Field; 4] { - assert(storage_slot == 1); - let note_header = NoteHeader::new(contract_address, nonce, storage_slot); - note_utils::compute_note_hash_and_nullifier(FieldNoteMethods, note_header, serialized_note) + if (storage_slot == 1) { + let note_header = NoteHeader::new(contract_address, nonce, storage_slot); + note_utils::compute_note_hash_and_nullifier(FieldNoteMethods, note_header, serialized_note) + } else { + // For ValueNotes created via write_value_to_storage + let note_header = NoteHeader::new(contract_address, nonce, storage_slot); + note_utils::compute_note_hash_and_nullifier(ValueNoteMethods, note_header, serialized_note) + } } } diff --git a/yarn-project/pxe/src/database/kv_pxe_database.ts b/yarn-project/pxe/src/database/kv_pxe_database.ts index e1b83358068..dd55301d3d4 100644 --- a/yarn-project/pxe/src/database/kv_pxe_database.ts +++ b/yarn-project/pxe/src/database/kv_pxe_database.ts @@ -165,16 +165,29 @@ export class KVPxeDatabase implements PxeDatabase { } } + *#getAllNonNullifiedNoteIndices(): IterableIterator { + for (const [index, _] of this.#notes.entries()) { + if (this.#nullifiedNotes.has(index)) { + continue; + } + + yield index; + } + } + async getNotes(filter: NoteFilter): Promise { const publicKey: PublicKey | undefined = filter.owner ? (await this.getCompleteAddress(filter.owner))?.publicKey : undefined; - let initialNoteIds: IterableIterator | undefined; + // TODO: refactor how we create the array of candidate note ids once the kv_pxe_database refactor from #3927 is + // merged. + let candidateNoteIds: Array = []; + + filter.status = filter.status ?? 'active'; - if ((filter.status ?? 'active') == 'active') { - // The #notesByX stores only track active notes. - initialNoteIds = publicKey + if (filter.status == 'active' || filter.status == 'active_or_nullified') { + const candidateActiveNoteIds = publicKey ? this.#notesByOwner.getValues(publicKey.toString()) : filter.txHash ? this.#notesByTxHash.getValues(filter.txHash.toString()) @@ -182,20 +195,17 @@ export class KVPxeDatabase implements PxeDatabase { ? this.#notesByContract.getValues(filter.contractAddress.toString()) : filter.storageSlot ? this.#notesByStorageSlot.getValues(filter.storageSlot.toString()) - : undefined; + : this.#getAllNonNullifiedNoteIndices(); - if (!initialNoteIds) { - return Array.from(this.#getAllNonNullifiedNotes()); - } - } else { - // TODO: this will cause a scan of all nullified notes in order to apply the filters manually. We could improve - // performance at the cost of storage by duplicating the #notesBy stores so that we also track nullified notes - // that way. - initialNoteIds = this.#nullifiedNotes.keys(); + candidateNoteIds = candidateNoteIds.concat([...candidateActiveNoteIds]); + } + + if (filter.status == 'active_or_nullified') { + candidateNoteIds = candidateNoteIds.concat([...this.#nullifiedNotes.keys()]); } const result: NoteDao[] = []; - for (const noteId of initialNoteIds) { + for (const noteId of candidateNoteIds) { const serializedNote = this.#notes.at(noteId); if (!serializedNote) { continue; diff --git a/yarn-project/pxe/src/database/pxe_database_test_suite.ts b/yarn-project/pxe/src/database/pxe_database_test_suite.ts index 351531c84a1..1561b1bf1ca 100644 --- a/yarn-project/pxe/src/database/pxe_database_test_suite.ts +++ b/yarn-project/pxe/src/database/pxe_database_test_suite.ts @@ -142,7 +142,9 @@ export function describePxeDatabase(getDatabase: () => PxeDatabase) { await expect(database.removeNullifiedNotes(nullifiers, owner.publicKey)).resolves.toEqual(notesToNullify); } - await expect(database.getNotes({ ...getFilter(), status: 'nullified' })).resolves.toEqual(getExpected()); + await expect(database.getNotes({ ...getFilter(), status: 'active_or_nullified' })).resolves.toEqual( + getExpected(), + ); }); it('skips nullified notes by default or when requesting active', async () => { @@ -161,7 +163,7 @@ export function describePxeDatabase(getDatabase: () => PxeDatabase) { expect(actualNotesWithActive).toEqual(notes.filter(note => !notesToNullify.includes(note))); }); - it('skips active notes when requesting nullified', async () => { + it('returns active and nullified notes when requesting either', async () => { await database.addNotes(notes); const notesToNullify = notes.filter(note => note.publicKey.equals(owners[0].publicKey)); @@ -170,11 +172,13 @@ export function describePxeDatabase(getDatabase: () => PxeDatabase) { notesToNullify, ); - await expect( - database.getNotes({ - status: 'nullified', - }), - ).resolves.toEqual(notesToNullify); + const result = await database.getNotes({ + status: 'active_or_nullified', + }); + + // We have compare the sorted arrays since the database does not return the same order as when originally + // inserted combining active and nullified results. + expect(result.sort()).toEqual([...notes].sort()); }); }); diff --git a/yarn-project/pxe/src/simulator_oracle/index.ts b/yarn-project/pxe/src/simulator_oracle/index.ts index 1caa8fb8845..b26a694eb1e 100644 --- a/yarn-project/pxe/src/simulator_oracle/index.ts +++ b/yarn-project/pxe/src/simulator_oracle/index.ts @@ -65,8 +65,12 @@ export class SimulatorOracle implements DBOracle { return capsule; } - async getNotes(contractAddress: AztecAddress, storageSlot: Fr) { - const noteDaos = await this.db.getNotes({ contractAddress, storageSlot }); + async getNotes(contractAddress: AztecAddress, storageSlot: Fr, includeNullified?: boolean) { + const noteDaos = await this.db.getNotes({ + contractAddress, + storageSlot, + status: includeNullified ?? false ? 'active_or_nullified' : 'active', + }); return noteDaos.map(({ contractAddress, storageSlot, nonce, note, innerNoteHash, siloedNullifier, index }) => ({ contractAddress, storageSlot, From d73827dd97caf537dc4cc28a419c9e8d65d83b40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Venturo?= Date: Wed, 24 Jan 2024 23:07:41 +0000 Subject: [PATCH 04/17] Make includeNullified mandatory --- yarn-project/acir-simulator/src/acvm/oracle/typed_oracle.ts | 2 +- yarn-project/acir-simulator/src/client/db_oracle.ts | 4 ++-- yarn-project/pxe/src/simulator_oracle/index.ts | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) 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 d8d1d5b5255..7ff34a7bb14 100644 --- a/yarn-project/acir-simulator/src/acvm/oracle/typed_oracle.ts +++ b/yarn-project/acir-simulator/src/acvm/oracle/typed_oracle.ts @@ -137,7 +137,7 @@ export abstract class TypedOracle { _sortOrder: number[], _limit: number, _offset: number, - _nullified: boolean + _includeNullified: boolean, ): Promise { throw new Error('Not available.'); } diff --git a/yarn-project/acir-simulator/src/client/db_oracle.ts b/yarn-project/acir-simulator/src/client/db_oracle.ts index 622ca48a8a9..e4db8320ea0 100644 --- a/yarn-project/acir-simulator/src/client/db_oracle.ts +++ b/yarn-project/acir-simulator/src/client/db_oracle.ts @@ -61,10 +61,10 @@ export interface DBOracle extends CommitmentsDB { * * @param contractAddress - The AztecAddress instance representing the contract address. * @param storageSlot - The Fr instance representing the storage slot of the notes. - * @param includeNullified - Whether to include nullified notes. Defaults to false. + * @param includeNullified - Whether to include nullified notes. * @returns A Promise that resolves to an array of note data. */ - getNotes(contractAddress: AztecAddress, storageSlot: Fr, includeNullified?: boolean): Promise; + getNotes(contractAddress: AztecAddress, storageSlot: Fr, includeNullified: boolean): Promise; /** * Retrieve the artifact information of a specific function within a contract. diff --git a/yarn-project/pxe/src/simulator_oracle/index.ts b/yarn-project/pxe/src/simulator_oracle/index.ts index b26a694eb1e..489e234123a 100644 --- a/yarn-project/pxe/src/simulator_oracle/index.ts +++ b/yarn-project/pxe/src/simulator_oracle/index.ts @@ -65,11 +65,11 @@ export class SimulatorOracle implements DBOracle { return capsule; } - async getNotes(contractAddress: AztecAddress, storageSlot: Fr, includeNullified?: boolean) { + async getNotes(contractAddress: AztecAddress, storageSlot: Fr, includeNullified: boolean) { const noteDaos = await this.db.getNotes({ contractAddress, storageSlot, - status: includeNullified ?? false ? 'active_or_nullified' : 'active', + status: includeNullified ? 'active_or_nullified' : 'active', }); return noteDaos.map(({ contractAddress, storageSlot, nonce, note, innerNoteHash, siloedNullifier, index }) => ({ contractAddress, From 1a96ef6c26e71857bf3ff9eab00434e3539de5a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Venturo?= Date: Thu, 25 Jan 2024 11:59:28 +0000 Subject: [PATCH 05/17] Slight param rename --- yarn-project/circuit-types/src/notes/note_filter.ts | 4 ++-- yarn-project/pxe/src/database/kv_pxe_database.ts | 6 +++--- yarn-project/pxe/src/database/pxe_database_test_suite.ts | 6 +++--- yarn-project/pxe/src/simulator_oracle/index.ts | 2 +- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/yarn-project/circuit-types/src/notes/note_filter.ts b/yarn-project/circuit-types/src/notes/note_filter.ts index 265e5650795..6f847af2cfe 100644 --- a/yarn-project/circuit-types/src/notes/note_filter.ts +++ b/yarn-project/circuit-types/src/notes/note_filter.ts @@ -15,6 +15,6 @@ export type NoteFilter = { storageSlot?: Fr; /** The owner of the note (whose public key was used to encrypt the note). */ owner?: AztecAddress; - /** The status of the note. Defaults to 'active'. */ - status?: 'active' | 'active_or_nullified'; // TODO: add 'nullified' + /** The status of the note. Defaults to 'active_only'. */ + status?: 'active_only' | 'include_nullified'; // TODO: add 'nullified_only' }; diff --git a/yarn-project/pxe/src/database/kv_pxe_database.ts b/yarn-project/pxe/src/database/kv_pxe_database.ts index dd55301d3d4..5513d98bc98 100644 --- a/yarn-project/pxe/src/database/kv_pxe_database.ts +++ b/yarn-project/pxe/src/database/kv_pxe_database.ts @@ -184,9 +184,9 @@ export class KVPxeDatabase implements PxeDatabase { // merged. let candidateNoteIds: Array = []; - filter.status = filter.status ?? 'active'; + filter.status = filter.status ?? 'active_only'; - if (filter.status == 'active' || filter.status == 'active_or_nullified') { + if (filter.status == 'active_only' || filter.status == 'include_nullified') { const candidateActiveNoteIds = publicKey ? this.#notesByOwner.getValues(publicKey.toString()) : filter.txHash @@ -200,7 +200,7 @@ export class KVPxeDatabase implements PxeDatabase { candidateNoteIds = candidateNoteIds.concat([...candidateActiveNoteIds]); } - if (filter.status == 'active_or_nullified') { + if (filter.status == 'include_nullified') { candidateNoteIds = candidateNoteIds.concat([...this.#nullifiedNotes.keys()]); } diff --git a/yarn-project/pxe/src/database/pxe_database_test_suite.ts b/yarn-project/pxe/src/database/pxe_database_test_suite.ts index 1561b1bf1ca..fe10e8e6770 100644 --- a/yarn-project/pxe/src/database/pxe_database_test_suite.ts +++ b/yarn-project/pxe/src/database/pxe_database_test_suite.ts @@ -142,7 +142,7 @@ export function describePxeDatabase(getDatabase: () => PxeDatabase) { await expect(database.removeNullifiedNotes(nullifiers, owner.publicKey)).resolves.toEqual(notesToNullify); } - await expect(database.getNotes({ ...getFilter(), status: 'active_or_nullified' })).resolves.toEqual( + await expect(database.getNotes({ ...getFilter(), status: 'include_nullified' })).resolves.toEqual( getExpected(), ); }); @@ -157,7 +157,7 @@ export function describePxeDatabase(getDatabase: () => PxeDatabase) { ); const actualNotesWithDefault = await database.getNotes({}); - const actualNotesWithActive = await database.getNotes({ status: 'active' }); + const actualNotesWithActive = await database.getNotes({ status: 'active_only' }); expect(actualNotesWithDefault).toEqual(actualNotesWithActive); expect(actualNotesWithActive).toEqual(notes.filter(note => !notesToNullify.includes(note))); @@ -173,7 +173,7 @@ export function describePxeDatabase(getDatabase: () => PxeDatabase) { ); const result = await database.getNotes({ - status: 'active_or_nullified', + status: 'include_nullified', }); // We have compare the sorted arrays since the database does not return the same order as when originally diff --git a/yarn-project/pxe/src/simulator_oracle/index.ts b/yarn-project/pxe/src/simulator_oracle/index.ts index 489e234123a..38dfc30adde 100644 --- a/yarn-project/pxe/src/simulator_oracle/index.ts +++ b/yarn-project/pxe/src/simulator_oracle/index.ts @@ -69,7 +69,7 @@ export class SimulatorOracle implements DBOracle { const noteDaos = await this.db.getNotes({ contractAddress, storageSlot, - status: includeNullified ? 'active_or_nullified' : 'active', + status: includeNullified ? 'include_nullified' : 'active_only', }); return noteDaos.map(({ contractAddress, storageSlot, nonce, note, innerNoteHash, siloedNullifier, index }) => ({ contractAddress, From f805574695da3da6abed02a2e8319b74d67e4517 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Venturo?= Date: Thu, 25 Jan 2024 12:18:14 +0000 Subject: [PATCH 06/17] Provide methods for the options --- yarn-project/aztec-nr/aztec/src/note/note_getter.nr | 6 +++--- .../aztec-nr/aztec/src/note/note_getter_options.nr | 12 +++++++++--- .../aztec-nr/aztec/src/note/note_viewer_options.nr | 9 +++++++-- yarn-project/aztec-nr/aztec/src/oracle/notes.nr | 10 +++++----- .../contracts/test_contract/src/main.nr | 10 ++++++++-- 5 files changed, 32 insertions(+), 15 deletions(-) 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 2adb390dc7a..b17ab6a7d33 100644 --- a/yarn-project/aztec-nr/aztec/src/note/note_getter.nr +++ b/yarn-project/aztec-nr/aztec/src/note/note_getter.nr @@ -117,7 +117,7 @@ unconstrained fn get_note_internal(storage_slot: Field, note_interface: [], 1, // limit 0, // offset - false, // includeNullified - TODO: add a way for to retrieve nullified notes? + false, // include_nullified - TODO: add a way for get_note to retrieve nullified notes? placeholder_note, placeholder_fields )[0].unwrap() // Notice: we don't allow dummies to be returned from get_note (singular). @@ -141,7 +141,7 @@ unconstrained fn get_notes_internal( sort_order, options.limit, options.offset, - options.includeNullified, + options.include_nullified, placeholder_opt_notes, placeholder_fields ); @@ -169,7 +169,7 @@ unconstrained pub fn view_notes( sort_order, options.limit, options.offset, - options.includeNullified, + options.include_nullified, placeholder_opt_notes, placeholder_fields ) 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 5be1e483771..014154d4202 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 @@ -49,7 +49,7 @@ struct NoteGetterOptions { offset: u32, filter: fn ([Option; MAX_READ_REQUESTS_PER_CALL], FILTER_ARGS) -> [Option; MAX_READ_REQUESTS_PER_CALL], filter_args: FILTER_ARGS, - includeNullified: bool, + include_nullified: bool, } // docs:end:NoteGetterOptions @@ -67,7 +67,7 @@ impl NoteGetterOptions { offset: 0, filter: return_all_notes, filter_args: 0, - includeNullified: false, + include_nullified: false, } } @@ -84,7 +84,7 @@ impl NoteGetterOptions { offset: 0, filter, filter_args, - includeNullified: false, + include_nullified: false, } } @@ -114,4 +114,10 @@ impl NoteGetterOptions { self.offset = offset; *self } + + // This method sets the include_nullified flag, which indicates that nullified notes should also be retrieved. + pub fn include_nullified(&mut self) -> Self { + self.include_nullified = true; + *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 671fa262e22..8cb68f5b217 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 @@ -9,7 +9,7 @@ struct NoteViewerOptions { sorts: BoundedVec, N>, limit: u32, offset: u32, - includeNullified: bool, + include_nullified: bool, } // docs:end:NoteViewerOptions @@ -20,7 +20,7 @@ impl NoteViewerOptions { sorts: BoundedVec::new(Option::none()), limit: MAX_NOTES_PER_PAGE as u32, offset: 0, - includeNullified: false, + include_nullified: false, } } @@ -44,4 +44,9 @@ impl NoteViewerOptions { self.offset = offset; *self } + + pub fn include_nullified(&mut self) -> Self { + self.include_nullified = true; + *self + } } diff --git a/yarn-project/aztec-nr/aztec/src/oracle/notes.nr b/yarn-project/aztec-nr/aztec/src/oracle/notes.nr index 667a317bf3e..781ba081f38 100644 --- a/yarn-project/aztec-nr/aztec/src/oracle/notes.nr +++ b/yarn-project/aztec-nr/aztec/src/oracle/notes.nr @@ -31,7 +31,7 @@ fn get_notes_oracle( _sort_order: [u2; N], _limit: u32, _offset: u32, - _includeNullified: bool, + _include_nullified: bool, _return_size: u32, _placeholder_fields: [Field; S] ) -> [Field; S] {} @@ -45,7 +45,7 @@ unconstrained fn get_notes_oracle_wrapper( sort_order: [u2; N], limit: u32, offset: u32, - includeNullified: bool, + include_nullified: bool, mut placeholder_fields: [Field; S] ) -> [Field; S] { let return_size = placeholder_fields.len() as u32; @@ -58,7 +58,7 @@ unconstrained fn get_notes_oracle_wrapper( sort_order, limit, offset, - includeNullified, + include_nullified, return_size, placeholder_fields ) @@ -74,7 +74,7 @@ unconstrained pub fn get_notes( sort_order: [u2; M], limit: u32, offset: u32, - includeNullified: bool, + include_nullified: bool, mut placeholder_opt_notes: [Option; S], // TODO: Remove it and use `limit` to initialize the note array. placeholder_fields: [Field; NS] // TODO: Remove it and use `limit` to initialize the note array. ) -> [Option; S] { @@ -87,7 +87,7 @@ unconstrained pub fn get_notes( sort_order, limit, offset, - includeNullified, + include_nullified, placeholder_fields ); let num_notes = fields[0] as u32; diff --git a/yarn-project/noir-contracts/contracts/test_contract/src/main.nr b/yarn-project/noir-contracts/contracts/test_contract/src/main.nr index 40dc64fd811..7d42771aead 100644 --- a/yarn-project/noir-contracts/contracts/test_contract/src/main.nr +++ b/yarn-project/noir-contracts/contracts/test_contract/src/main.nr @@ -114,7 +114,10 @@ contract Test { assert(storage_slot != 1, "storage slot 1 is reserved for example_constant"); let mut options = NoteGetterOptions::new(); - options.includeNullified = includeNullified; + if (includeNullified) { + options = options.include_nullified(); + } + let opt_notes = get_notes( &mut context, storage_slot, @@ -136,7 +139,10 @@ contract Test { assert(storage_slot != 1, "storage slot 1 is reserved for example_constant"); let mut options = NoteViewerOptions::new(); - options.includeNullified = includeNullified; + if (includeNullified) { + options = options.include_nullified(); + } + let opt_notes = view_notes( storage_slot, ValueNoteMethods, From 70e81b474d15d08ca6b11b3c67a4010d04e818d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Venturo?= Date: Thu, 25 Jan 2024 09:47:09 -0300 Subject: [PATCH 07/17] Fix typo --- yarn-project/pxe/src/database/pxe_database_test_suite.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yarn-project/pxe/src/database/pxe_database_test_suite.ts b/yarn-project/pxe/src/database/pxe_database_test_suite.ts index fe10e8e6770..7e0891e83cb 100644 --- a/yarn-project/pxe/src/database/pxe_database_test_suite.ts +++ b/yarn-project/pxe/src/database/pxe_database_test_suite.ts @@ -176,7 +176,7 @@ export function describePxeDatabase(getDatabase: () => PxeDatabase) { status: 'include_nullified', }); - // We have compare the sorted arrays since the database does not return the same order as when originally + // We have to compare the sorted arrays since the database does not return the same order as when originally // inserted combining active and nullified results. expect(result.sort()).toEqual([...notes].sort()); }); From fb05a447d8e7adef1a3198346d39b2bb0a4ba936 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Venturo?= Date: Thu, 25 Jan 2024 13:44:50 +0000 Subject: [PATCH 08/17] Switch to camel case --- yarn-project/circuit-types/src/notes/note_filter.ts | 4 ++-- yarn-project/pxe/src/database/kv_pxe_database.ts | 6 +++--- yarn-project/pxe/src/database/pxe_database_test_suite.ts | 8 +++----- yarn-project/pxe/src/simulator_oracle/index.ts | 2 +- 4 files changed, 9 insertions(+), 11 deletions(-) diff --git a/yarn-project/circuit-types/src/notes/note_filter.ts b/yarn-project/circuit-types/src/notes/note_filter.ts index 6f847af2cfe..361734c6e18 100644 --- a/yarn-project/circuit-types/src/notes/note_filter.ts +++ b/yarn-project/circuit-types/src/notes/note_filter.ts @@ -15,6 +15,6 @@ export type NoteFilter = { storageSlot?: Fr; /** The owner of the note (whose public key was used to encrypt the note). */ owner?: AztecAddress; - /** The status of the note. Defaults to 'active_only'. */ - status?: 'active_only' | 'include_nullified'; // TODO: add 'nullified_only' + /** The status of the note. Defaults to 'activeOnly'. */ + status?: 'activeOnly' | 'includeNullified'; // TODO: add 'nullifiedOnly' }; diff --git a/yarn-project/pxe/src/database/kv_pxe_database.ts b/yarn-project/pxe/src/database/kv_pxe_database.ts index 5513d98bc98..cfe947207ac 100644 --- a/yarn-project/pxe/src/database/kv_pxe_database.ts +++ b/yarn-project/pxe/src/database/kv_pxe_database.ts @@ -184,9 +184,9 @@ export class KVPxeDatabase implements PxeDatabase { // merged. let candidateNoteIds: Array = []; - filter.status = filter.status ?? 'active_only'; + filter.status = filter.status ?? 'activeOnly'; - if (filter.status == 'active_only' || filter.status == 'include_nullified') { + if (filter.status == 'activeOnly' || filter.status == 'includeNullified') { const candidateActiveNoteIds = publicKey ? this.#notesByOwner.getValues(publicKey.toString()) : filter.txHash @@ -200,7 +200,7 @@ export class KVPxeDatabase implements PxeDatabase { candidateNoteIds = candidateNoteIds.concat([...candidateActiveNoteIds]); } - if (filter.status == 'include_nullified') { + if (filter.status == 'includeNullified') { candidateNoteIds = candidateNoteIds.concat([...this.#nullifiedNotes.keys()]); } diff --git a/yarn-project/pxe/src/database/pxe_database_test_suite.ts b/yarn-project/pxe/src/database/pxe_database_test_suite.ts index 7e0891e83cb..9e7d6d4245c 100644 --- a/yarn-project/pxe/src/database/pxe_database_test_suite.ts +++ b/yarn-project/pxe/src/database/pxe_database_test_suite.ts @@ -142,9 +142,7 @@ export function describePxeDatabase(getDatabase: () => PxeDatabase) { await expect(database.removeNullifiedNotes(nullifiers, owner.publicKey)).resolves.toEqual(notesToNullify); } - await expect(database.getNotes({ ...getFilter(), status: 'include_nullified' })).resolves.toEqual( - getExpected(), - ); + await expect(database.getNotes({ ...getFilter(), status: 'includeNullified' })).resolves.toEqual(getExpected()); }); it('skips nullified notes by default or when requesting active', async () => { @@ -157,7 +155,7 @@ export function describePxeDatabase(getDatabase: () => PxeDatabase) { ); const actualNotesWithDefault = await database.getNotes({}); - const actualNotesWithActive = await database.getNotes({ status: 'active_only' }); + const actualNotesWithActive = await database.getNotes({ status: 'activeOnly' }); expect(actualNotesWithDefault).toEqual(actualNotesWithActive); expect(actualNotesWithActive).toEqual(notes.filter(note => !notesToNullify.includes(note))); @@ -173,7 +171,7 @@ export function describePxeDatabase(getDatabase: () => PxeDatabase) { ); const result = await database.getNotes({ - status: 'include_nullified', + status: 'includeNullified', }); // We have to compare the sorted arrays since the database does not return the same order as when originally diff --git a/yarn-project/pxe/src/simulator_oracle/index.ts b/yarn-project/pxe/src/simulator_oracle/index.ts index 38dfc30adde..aa05283c41f 100644 --- a/yarn-project/pxe/src/simulator_oracle/index.ts +++ b/yarn-project/pxe/src/simulator_oracle/index.ts @@ -69,7 +69,7 @@ export class SimulatorOracle implements DBOracle { const noteDaos = await this.db.getNotes({ contractAddress, storageSlot, - status: includeNullified ? 'include_nullified' : 'active_only', + status: includeNullified ? 'includeNullified' : 'activeOnly', }); return noteDaos.map(({ contractAddress, storageSlot, nonce, note, innerNoteHash, siloedNullifier, index }) => ({ contractAddress, From 62c0256c4ee978535c7a2de30089e74de7cec6a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Venturo?= Date: Thu, 25 Jan 2024 16:06:21 +0000 Subject: [PATCH 09/17] Link to new issue --- yarn-project/circuit-types/src/notes/note_filter.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yarn-project/circuit-types/src/notes/note_filter.ts b/yarn-project/circuit-types/src/notes/note_filter.ts index 361734c6e18..0364c206098 100644 --- a/yarn-project/circuit-types/src/notes/note_filter.ts +++ b/yarn-project/circuit-types/src/notes/note_filter.ts @@ -16,5 +16,5 @@ export type NoteFilter = { /** The owner of the note (whose public key was used to encrypt the note). */ owner?: AztecAddress; /** The status of the note. Defaults to 'activeOnly'. */ - status?: 'activeOnly' | 'includeNullified'; // TODO: add 'nullifiedOnly' + status?: 'activeOnly' | 'includeNullified'; // TODO 4208: add 'nullifiedOnly' }; From 8b63fe3d4c4f15e55647e6e139a6d6d757715f2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Venturo?= Date: Thu, 25 Jan 2024 16:21:14 +0000 Subject: [PATCH 10/17] Formatting pass --- .../contracts/test_contract/src/main.nr | 52 ++++--------------- 1 file changed, 10 insertions(+), 42 deletions(-) diff --git a/yarn-project/noir-contracts/contracts/test_contract/src/main.nr b/yarn-project/noir-contracts/contracts/test_contract/src/main.nr index 7d42771aead..f739f95878a 100644 --- a/yarn-project/noir-contracts/contracts/test_contract/src/main.nr +++ b/yarn-project/noir-contracts/contracts/test_contract/src/main.nr @@ -89,28 +89,15 @@ contract Test { } #[aztec(private)] - fn call_create_note( - value: Field, - owner: AztecAddress, - storage_slot: Field - ) { + fn call_create_note(value: Field, owner: AztecAddress, storage_slot: Field) { assert(storage_slot != 1, "storage slot 1 is reserved for example_constant"); let mut note = ValueNote::new(value, owner); - create_note( - &mut context, - storage_slot, - &mut note, - ValueNoteMethods, - true, - ); + create_note(&mut context, storage_slot, &mut note, ValueNoteMethods, true); } #[aztec(private)] - fn call_get_notes( - storage_slot: Field, - includeNullified: bool, - ) { + fn call_get_notes(storage_slot: Field, includeNullified: bool) { assert(storage_slot != 1, "storage slot 1 is reserved for example_constant"); let mut options = NoteGetterOptions::new(); @@ -118,12 +105,7 @@ contract Test { options = options.include_nullified(); } - let opt_notes = get_notes( - &mut context, - storage_slot, - ValueNoteMethods, - options, - ); + let opt_notes = get_notes(&mut context, storage_slot, ValueNoteMethods, options); // We can't get the return value of a private function from the outside world in an end to end test, so we // expose it via an unecrypted log instead. @@ -131,10 +113,9 @@ contract Test { emit_unencrypted_log_from_private(&mut context, value); } - unconstrained - fn call_view_notes( + unconstrained fn call_view_notes( storage_slot: Field, - includeNullified: bool, + includeNullified: bool ) -> pub Field { assert(storage_slot != 1, "storage slot 1 is reserved for example_constant"); @@ -143,11 +124,7 @@ contract Test { options = options.include_nullified(); } - let opt_notes = view_notes( - storage_slot, - ValueNoteMethods, - options, - ); + let opt_notes = view_notes(storage_slot, ValueNoteMethods, options); opt_notes[0].unwrap().value } @@ -157,21 +134,12 @@ contract Test { assert(storage_slot != 1, "storage slot 1 is reserved for example_constant"); let options = NoteGetterOptions::new(); - let opt_notes = get_notes( - &mut context, - storage_slot, - ValueNoteMethods, - options, - ); + let opt_notes = get_notes(&mut context, storage_slot, ValueNoteMethods, options); let note = opt_notes[0].unwrap(); - destroy_note( - &mut context, - note, - ValueNoteMethods, - ); - } + destroy_note(&mut context, note, ValueNoteMethods); + } // Test codegen for Aztec.nr interfaces // See yarn-project/acir-simulator/src/client/private_execution.test.ts 'nested calls through autogenerated interface' From c241d388b4b055c65ebd967d69cf0ef6e8cf2871 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Venturo?= Date: Thu, 25 Jan 2024 18:06:02 +0000 Subject: [PATCH 11/17] Remove extraneous comment --- yarn-project/end-to-end/src/e2e_get_notes.test.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/yarn-project/end-to-end/src/e2e_get_notes.test.ts b/yarn-project/end-to-end/src/e2e_get_notes.test.ts index 984532c0fa7..b27fab914d8 100644 --- a/yarn-project/end-to-end/src/e2e_get_notes.test.ts +++ b/yarn-project/end-to-end/src/e2e_get_notes.test.ts @@ -4,7 +4,6 @@ import { TestContract } from '@aztec/noir-contracts'; import { setup } from './fixtures/utils.js'; describe('e2e_get_notes', () => { - // export DEBUG=aztec:e2e_get_notes let wallet: Wallet; let teardown: () => Promise; From 853ac0b127bdaa444e963965d448c05e1765bb5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Venturo?= Date: Thu, 25 Jan 2024 18:06:53 +0000 Subject: [PATCH 12/17] Remove todo comment --- yarn-project/aztec-nr/aztec/src/note/note_getter.nr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 b17ab6a7d33..d9563533842 100644 --- a/yarn-project/aztec-nr/aztec/src/note/note_getter.nr +++ b/yarn-project/aztec-nr/aztec/src/note/note_getter.nr @@ -117,7 +117,7 @@ unconstrained fn get_note_internal(storage_slot: Field, note_interface: [], 1, // limit 0, // offset - false, // include_nullified - TODO: add a way for get_note to retrieve nullified notes? + false, // include_nullified placeholder_note, placeholder_fields )[0].unwrap() // Notice: we don't allow dummies to be returned from get_note (singular). From 6cc5b0efcf5db7584ddcd8526a391540ef67ec79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Venturo?= Date: Thu, 25 Jan 2024 18:55:29 +0000 Subject: [PATCH 13/17] More formatting edits --- .../noir-contracts/contracts/test_contract/src/main.nr | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/yarn-project/noir-contracts/contracts/test_contract/src/main.nr b/yarn-project/noir-contracts/contracts/test_contract/src/main.nr index f739f95878a..d70479d6637 100644 --- a/yarn-project/noir-contracts/contracts/test_contract/src/main.nr +++ b/yarn-project/noir-contracts/contracts/test_contract/src/main.nr @@ -113,10 +113,7 @@ contract Test { emit_unencrypted_log_from_private(&mut context, value); } - unconstrained fn call_view_notes( - storage_slot: Field, - includeNullified: bool - ) -> pub Field { + unconstrained fn call_view_notes(storage_slot: Field, includeNullified: bool) -> pub Field { assert(storage_slot != 1, "storage slot 1 is reserved for example_constant"); let mut options = NoteViewerOptions::new(); From c05ab06ddef00f61fc3c6f08f627b7d037e81115 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Venturo?= Date: Thu, 25 Jan 2024 21:22:06 +0000 Subject: [PATCH 14/17] Switch to enums --- .../acir-simulator/src/acvm/oracle/oracle.ts | 4 ++-- .../src/acvm/oracle/typed_oracle.ts | 3 ++- .../src/client/client_execution_context.ts | 8 +++---- .../acir-simulator/src/client/db_oracle.ts | 6 ++--- .../src/client/view_data_oracle.ts | 7 +++--- .../aztec-nr/aztec/src/note/note_getter.nr | 8 +++---- .../aztec/src/note/note_getter_options.nr | 23 +++++++++++++----- .../aztec/src/note/note_viewer_options.nr | 11 +++++---- .../aztec-nr/aztec/src/oracle/notes.nr | 10 ++++---- .../circuit-types/src/notes/note_filter.ts | 13 ++++++++-- .../end-to-end/src/e2e_get_notes.test.ts | 24 +++++++++---------- .../contracts/test_contract/src/main.nr | 14 +++++------ .../pxe/src/database/kv_pxe_database.ts | 8 +++---- .../src/database/pxe_database_test_suite.ts | 10 ++++---- .../pxe/src/simulator_oracle/index.ts | 5 ++-- 15 files changed, 90 insertions(+), 64 deletions(-) diff --git a/yarn-project/acir-simulator/src/acvm/oracle/oracle.ts b/yarn-project/acir-simulator/src/acvm/oracle/oracle.ts index e4d23cdfc89..8f0e0654cc9 100644 --- a/yarn-project/acir-simulator/src/acvm/oracle/oracle.ts +++ b/yarn-project/acir-simulator/src/acvm/oracle/oracle.ts @@ -167,7 +167,7 @@ export class Oracle { sortOrder: ACVMField[], [limit]: ACVMField[], [offset]: ACVMField[], - [includeNullified]: ACVMField[], + [status]: ACVMField[], [returnSize]: ACVMField[], ): Promise { const noteDatas = await this.typedOracle.getNotes( @@ -179,7 +179,7 @@ export class Oracle { sortOrder.map(s => +s), +limit, +offset, - !!+includeNullified, + +status, ); const noteLength = noteDatas?.[0]?.note.items.length ?? 0; 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 7ff34a7bb14..e3cba6eaf73 100644 --- a/yarn-project/acir-simulator/src/acvm/oracle/typed_oracle.ts +++ b/yarn-project/acir-simulator/src/acvm/oracle/typed_oracle.ts @@ -2,6 +2,7 @@ import { CompleteAddress, MerkleTreeId, Note, + NoteStatus, NullifierMembershipWitness, PublicDataWitness, PublicKey, @@ -137,7 +138,7 @@ export abstract class TypedOracle { _sortOrder: number[], _limit: number, _offset: number, - _includeNullified: boolean, + _status: NoteStatus, ): Promise { throw new Error('Not available.'); } 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 26b356c1449..4a92c1509bf 100644 --- a/yarn-project/acir-simulator/src/client/client_execution_context.ts +++ b/yarn-project/acir-simulator/src/client/client_execution_context.ts @@ -1,4 +1,4 @@ -import { AuthWitness, FunctionL2Logs, L1NotePayload, Note, UnencryptedL2Log } from '@aztec/circuit-types'; +import { AuthWitness, FunctionL2Logs, L1NotePayload, Note, NoteStatus, UnencryptedL2Log } from '@aztec/circuit-types'; import { BlockHeader, CallContext, @@ -189,7 +189,7 @@ export class ClientExecutionContext extends ViewDataOracle { * @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. * @param offset - The starting index for pagination. - * @param includeNullified - Whether to include nullified notes. + * @param status - The status of notes to fetch. * @returns Array of note data. */ public async getNotes( @@ -201,13 +201,13 @@ export class ClientExecutionContext extends ViewDataOracle { sortOrder: number[], limit: number, offset: number, - includeNullified: boolean, + status: NoteStatus, ): Promise { // Nullified pending notes are already removed from the list. const pendingNotes = this.noteCache.getNotes(this.contractAddress, storageSlot); const pendingNullifiers = this.noteCache.getNullifiers(this.contractAddress); - const dbNotes = await this.db.getNotes(this.contractAddress, storageSlot, includeNullified); + const dbNotes = await this.db.getNotes(this.contractAddress, storageSlot, status); const dbNotesFiltered = dbNotes.filter(n => !pendingNullifiers.has((n.siloedNullifier as Fr).value)); const notes = pickNotes([...dbNotesFiltered, ...pendingNotes], { diff --git a/yarn-project/acir-simulator/src/client/db_oracle.ts b/yarn-project/acir-simulator/src/client/db_oracle.ts index e4db8320ea0..4c47f8f4278 100644 --- a/yarn-project/acir-simulator/src/client/db_oracle.ts +++ b/yarn-project/acir-simulator/src/client/db_oracle.ts @@ -1,4 +1,4 @@ -import { L2Block, MerkleTreeId, NullifierMembershipWitness, PublicDataWitness } from '@aztec/circuit-types'; +import { L2Block, MerkleTreeId, NoteStatus, NullifierMembershipWitness, PublicDataWitness } from '@aztec/circuit-types'; import { BlockHeader, CompleteAddress, GrumpkinPrivateKey, PublicKey } from '@aztec/circuits.js'; import { FunctionArtifactWithDebugMetadata, FunctionSelector } from '@aztec/foundation/abi'; import { AztecAddress } from '@aztec/foundation/aztec-address'; @@ -61,10 +61,10 @@ export interface DBOracle extends CommitmentsDB { * * @param contractAddress - The AztecAddress instance representing the contract address. * @param storageSlot - The Fr instance representing the storage slot of the notes. - * @param includeNullified - Whether to include nullified notes. + * @param status - The status of notes to fetch. * @returns A Promise that resolves to an array of note data. */ - getNotes(contractAddress: AztecAddress, storageSlot: Fr, includeNullified: boolean): Promise; + getNotes(contractAddress: AztecAddress, storageSlot: Fr, status: NoteStatus): Promise; /** * Retrieve the artifact information of a specific function within a contract. 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 9c690864424..f678d3bfb53 100644 --- a/yarn-project/acir-simulator/src/client/view_data_oracle.ts +++ b/yarn-project/acir-simulator/src/client/view_data_oracle.ts @@ -4,6 +4,7 @@ import { CompleteAddress, INITIAL_L2_BLOCK_NUM, MerkleTreeId, + NoteStatus, NullifierMembershipWitness, PublicDataWitness, } from '@aztec/circuit-types'; @@ -202,7 +203,7 @@ export class ViewDataOracle extends TypedOracle { * @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. * @param offset - The starting index for pagination. - * @param includeNullified - Whether to include nullified notes. + * @param status - The status of notes to fetch. * @returns Array of note data. */ public async getNotes( @@ -214,9 +215,9 @@ export class ViewDataOracle extends TypedOracle { sortOrder: number[], limit: number, offset: number, - includeNullified: boolean, + status: NoteStatus, ): Promise { - const dbNotes = await this.db.getNotes(this.contractAddress, storageSlot, includeNullified); + const dbNotes = await this.db.getNotes(this.contractAddress, storageSlot, status); return pickNotes(dbNotes, { selects: selectBy.slice(0, numSelects).map((index, i) => ({ index, value: selectValues[i] })), sorts: sortBy.map((index, i) => ({ index, order: sortOrder[i] })), 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 d9563533842..9c015334f8e 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, NoteStatus}, note_interface::NoteInterface, note_viewer_options::NoteViewerOptions, utils::compute_note_hash_for_read_or_nullify, @@ -117,7 +117,7 @@ unconstrained fn get_note_internal(storage_slot: Field, note_interface: [], 1, // limit 0, // offset - false, // include_nullified + NoteStatus.ACTIVE, placeholder_note, placeholder_fields )[0].unwrap() // Notice: we don't allow dummies to be returned from get_note (singular). @@ -141,7 +141,7 @@ unconstrained fn get_notes_internal( sort_order, options.limit, options.offset, - options.include_nullified, + options.status, placeholder_opt_notes, placeholder_fields ); @@ -169,7 +169,7 @@ unconstrained pub fn view_notes( sort_order, options.limit, options.offset, - options.include_nullified, + options.status, placeholder_opt_notes, placeholder_fields ) 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 014154d4202..0525448bea6 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 @@ -34,6 +34,17 @@ impl Sort { } } +struct NoteStatusEnum { + ACTIVE: u2, + ACTIVE_OR_NULLIFIED: u2, +} + +global NoteStatus = NoteStatusEnum { + ACTIVE: 1, + ACTIVE_OR_NULLIFIED: 2, + // TODO 4208: add 'NULLIFIED' +}; + fn return_all_notes( notes: [Option; MAX_READ_REQUESTS_PER_CALL], _p: Field @@ -49,7 +60,7 @@ struct NoteGetterOptions { offset: u32, filter: fn ([Option; MAX_READ_REQUESTS_PER_CALL], FILTER_ARGS) -> [Option; MAX_READ_REQUESTS_PER_CALL], filter_args: FILTER_ARGS, - include_nullified: bool, + status: u2, } // docs:end:NoteGetterOptions @@ -67,7 +78,7 @@ impl NoteGetterOptions { offset: 0, filter: return_all_notes, filter_args: 0, - include_nullified: false, + status: NoteStatus.ACTIVE, } } @@ -84,7 +95,7 @@ impl NoteGetterOptions { offset: 0, filter, filter_args, - include_nullified: false, + status: NoteStatus.ACTIVE, } } @@ -115,9 +126,9 @@ impl NoteGetterOptions { *self } - // This method sets the include_nullified flag, which indicates that nullified notes should also be retrieved. - pub fn include_nullified(&mut self) -> Self { - self.include_nullified = true; + // This method sets the status value, which determines whether to retrieve active or nullified notes. + pub fn set_status(&mut self, status: u2) -> Self { + self.status = status; *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 8cb68f5b217..c93886af4b4 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, NoteStatus}; use crate::types::vec::BoundedVec; // docs:start:NoteViewerOptions @@ -9,7 +9,7 @@ struct NoteViewerOptions { sorts: BoundedVec, N>, limit: u32, offset: u32, - include_nullified: bool, + status: u2, } // docs:end:NoteViewerOptions @@ -20,7 +20,7 @@ impl NoteViewerOptions { sorts: BoundedVec::new(Option::none()), limit: MAX_NOTES_PER_PAGE as u32, offset: 0, - include_nullified: false, + status: NoteStatus.ACTIVE, } } @@ -45,8 +45,9 @@ impl NoteViewerOptions { *self } - pub fn include_nullified(&mut self) -> Self { - self.include_nullified = true; + // This method sets the status value, which determines whether to retrieve active or nullified notes. + pub fn set_status(&mut self, status: u2) -> Self { + self.status = status; *self } } diff --git a/yarn-project/aztec-nr/aztec/src/oracle/notes.nr b/yarn-project/aztec-nr/aztec/src/oracle/notes.nr index 781ba081f38..a536326cb2b 100644 --- a/yarn-project/aztec-nr/aztec/src/oracle/notes.nr +++ b/yarn-project/aztec-nr/aztec/src/oracle/notes.nr @@ -31,7 +31,7 @@ fn get_notes_oracle( _sort_order: [u2; N], _limit: u32, _offset: u32, - _include_nullified: bool, + _status: u2, _return_size: u32, _placeholder_fields: [Field; S] ) -> [Field; S] {} @@ -45,7 +45,7 @@ unconstrained fn get_notes_oracle_wrapper( sort_order: [u2; N], limit: u32, offset: u32, - include_nullified: bool, + status: u2, mut placeholder_fields: [Field; S] ) -> [Field; S] { let return_size = placeholder_fields.len() as u32; @@ -58,7 +58,7 @@ unconstrained fn get_notes_oracle_wrapper( sort_order, limit, offset, - include_nullified, + status, return_size, placeholder_fields ) @@ -74,7 +74,7 @@ unconstrained pub fn get_notes( sort_order: [u2; M], limit: u32, offset: u32, - include_nullified: bool, + status: u2, mut placeholder_opt_notes: [Option; S], // TODO: Remove it and use `limit` to initialize the note array. placeholder_fields: [Field; NS] // TODO: Remove it and use `limit` to initialize the note array. ) -> [Option; S] { @@ -87,7 +87,7 @@ unconstrained pub fn get_notes( sort_order, limit, offset, - include_nullified, + status, placeholder_fields ); let num_notes = fields[0] as u32; diff --git a/yarn-project/circuit-types/src/notes/note_filter.ts b/yarn-project/circuit-types/src/notes/note_filter.ts index 0364c206098..c69b694b487 100644 --- a/yarn-project/circuit-types/src/notes/note_filter.ts +++ b/yarn-project/circuit-types/src/notes/note_filter.ts @@ -2,6 +2,15 @@ import { AztecAddress, Fr } from '@aztec/circuits.js'; import { TxHash } from '../index.js'; +/** + * The status of notes to retrieve. + */ +export enum NoteStatus { + ACTIVE = 1, + ACTIVE_OR_NULLIFIED = 2, + // TODO 4208: add 'NULLIFIED' +} + /** * A filter used to fetch Notes. * @remarks This filter is applied as an intersection of all it's params. @@ -15,6 +24,6 @@ export type NoteFilter = { storageSlot?: Fr; /** The owner of the note (whose public key was used to encrypt the note). */ owner?: AztecAddress; - /** The status of the note. Defaults to 'activeOnly'. */ - status?: 'activeOnly' | 'includeNullified'; // TODO 4208: add 'nullifiedOnly' + /** The status of the note. Defaults to 'ACTIVE'. */ + status?: NoteStatus; }; diff --git a/yarn-project/end-to-end/src/e2e_get_notes.test.ts b/yarn-project/end-to-end/src/e2e_get_notes.test.ts index b27fab914d8..5e8115470a8 100644 --- a/yarn-project/end-to-end/src/e2e_get_notes.test.ts +++ b/yarn-project/end-to-end/src/e2e_get_notes.test.ts @@ -28,11 +28,11 @@ describe('e2e_get_notes', () => { storageSlot += 1; }); - async function assertNoteIsReturned(storageSlot: number, expectedValue: number, includeNullified: boolean) { - const viewNotesResult = await contract.methods.call_view_notes(storageSlot, includeNullified).view(); + async function assertNoteIsReturned(storageSlot: number, expectedValue: number, activeOrNullified: boolean) { + const viewNotesResult = await contract.methods.call_view_notes(storageSlot, activeOrNullified).view(); // call_get_notes exposes the return value via an event since we cannot use view() with it. - const tx = contract.methods.call_get_notes(storageSlot, includeNullified).send(); + const tx = contract.methods.call_get_notes(storageSlot, activeOrNullified).send(); await tx.wait(); const logs = (await tx.getUnencryptedLogs()).logs; @@ -44,42 +44,42 @@ describe('e2e_get_notes', () => { expect(viewNotesResult).toEqual(BigInt(expectedValue)); } - async function assertNoReturnValue(storageSlot: number, includeNullified: boolean) { - await expect(contract.methods.call_view_notes(storageSlot, includeNullified).view()).rejects.toThrow('is_some'); - await expect(contract.methods.call_get_notes(storageSlot, includeNullified).send().wait()).rejects.toThrow( + async function assertNoReturnValue(storageSlot: number, activeOrNullified: boolean) { + await expect(contract.methods.call_view_notes(storageSlot, activeOrNullified).view()).rejects.toThrow('is_some'); + await expect(contract.methods.call_get_notes(storageSlot, activeOrNullified).send().wait()).rejects.toThrow( 'is_some', ); } describe('active note only', () => { - const includeNullified = false; + const activeOrNullified = false; it('returns active notes', async () => { await contract.methods.call_create_note(VALUE, owner, storageSlot).send().wait(); - await assertNoteIsReturned(storageSlot, VALUE, includeNullified); + await assertNoteIsReturned(storageSlot, VALUE, activeOrNullified); }); it('does not return nullified notes', async () => { await contract.methods.call_create_note(VALUE, owner, storageSlot).send().wait(); await contract.methods.call_destroy_note(storageSlot).send().wait(); - await assertNoReturnValue(storageSlot, includeNullified); + await assertNoReturnValue(storageSlot, activeOrNullified); }); }); describe('active and nullified notes', () => { - const includeNullified = true; + const activeOrNullified = true; it('returns active notes', async () => { await contract.methods.call_create_note(VALUE, owner, storageSlot).send().wait(); - await assertNoteIsReturned(storageSlot, VALUE, includeNullified); + await assertNoteIsReturned(storageSlot, VALUE, activeOrNullified); }); it('returns nullified notes', async () => { await contract.methods.call_create_note(VALUE, owner, storageSlot).send().wait(); await contract.methods.call_destroy_note(storageSlot).send().wait(); - await assertNoteIsReturned(storageSlot, VALUE, includeNullified); + await assertNoteIsReturned(storageSlot, VALUE, activeOrNullified); }, 30_000); }); }); diff --git a/yarn-project/noir-contracts/contracts/test_contract/src/main.nr b/yarn-project/noir-contracts/contracts/test_contract/src/main.nr index d70479d6637..d9a6fb09310 100644 --- a/yarn-project/noir-contracts/contracts/test_contract/src/main.nr +++ b/yarn-project/noir-contracts/contracts/test_contract/src/main.nr @@ -25,7 +25,7 @@ contract Test { utils as note_utils, lifecycle::{create_note, destroy_note}, note_getter::{get_notes, view_notes}, - note_getter_options::NoteGetterOptions, + note_getter_options::{NoteGetterOptions, NoteStatus}, note_viewer_options::NoteViewerOptions, }, oracle::{ @@ -97,12 +97,12 @@ contract Test { } #[aztec(private)] - fn call_get_notes(storage_slot: Field, includeNullified: bool) { + fn call_get_notes(storage_slot: Field, active_or_nullified: bool) { assert(storage_slot != 1, "storage slot 1 is reserved for example_constant"); let mut options = NoteGetterOptions::new(); - if (includeNullified) { - options = options.include_nullified(); + if (active_or_nullified) { + options = options.set_status(NoteStatus.ACTIVE_OR_NULLIFIED); } let opt_notes = get_notes(&mut context, storage_slot, ValueNoteMethods, options); @@ -113,12 +113,12 @@ contract Test { emit_unencrypted_log_from_private(&mut context, value); } - unconstrained fn call_view_notes(storage_slot: Field, includeNullified: bool) -> pub Field { + unconstrained fn call_view_notes(storage_slot: Field, active_or_nullified: bool) -> pub Field { assert(storage_slot != 1, "storage slot 1 is reserved for example_constant"); let mut options = NoteViewerOptions::new(); - if (includeNullified) { - options = options.include_nullified(); + if (active_or_nullified) { + options = options.set_status(NoteStatus.ACTIVE_OR_NULLIFIED); } let opt_notes = view_notes(storage_slot, ValueNoteMethods, options); diff --git a/yarn-project/pxe/src/database/kv_pxe_database.ts b/yarn-project/pxe/src/database/kv_pxe_database.ts index cfe947207ac..d176149c482 100644 --- a/yarn-project/pxe/src/database/kv_pxe_database.ts +++ b/yarn-project/pxe/src/database/kv_pxe_database.ts @@ -1,4 +1,4 @@ -import { ContractDao, MerkleTreeId, NoteFilter, PublicKey } from '@aztec/circuit-types'; +import { ContractDao, MerkleTreeId, NoteFilter, NoteStatus, PublicKey } from '@aztec/circuit-types'; import { AztecAddress, BlockHeader, CompleteAddress } from '@aztec/circuits.js'; import { Fr, Point } from '@aztec/foundation/fields'; import { AztecArray, AztecKVStore, AztecMap, AztecMultiMap, AztecSingleton } from '@aztec/kv-store'; @@ -184,9 +184,9 @@ export class KVPxeDatabase implements PxeDatabase { // merged. let candidateNoteIds: Array = []; - filter.status = filter.status ?? 'activeOnly'; + filter.status = filter.status ?? NoteStatus.ACTIVE; - if (filter.status == 'activeOnly' || filter.status == 'includeNullified') { + if (filter.status == NoteStatus.ACTIVE || filter.status == NoteStatus.ACTIVE_OR_NULLIFIED) { const candidateActiveNoteIds = publicKey ? this.#notesByOwner.getValues(publicKey.toString()) : filter.txHash @@ -200,7 +200,7 @@ export class KVPxeDatabase implements PxeDatabase { candidateNoteIds = candidateNoteIds.concat([...candidateActiveNoteIds]); } - if (filter.status == 'includeNullified') { + if (filter.status == NoteStatus.ACTIVE_OR_NULLIFIED) { candidateNoteIds = candidateNoteIds.concat([...this.#nullifiedNotes.keys()]); } diff --git a/yarn-project/pxe/src/database/pxe_database_test_suite.ts b/yarn-project/pxe/src/database/pxe_database_test_suite.ts index 9e7d6d4245c..59bcc03cf7c 100644 --- a/yarn-project/pxe/src/database/pxe_database_test_suite.ts +++ b/yarn-project/pxe/src/database/pxe_database_test_suite.ts @@ -1,4 +1,4 @@ -import { INITIAL_L2_BLOCK_NUM, MerkleTreeId, NoteFilter, randomTxHash } from '@aztec/circuit-types'; +import { INITIAL_L2_BLOCK_NUM, MerkleTreeId, NoteFilter, NoteStatus, randomTxHash } from '@aztec/circuit-types'; import { AztecAddress, BlockHeader, CompleteAddress } from '@aztec/circuits.js'; import { Fr, Point } from '@aztec/foundation/fields'; @@ -142,7 +142,9 @@ export function describePxeDatabase(getDatabase: () => PxeDatabase) { await expect(database.removeNullifiedNotes(nullifiers, owner.publicKey)).resolves.toEqual(notesToNullify); } - await expect(database.getNotes({ ...getFilter(), status: 'includeNullified' })).resolves.toEqual(getExpected()); + await expect(database.getNotes({ ...getFilter(), status: NoteStatus.ACTIVE_OR_NULLIFIED })).resolves.toEqual( + getExpected(), + ); }); it('skips nullified notes by default or when requesting active', async () => { @@ -155,7 +157,7 @@ export function describePxeDatabase(getDatabase: () => PxeDatabase) { ); const actualNotesWithDefault = await database.getNotes({}); - const actualNotesWithActive = await database.getNotes({ status: 'activeOnly' }); + const actualNotesWithActive = await database.getNotes({ status: NoteStatus.ACTIVE }); expect(actualNotesWithDefault).toEqual(actualNotesWithActive); expect(actualNotesWithActive).toEqual(notes.filter(note => !notesToNullify.includes(note))); @@ -171,7 +173,7 @@ export function describePxeDatabase(getDatabase: () => PxeDatabase) { ); const result = await database.getNotes({ - status: 'includeNullified', + status: NoteStatus.ACTIVE_OR_NULLIFIED, }); // We have to compare the sorted arrays since the database does not return the same order as when originally diff --git a/yarn-project/pxe/src/simulator_oracle/index.ts b/yarn-project/pxe/src/simulator_oracle/index.ts index aa05283c41f..82e4b190e9a 100644 --- a/yarn-project/pxe/src/simulator_oracle/index.ts +++ b/yarn-project/pxe/src/simulator_oracle/index.ts @@ -3,6 +3,7 @@ import { KeyStore, L2Block, MerkleTreeId, + NoteStatus, NullifierMembershipWitness, PublicDataWitness, StateInfoProvider, @@ -65,11 +66,11 @@ export class SimulatorOracle implements DBOracle { return capsule; } - async getNotes(contractAddress: AztecAddress, storageSlot: Fr, includeNullified: boolean) { + async getNotes(contractAddress: AztecAddress, storageSlot: Fr, status: NoteStatus) { const noteDaos = await this.db.getNotes({ contractAddress, storageSlot, - status: includeNullified ? 'includeNullified' : 'activeOnly', + status, }); return noteDaos.map(({ contractAddress, storageSlot, nonce, note, innerNoteHash, siloedNullifier, index }) => ({ contractAddress, From e2e8d33326fff7e4dbfea86c7a5b7eb9d25f8ed5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Venturo?= Date: Fri, 26 Jan 2024 13:28:35 +0000 Subject: [PATCH 15/17] Add test for mixed retrievals --- .../end-to-end/src/e2e_get_notes.test.ts | 52 +++++++++++++++---- .../contracts/test_contract/src/main.nr | 31 +++++++++++ 2 files changed, 74 insertions(+), 9 deletions(-) diff --git a/yarn-project/end-to-end/src/e2e_get_notes.test.ts b/yarn-project/end-to-end/src/e2e_get_notes.test.ts index 5e8115470a8..0ee70d4d644 100644 --- a/yarn-project/end-to-end/src/e2e_get_notes.test.ts +++ b/yarn-project/end-to-end/src/e2e_get_notes.test.ts @@ -30,15 +30,7 @@ describe('e2e_get_notes', () => { async function assertNoteIsReturned(storageSlot: number, expectedValue: number, activeOrNullified: boolean) { const viewNotesResult = await contract.methods.call_view_notes(storageSlot, activeOrNullified).view(); - - // call_get_notes exposes the return value via an event since we cannot use view() with it. - const tx = contract.methods.call_get_notes(storageSlot, activeOrNullified).send(); - await tx.wait(); - - const logs = (await tx.getUnencryptedLogs()).logs; - expect(logs.length).toBe(1); - - const getNotesResult = toBigInt(logs[0].log.data); + const getNotesResult = await callGetNotes(storageSlot, activeOrNullified); expect(viewNotesResult).toEqual(getNotesResult); expect(viewNotesResult).toEqual(BigInt(expectedValue)); @@ -51,6 +43,28 @@ describe('e2e_get_notes', () => { ); } + async function callGetNotes(storageSlot: number, activeOrNullified: boolean): Promise { + // call_get_notes exposes the return value via an event since we cannot use view() with it. + const tx = contract.methods.call_get_notes(storageSlot, activeOrNullified).send(); + await tx.wait(); + + const logs = (await tx.getUnencryptedLogs()).logs; + expect(logs.length).toBe(1); + + return toBigInt(logs[0].log.data); + } + + async function callGetNotesMany(storageSlot: number, activeOrNullified: boolean): Promise> { + // call_get_notes_many exposes the return values via event since we cannot use view() with it. + const tx = contract.methods.call_get_notes_many(storageSlot, activeOrNullified).send(); + await tx.wait(); + + const logs = (await tx.getUnencryptedLogs()).logs; + expect(logs.length).toBe(2); + + return [toBigInt(logs[0].log.data), toBigInt(logs[1].log.data)]; + } + describe('active note only', () => { const activeOrNullified = false; @@ -81,5 +95,25 @@ describe('e2e_get_notes', () => { await assertNoteIsReturned(storageSlot, VALUE, activeOrNullified); }, 30_000); + + it('returns both active and nullified notes', async () => { + // We store two notes with two different values in the same storage slot, and then delete one of them. Note that + // we can't be sure which one was deleted since we're just deleting based on the storage slot. + await contract.methods.call_create_note(VALUE, owner, storageSlot).send().wait(); + await contract.methods + .call_create_note(VALUE + 1, owner, storageSlot) + .send() + .wait(); + await contract.methods.call_destroy_note(storageSlot).send().wait(); + + // We now fetch multiple notes, and get both the active and the nullified one. + const viewNotesManyResult = await contract.methods.call_view_notes_many(storageSlot, activeOrNullified).view(); + const getNotesManyResult = await callGetNotesMany(storageSlot, activeOrNullified); + + // We can't be sure in which order the notes will be returned, so we simply sort them to test equality. Note + // however that both view_notes and get_notes get the exact same result. + expect(viewNotesManyResult).toEqual(getNotesManyResult); + expect(viewNotesManyResult.sort()).toEqual([BigInt(VALUE), BigInt(VALUE + 1)]); + }, 30_000); }); }); diff --git a/yarn-project/noir-contracts/contracts/test_contract/src/main.nr b/yarn-project/noir-contracts/contracts/test_contract/src/main.nr index d9a6fb09310..52ac5641293 100644 --- a/yarn-project/noir-contracts/contracts/test_contract/src/main.nr +++ b/yarn-project/noir-contracts/contracts/test_contract/src/main.nr @@ -113,6 +113,24 @@ contract Test { emit_unencrypted_log_from_private(&mut context, value); } + + #[aztec(private)] + fn call_get_notes_many(storage_slot: Field, active_or_nullified: bool) { + assert(storage_slot != 1, "storage slot 1 is reserved for example_constant"); + + let mut options = NoteGetterOptions::new(); + if (active_or_nullified) { + options = options.set_status(NoteStatus.ACTIVE_OR_NULLIFIED); + } + + let opt_notes = get_notes(&mut context, storage_slot, ValueNoteMethods, options); + + // We can't get the return value of a private function from the outside world in an end to end test, so we + // expose it via an unecrypted log instead. + emit_unencrypted_log_from_private(&mut context, opt_notes[0].unwrap().value); + emit_unencrypted_log_from_private(&mut context, opt_notes[1].unwrap().value); + } + unconstrained fn call_view_notes(storage_slot: Field, active_or_nullified: bool) -> pub Field { assert(storage_slot != 1, "storage slot 1 is reserved for example_constant"); @@ -126,6 +144,19 @@ contract Test { opt_notes[0].unwrap().value } + unconstrained fn call_view_notes_many(storage_slot: Field, active_or_nullified: bool) -> pub [Field; 2] { + assert(storage_slot != 1, "storage slot 1 is reserved for example_constant"); + + let mut options = NoteViewerOptions::new(); + if (active_or_nullified) { + options = options.set_status(NoteStatus.ACTIVE_OR_NULLIFIED); + } + + let opt_notes = view_notes(storage_slot, ValueNoteMethods, options); + + [opt_notes[0].unwrap().value, opt_notes[1].unwrap().value] + } + #[aztec(private)] fn call_destroy_note(storage_slot: Field) { assert(storage_slot != 1, "storage slot 1 is reserved for example_constant"); From f3378ca3070334d0a3f74d42395652f05c8bc588 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Venturo?= Date: Fri, 26 Jan 2024 14:03:02 +0000 Subject: [PATCH 16/17] Increase timeouts --- yarn-project/end-to-end/src/e2e_get_notes.test.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/yarn-project/end-to-end/src/e2e_get_notes.test.ts b/yarn-project/end-to-end/src/e2e_get_notes.test.ts index 0ee70d4d644..9ec0e6fca60 100644 --- a/yarn-project/end-to-end/src/e2e_get_notes.test.ts +++ b/yarn-project/end-to-end/src/e2e_get_notes.test.ts @@ -71,14 +71,14 @@ describe('e2e_get_notes', () => { it('returns active notes', async () => { await contract.methods.call_create_note(VALUE, owner, storageSlot).send().wait(); await assertNoteIsReturned(storageSlot, VALUE, activeOrNullified); - }); + }, 30_000); it('does not return nullified notes', async () => { await contract.methods.call_create_note(VALUE, owner, storageSlot).send().wait(); await contract.methods.call_destroy_note(storageSlot).send().wait(); await assertNoReturnValue(storageSlot, activeOrNullified); - }); + }, 30_000); }); describe('active and nullified notes', () => { @@ -87,7 +87,7 @@ describe('e2e_get_notes', () => { it('returns active notes', async () => { await contract.methods.call_create_note(VALUE, owner, storageSlot).send().wait(); await assertNoteIsReturned(storageSlot, VALUE, activeOrNullified); - }); + }, 30_000); it('returns nullified notes', async () => { await contract.methods.call_create_note(VALUE, owner, storageSlot).send().wait(); @@ -114,6 +114,6 @@ describe('e2e_get_notes', () => { // however that both view_notes and get_notes get the exact same result. expect(viewNotesManyResult).toEqual(getNotesManyResult); expect(viewNotesManyResult.sort()).toEqual([BigInt(VALUE), BigInt(VALUE + 1)]); - }, 30_000); + }, 45_000); }); }); From 67f6889bd5ed81177580b34da936c689adaf626e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Venturo?= Date: Fri, 26 Jan 2024 14:10:48 +0000 Subject: [PATCH 17/17] Remove superflous todo --- yarn-project/pxe/src/database/kv_pxe_database.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/yarn-project/pxe/src/database/kv_pxe_database.ts b/yarn-project/pxe/src/database/kv_pxe_database.ts index bb654390393..c5216b591de 100644 --- a/yarn-project/pxe/src/database/kv_pxe_database.ts +++ b/yarn-project/pxe/src/database/kv_pxe_database.ts @@ -210,8 +210,6 @@ export class KVPxeDatabase implements PxeDatabase { ? (await this.getCompleteAddress(filter.owner))?.publicKey : undefined; - // TODO: refactor how we create the array of candidate note ids once the kv_pxe_database refactor from #3927 is - // merged. let candidateNoteIds: Array = []; filter.status = filter.status ?? NoteStatus.ACTIVE;